USB: Make Pipe::CancelQueuedTransfers virtual and add a ControlPipe variant.

Control pipes have internal structures to wait for queued requests.
When force-cancelling queued transfers, the callbacks will not be called,
and so such transfers would be left hanging until the timeout occurred
or the destructor destroys the semaphore and mutex.

This probably will not fix any hang-related tickets, though, as force
cancellation is pretty much only used during device/pipe teardown.

Change-Id: I41db7caf380cdd082bc3509e95262317489bf100
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4488
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Augustin Cavalier 2021-09-20 11:05:31 -04:00 committed by waddlesplash
parent 3e0eea85ec
commit 2f496b3095
2 changed files with 23 additions and 2 deletions

View File

@ -23,7 +23,7 @@ Pipe::~Pipe()
{
PutUSBID();
CancelQueuedTransfers(true);
Pipe::CancelQueuedTransfers(true);
GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED);
}
@ -334,6 +334,10 @@ ControlPipe::ControlPipe(Object *parent)
ControlPipe::~ControlPipe()
{
// We do this here in case a submitted request is still running.
PutUSBID();
ControlPipe::CancelQueuedTransfers(true);
if (fNotifySem >= 0)
delete_sem(fNotifySem);
mutex_lock(&fSendRequestLock);
@ -465,3 +469,18 @@ ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value,
delete transfer;
return result;
}
status_t
ControlPipe::CancelQueuedTransfers(bool force)
{
if (force && fNotifySem >= 0) {
// There is likely a transfer currently running; we need to cancel it
// manually, as callbacks are not invoked when force-cancelling.
fTransferStatus = B_CANCELED;
fActualLength = 0;
release_sem_etc(fNotifySem, 1, B_RELEASE_IF_WAITING_ONLY);
}
return Pipe::CancelQueuedTransfers(force);
}

View File

@ -341,7 +341,7 @@ virtual void SetDataToggle(bool toggle)
{ fDataToggle = toggle; }
status_t SubmitTransfer(Transfer *transfer);
status_t CancelQueuedTransfers(bool force);
virtual status_t CancelQueuedTransfers(bool force);
void SetControllerCookie(void *cookie)
{ fControllerCookie = cookie; }
@ -414,6 +414,8 @@ static void SendRequestCallback(void *cookie,
usb_callback_func callback,
void *callbackCookie);
virtual status_t CancelQueuedTransfers(bool force);
private:
mutex fSendRequestLock;
sem_id fNotifySem;