From 5c8d420b7c2a26b7153114396e6d0c4c1641dd3d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 19 Aug 2008 21:37:16 +0000 Subject: [PATCH] * Added "bool wait" parameter to _GetOperation(). If false and no unused operation is available ATM, it will return NULL. * _Finisher() does now re-schedule a request, if all of its operations finished successfully, but there are still remaining bytes. * _Scheduler() does now operate in two passes. First it creates as many operations for a given request as possible, then it executes the operations. This fixes bug #2644. The problem was that by creating and executing the operations in a single loop, an operation could be finished before the next one was added. The request would thus be considered finished and the request owner be notified. This would usually lead to the destruction of the request while it was still in use. * _Scheduler(): In case we don't have a DMA resource also advance the request. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27070 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/device_manager/IOScheduler.cpp | 26 +++++++++++++++---- .../kernel/device_manager/IOScheduler.h | 2 +- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/system/kernel/device_manager/IOScheduler.cpp b/src/system/kernel/device_manager/IOScheduler.cpp index 0c7f5b6d5a..e0363bbc7c 100644 --- a/src/system/kernel/device_manager/IOScheduler.cpp +++ b/src/system/kernel/device_manager/IOScheduler.cpp @@ -209,7 +209,12 @@ IOScheduler::_Finisher() // If the request is done, we need to perform its notifications. if (request->IsFinished()) { - if (request->HasCallbacks()) { + if (request->Status() == B_OK && request->RemainingBytes() > 0) { + // The request has been processed OK so far, but it isn't really + // finished yet. + fUnscheduledRequests.Add(request); + fNewRequestCondition.NotifyAll(); + } else if (request->HasCallbacks()) { // The request has callbacks that may take some time to perform, // so we hand it over to the request notifier. fFinishedRequests.Add(request); @@ -233,13 +238,13 @@ IOScheduler::_FinisherWorkPending() IOOperation* -IOScheduler::_GetOperation() +IOScheduler::_GetOperation(bool wait) { while (true) { MutexLocker locker(fLock); IOOperation* operation = fUnusedOperations.RemoveHead(); - if (operation != NULL) + if (operation != NULL || !wait) return operation; // Wait for new operations. First check whether any finisher work has @@ -311,16 +316,26 @@ IOScheduler::_Scheduler() TRACE("IOScheduler::_Scheduler(): request: %p\n", request); if (fDMAResource != NULL) { + IOOperationList operations; while (request->RemainingBytes() > 0) { - IOOperation* operation = _GetOperation(); + IOOperation* operation = _GetOperation(operations.IsEmpty()); + if (operation == NULL) + break; status_t status = fDMAResource->TranslateNext(request, operation); if (status != B_OK) { +// TODO: Handle correctly! E.g. B_BUSY just means that some resource (e.g. +// DMA buffers) isn't available ATM. We should execute the operations we have +// so far and wait for resources to become available again. AbortRequest(request, status); break; } + operations.Add(operation); + } + + while (IOOperation* operation = operations.RemoveHead()) { TRACE("IOScheduler::_Scheduler(): calling callback for " "operation: %p\n", operation); @@ -329,9 +344,10 @@ IOScheduler::_Scheduler() } else { // TODO: If the device has block size restrictions, we might need to use a // bounce buffer. - IOOperation* operation = _GetOperation(); + IOOperation* operation = _GetOperation(true); operation->Prepare(request); operation->SetOriginalRange(request->Offset(), request->Length()); + request->Advance(request->Length()); fIOCallback(fIOCallbackData, operation); } } diff --git a/src/system/kernel/device_manager/IOScheduler.h b/src/system/kernel/device_manager/IOScheduler.h index 0ecf5f978c..e3cb2ed1c0 100644 --- a/src/system/kernel/device_manager/IOScheduler.h +++ b/src/system/kernel/device_manager/IOScheduler.h @@ -47,7 +47,7 @@ public: private: void _Finisher(); bool _FinisherWorkPending(); - IOOperation* _GetOperation(); + IOOperation* _GetOperation(bool wait); IORequest* _GetNextUnscheduledRequest(); status_t _Scheduler(); static status_t _SchedulerThread(void* self);