Hi all,
As per discussion with Martin Ling on this mailing list, please find below a proposed
patch that simplifies the async_read, keeps track of open tranfers and checks for zero
open transfers before closing to avoid unidentified behaviour at close.
Thanks, Jasper
commit 4b06ae321e91296f13355a0715e9a961b4f57e45
Author: jvde.github <jvde.github(a)gmail.com>
Date: Mon Jan 24 20:15:34 2022 +0100
count live transfers before close
diff --git a/src/librtlsdr.c b/src/librtlsdr.c
index 096abae..67e30c4 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -119,6 +119,7 @@ struct rtlsdr_dev {
int dev_lost;
int driver_active;
unsigned int xfer_errors;
+ int live_transfers;
};
void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val);
@@ -1695,11 +1696,15 @@ static void LIBUSB_CALL _libusb_callback(struct libusb_transfer
*xfer)
{
rtlsdr_dev_t *dev = (rtlsdr_dev_t *)xfer->user_data;
+ dev->live_transfers --;
+
if (LIBUSB_TRANSFER_COMPLETED == xfer->status) {
if (dev->cb)
dev->cb(xfer->buffer, xfer->actual_length, dev->cb_ctx);
- libusb_submit_transfer(xfer); /* resubmit transfer */
+ if(!dev->async_cancel)
+ if( libusb_submit_transfer(xfer) == 0) /* resubmit transfer */
+ dev->live_transfers++;
dev->xfer_errors = 0;
} else if (LIBUSB_TRANSFER_CANCELLED != xfer->status) {
#ifndef _WIN32
@@ -1847,9 +1852,9 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb,
void *ctx,
{
unsigned int i;
int r = 0;
+ int ret = 0;
struct timeval tv = { 1, 0 };
- struct timeval zerotv = { 0, 0 };
- enum rtlsdr_async_status next_status = RTLSDR_INACTIVE;
+ struct timeval canceltv = { 0, 50 };
if (!dev)
return -1;
@@ -1863,6 +1868,7 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb,
void *ctx,
dev->cb = cb;
dev->cb_ctx = ctx;
+
if (buf_num > 0)
dev->xfer_buf_num = buf_num;
else
@@ -1875,6 +1881,8 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb,
void *ctx,
_rtlsdr_alloc_async_buffers(dev);
+ dev->live_transfers = 0;
+
for(i = 0; i < dev->xfer_buf_num; ++i) {
libusb_fill_bulk_transfer(dev->xfer[i],
dev->devh,
@@ -1894,64 +1902,41 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t
cb, void *ctx,
"echo 0 > /sys/module/usbcore"
"/parameters/usbfs_memory_mb\n", i);
dev->async_status = RTLSDR_CANCELING;
+ ret = -3;
break;
}
+ else
+ dev->live_transfers++;
}
- while (RTLSDR_INACTIVE != dev->async_status) {
+ while (RTLSDR_RUNNING == dev->async_status) {
r = libusb_handle_events_timeout_completed(dev->ctx, &tv,
- &dev->async_cancel);
+ &dev->async_cancel);
if (r < 0) {
/*fprintf(stderr, "handle_events returned: %d\n", r);*/
if (r == LIBUSB_ERROR_INTERRUPTED) /* stray signal */
continue;
- break;
+ rtlsdr_cancel_async(dev);
+ ret = -4;
}
+ }
- if (RTLSDR_CANCELING == dev->async_status) {
- next_status = RTLSDR_INACTIVE;
+ if (!dev->xfer) return -5;
- if (!dev->xfer)
- break;
+ for(i = 0; i < dev->xfer_buf_num; ++i)
+ if (dev->xfer[i])
+ libusb_cancel_transfer(dev->xfer[i]);
- for(i = 0; i < dev->xfer_buf_num; ++i) {
- if (!dev->xfer[i])
- continue;
+ for (i = 0; i < dev->xfer_buf_num && dev->live_transfers > 0; ++i)
+ libusb_handle_events_timeout_completed(dev->ctx, &canceltv, NULL);
- if (LIBUSB_TRANSFER_CANCELLED !=
- dev->xfer[i]->status) {
- r = libusb_cancel_transfer(dev->xfer[i]);
- /* handle events after canceling
- * to allow transfer status to
- * propagate */
-#ifdef _WIN32
- Sleep(1);
-#endif
- libusb_handle_events_timeout_completed(dev->ctx,
- &zerotv, NULL);
- if (r < 0)
- continue;
-
- next_status = RTLSDR_CANCELING;
- }
- }
-
- if (dev->dev_lost || RTLSDR_INACTIVE == next_status) {
- /* handle any events that still need to
- * be handled before exiting after we
- * just cancelled all transfers */
- libusb_handle_events_timeout_completed(dev->ctx,
- &zerotv, NULL);
- break;
- }
- }
- }
+ if(dev->live_transfers > 0) return -6;
_rtlsdr_free_async_buffers(dev);
- dev->async_status = next_status;
+ dev->async_status = RTLSDR_INACTIVE;
- return r;
+ return ret;
}
int rtlsdr_cancel_async(rtlsdr_dev_t *dev)