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.git...@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)