From f9cd43a9406a515b40595274ae569d9dec9217bb Mon Sep 17 00:00:00 2001 From: Lars Glud Date: Fri, 24 Apr 2015 13:19:21 +0200 Subject: [PATCH] Handling race condition for list/queues and iterators. Locking pending_transfers_ when canceling transfers. --- .../include/libfreenect2/usb/transfer_pool.h | 3 +++ examples/protonect/src/transfer_pool.cpp | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/examples/protonect/include/libfreenect2/usb/transfer_pool.h b/examples/protonect/include/libfreenect2/usb/transfer_pool.h index 3a0dbef56..c5b8f7cc8 100644 --- a/examples/protonect/include/libfreenect2/usb/transfer_pool.h +++ b/examples/protonect/include/libfreenect2/usb/transfer_pool.h @@ -29,6 +29,7 @@ #include #include +#include #include @@ -70,6 +71,8 @@ class TransferPool libusb_device_handle *device_handle_; unsigned char device_endpoint_; + mutex pending_transfers_lock_; + mutex idle_transfers_lock_; TransferQueue idle_transfers_, pending_transfers_; unsigned char *buffer_; size_t buffer_size_; diff --git a/examples/protonect/src/transfer_pool.cpp b/examples/protonect/src/transfer_pool.cpp index 60c4358b1..b5ba669ed 100644 --- a/examples/protonect/src/transfer_pool.cpp +++ b/examples/protonect/src/transfer_pool.cpp @@ -60,10 +60,13 @@ void TransferPool::disableSubmission() void TransferPool::deallocate() { + idle_transfers_lock_.lock(); for(TransferQueue::iterator it = idle_transfers_.begin(); it != idle_transfers_.end(); ++it) { libusb_free_transfer(*it); } + idle_transfers_lock_.unlock(); + idle_transfers_.clear(); if(buffer_ != 0) @@ -86,6 +89,7 @@ void TransferPool::submit(size_t num_parallel_transfers) { std::cerr << "[TransferPool::submit] too few idle transfers!" << std::endl; } + pending_transfers_lock_.lock(); for(size_t i = 0; i < num_parallel_transfers; ++i) { @@ -105,10 +109,14 @@ void TransferPool::submit(size_t num_parallel_transfers) std::cerr << "[TransferPool::submit] failed to submit transfer" << std::endl; } } + + pending_transfers_lock_.unlock(); } void TransferPool::cancel() { + pending_transfers_lock_.lock(); + for(TransferQueue::iterator it = pending_transfers_.begin(); it != pending_transfers_.end(); ++it) { int r = libusb_cancel_transfer(*it); @@ -119,6 +127,8 @@ void TransferPool::cancel() } } + pending_transfers_lock_.unlock(); + //idle_transfers_.insert(idle_transfers_.end(), pending_transfers_.begin(), pending_transfers_.end()); } @@ -160,6 +170,7 @@ void TransferPool::onTransferCompleteStatic(libusb_transfer* transfer) void TransferPool::onTransferComplete(libusb_transfer* transfer) { + pending_transfers_lock_.lock(); // remove transfer from pending queue - should be fast as it is somewhere at the front TransferQueue::iterator it = std::find(pending_transfers_.begin(), pending_transfers_.end(), transfer); @@ -170,6 +181,8 @@ void TransferPool::onTransferComplete(libusb_transfer* transfer) pending_transfers_.erase(it); + pending_transfers_lock_.unlock(); + // process data processTransfer(transfer);