* 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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user