Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Unified Diff: device/usb/usb_device_handle_usbfs.cc

Issue 2274343002: Tell the kernel to discard USB requests when they time out. (Closed)
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « device/usb/usb_device_handle_usbfs.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: device/usb/usb_device_handle_usbfs.cc
diff --git a/device/usb/usb_device_handle_usbfs.cc b/device/usb/usb_device_handle_usbfs.cc
index 4ac0d10d080f254d953ae5bea798c25e21fa8139..07ca8cbe97a02f1a3e8dd35e56b0a7cb9006eaa9 100644
--- a/device/usb/usb_device_handle_usbfs.cc
+++ b/device/usb/usb_device_handle_usbfs.cc
@@ -253,6 +253,12 @@ struct UsbDeviceHandleUsbfs::Transfer {
base::CancelableClosure timeout_closure;
bool cancelled = false;
+ // When the URB is |cancelled| these two flags track whether the URB has both
+ // been |discarded| and |reaped| since the possiblity of last-minute
+ // completion makes these two conditions race.
+ bool discarded = false;
+ bool reaped = false;
+
// The |urb| field must be the last in the struct so that the extra space
// allocated by the overridden new function above extends the length of its
// |iso_frame_desc| field.
@@ -738,17 +744,16 @@ void UsbDeviceHandleUsbfs::GenericTransferInternal(
void UsbDeviceHandleUsbfs::ReapedUrbs(const std::vector<usbdevfs_urb*>& urbs) {
for (auto* urb : urbs) {
- Transfer* this_transfer = static_cast<Transfer*>(urb->usercontext);
- DCHECK_EQ(urb, &this_transfer->urb);
- auto it = std::find_if(
- transfers_.begin(), transfers_.end(),
- [this_transfer](const std::unique_ptr<Transfer>& transfer) -> bool {
- return transfer.get() == this_transfer;
- });
- DCHECK(it != transfers_.end());
- std::unique_ptr<Transfer> transfer = std::move(*it);
- transfers_.erase(it);
- TransferComplete(std::move(transfer));
+ Transfer* transfer = static_cast<Transfer*>(urb->usercontext);
+ DCHECK_EQ(urb, &transfer->urb);
+
+ if (transfer->cancelled) {
+ transfer->reaped = true;
+ if (transfer->discarded)
+ RemoveFromTransferList(transfer);
+ } else {
+ TransferComplete(RemoveFromTransferList(transfer));
+ }
}
}
@@ -830,21 +835,35 @@ void UsbDeviceHandleUsbfs::ReportIsochronousError(
void UsbDeviceHandleUsbfs::SetUpTimeoutCallback(Transfer* transfer,
unsigned int timeout) {
if (timeout > 0) {
- transfer->timeout_closure.Reset(base::Bind(
- &UsbDeviceHandleUsbfs::CancelTransfer, transfer, USB_TRANSFER_TIMEOUT));
+ transfer->timeout_closure.Reset(
+ base::Bind(&UsbDeviceHandleUsbfs::CancelTransfer, this, transfer,
+ USB_TRANSFER_TIMEOUT));
task_runner_->PostDelayedTask(FROM_HERE,
transfer->timeout_closure.callback(),
base::TimeDelta::FromMilliseconds(timeout));
}
}
-// static
+std::unique_ptr<UsbDeviceHandleUsbfs::Transfer>
+UsbDeviceHandleUsbfs::RemoveFromTransferList(Transfer* transfer_ptr) {
+ auto it = std::find_if(
+ transfers_.begin(), transfers_.end(),
+ [transfer_ptr](const std::unique_ptr<Transfer>& transfer) -> bool {
+ return transfer.get() == transfer_ptr;
+ });
+ DCHECK(it != transfers_.end());
+ std::unique_ptr<Transfer> transfer = std::move(*it);
+ transfers_.erase(it);
+ return transfer;
+}
+
void UsbDeviceHandleUsbfs::CancelTransfer(Transfer* transfer,
UsbTransferStatus status) {
// |transfer| must stay in |transfers_| as it is still being processed by the
- // kernel and may be reaped later.
+ // kernel and will be reaped later.
transfer->cancelled = true;
transfer->timeout_closure.Cancel();
+
if (transfer->urb.type == USBDEVFS_URB_TYPE_ISO) {
std::vector<IsochronousPacket> packets(transfer->urb.number_of_packets);
for (size_t i = 0; i < packets.size(); ++i) {
@@ -856,6 +875,25 @@ void UsbDeviceHandleUsbfs::CancelTransfer(Transfer* transfer,
} else {
transfer->RunCallback(status, 0);
}
+
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDeviceHandleUsbfs::DiscardUrbBlocking, this, transfer));
+}
+
+void UsbDeviceHandleUsbfs::DiscardUrbBlocking(Transfer* transfer) {
+ if (fd_.is_valid())
+ HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_DISCARDURB, &transfer->urb));
+
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDeviceHandleUsbfs::UrbDiscarded, this, transfer));
+}
+
+void UsbDeviceHandleUsbfs::UrbDiscarded(Transfer* transfer) {
+ transfer->discarded = true;
+ if (transfer->reaped)
+ RemoveFromTransferList(transfer);
}
} // namespace device
« no previous file with comments | « device/usb/usb_device_handle_usbfs.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698