* 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
This commit is contained in:
Ingo Weinhold
2008-08-19 21:37:16 +00:00
parent 16d07755e4
commit 5c8d420b7c
2 changed files with 22 additions and 6 deletions
@@ -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);
}
}
@@ -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);