Author: bonefish Date: 2009-12-19 15:32:14 +0100 (Sat, 19 Dec 2009) New Revision: 34702 Changeset: http://dev.haiku-os.org/changeset/34702/haiku Modified: haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_cd/Jamfile haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/Jamfile haiku/trunk/src/system/kernel/device_manager/IOScheduler.cpp haiku/trunk/src/system/kernel/device_manager/IOScheduler.h Log: * Implemented missing cleanup when an IOScheduler is destroyed. The threads weren't terminated orderly. * IOScheduler now stores its name and gets a unique ID. * Added IOSchedulerRoster singleton which registers all IOSchedulers. It also provides a notification service. We generate interesting events for IOSchedulers, IORequests, and IOOperations. Modified: haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_cd/Jamfile =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_cd/Jamfile 2009-12-19 14:23:44 UTC (rev 34701) +++ haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_cd/Jamfile 2009-12-19 14:32:14 UTC (rev 34702) @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers disk scsi scsi_cd ; -UsePrivateHeaders drivers kernel ; +UsePrivateKernelHeaders ; +UsePrivateHeaders drivers ; SubDirHdrs $(HAIKU_TOP) src system kernel device_manager ; KernelAddon scsi_cd : Modified: haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/Jamfile =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/Jamfile 2009-12-19 14:23:44 UTC (rev 34701) +++ haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/Jamfile 2009-12-19 14:32:14 UTC (rev 34702) @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers disk scsi scsi_disk ; -UsePrivateHeaders drivers kernel ; +UsePrivateKernelHeaders ; +UsePrivateHeaders drivers ; SubDirHdrs $(HAIKU_TOP) src system kernel device_manager ; KernelAddon scsi_disk : Modified: haiku/trunk/src/system/kernel/device_manager/IOScheduler.cpp =================================================================== --- haiku/trunk/src/system/kernel/device_manager/IOScheduler.cpp 2009-12-19 14:23:44 UTC (rev 34701) +++ haiku/trunk/src/system/kernel/device_manager/IOScheduler.cpp 2009-12-19 14:32:14 UTC (rev 34702) @@ -1,5 +1,5 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@xxxxxxx * Copyright 2004-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * Distributed under the terms of the MIT License. */ @@ -30,6 +30,9 @@ #endif +// #pragma mark - IOCallback + + IOCallback::~IOCallback() { } @@ -99,21 +102,51 @@ IOScheduler::IOScheduler(DMAResource* resource) : fDMAResource(resource), + fName(NULL), + fID(-1), + fSchedulerThread(-1), + fRequestNotifierThread(-1), fOperationArray(NULL), fAllocatedRequestOwners(NULL), fRequestOwners(NULL), fBlockSize(0), - fPendingOperations(0) + fPendingOperations(0), + fTerminating(false) { mutex_init(&fLock, "I/O scheduler"); B_INITIALIZE_SPINLOCK(&fFinisherLock); + + fNewRequestCondition.Init(this, "I/O new request"); + fFinishedOperationCondition.Init(this, "I/O finished operation"); + fFinishedRequestCondition.Init(this, "I/O finished request"); + } IOScheduler::~IOScheduler() { - // TODO: Shutdown threads. + if (InitCheck() == B_OK) + IOSchedulerRoster::Default()->RemoveScheduler(this); + // shutdown threads + MutexLocker locker(fLock); + InterruptsSpinLocker finisherLocker(fFinisherLock); + fTerminating = true; + + fNewRequestCondition.NotifyAll(); + fFinishedOperationCondition.NotifyAll(); + fFinishedRequestCondition.NotifyAll(); + + finisherLocker.Unlock(); + locker.Unlock(); + + if (fSchedulerThread >= 0) + wait_for_thread(fSchedulerThread, NULL); + + if (fRequestNotifierThread >= 0) + wait_for_thread(fRequestNotifierThread, NULL); + + // destroy our belongings mutex_lock(&fLock); mutex_destroy(&fLock); @@ -124,15 +157,17 @@ delete fRequestOwners; delete[] fAllocatedRequestOwners; + + free(fName); } status_t IOScheduler::Init(const char* name) { - fNewRequestCondition.Init(this, "I/O new request"); - fFinishedOperationCondition.Init(this, "I/O finished operation"); - fFinishedRequestCondition.Init(this, "I/O finished request"); + fName = strdup(name); + if (fName == NULL) + return B_NO_MEMORY; size_t count = fDMAResource != NULL ? fDMAResource->BufferCount() : 16; for (size_t i = 0; i < count; i++) { @@ -195,10 +230,20 @@ resume_thread(fSchedulerThread); resume_thread(fRequestNotifierThread); + + IOSchedulerRoster::Default()->AddScheduler(this); + return B_OK; } +status_t +IOScheduler::InitCheck() const +{ + return fRequestNotifierThread >= 0 ? B_OK : B_NO_INIT; +} + + void IOScheduler::SetCallback(IOCallback& callback) { @@ -259,6 +304,9 @@ if (!wasActive) fActiveRequestOwners.Add(owner); + IOSchedulerRoster::Default()->Notify(IO_SCHEDULER_REQUEST_SCHEDULED, this, + request); + fNewRequestCondition.NotifyAll(); return B_OK; @@ -325,7 +373,14 @@ TRACE("IOScheduler::_Finisher(): operation: %p\n", operation); - if (!operation->Finish()) { + bool operationFinished = operation->Finish(); + + IOSchedulerRoster::Default()->Notify(IO_SCHEDULER_OPERATION_FINISHED, + this, operation->Parent(), operation); + // Notify for every time the operation is passed to the I/O hook, + // not only when it is fully finished. + + if (!operationFinished) { TRACE(" operation: %p not finished yet\n", operation); MutexLocker _(fLock); operation->SetTransferredBytes(0); @@ -379,6 +434,8 @@ fFinishedRequestCondition.NotifyAll(); } else { // No callbacks -- finish the request right now. + IOSchedulerRoster::Default()->Notify( + IO_SCHEDULER_REQUEST_FINISHED, this, request); request->NotifyFinished(); } } @@ -472,10 +529,13 @@ } -void +bool IOScheduler::_NextActiveRequestOwner(IORequestOwner*& owner, off_t& quantum) { while (true) { + if (fTerminating) + return false; + if (owner != NULL) owner = fActiveRequestOwners.GetNext(owner); if (owner == NULL) @@ -483,7 +543,7 @@ if (owner != NULL) { quantum = _ComputeRequestOwnerBandwidth(owner->priority); - return; + return true; } // Wait for new requests owners. First check whether any finisher work @@ -579,7 +639,7 @@ IORequestOwner* owner = NULL; off_t quantum = 0; - while (true) { + while (!fTerminating) { //dprintf("IOScheduler::_Scheduler(): next iteration: request owner: %p, quantum: %lld\n", owner, quantum); MutexLocker locker(fLock); @@ -594,8 +654,12 @@ fActiveRequestOwners.Remove(&marker); } - if (owner == NULL || quantum < fBlockSize) - _NextActiveRequestOwner(owner, quantum); + if (owner == NULL || quantum < fBlockSize) { + if (!_NextActiveRequestOwner(owner, quantum)) { + // we've been asked to terminate + return B_OK; + } + } while (resourcesAvailable && iterationBandwidth >= fBlockSize) { //dprintf("IOScheduler::_Scheduler(): request owner: %p (thread %ld)\n", @@ -673,13 +737,16 @@ TRACE("IOScheduler::_Scheduler(): calling callback for " "operation %ld: %p\n", i++, operation); + IOSchedulerRoster::Default()->Notify(IO_SCHEDULER_OPERATION_STARTED, + this, operation->Parent(), operation); + fIOCallback(fIOCallbackData, operation); _Finisher(); } // wait for all operations to finish - while (true) { + while (!fTerminating) { locker.Lock(); if (fPendingOperations == 0) @@ -729,6 +796,9 @@ IORequest* request = fFinishedRequests.RemoveHead(); if (request == NULL) { + if (fTerminating) + return B_OK; + ConditionVariableEntry entry; fFinishedRequestCondition.Add(&entry); @@ -740,6 +810,9 @@ locker.Unlock(); + IOSchedulerRoster::Default()->Notify(IO_SCHEDULER_REQUEST_FINISHED, + this, request); + // notify the request request->NotifyFinished(); } @@ -796,3 +869,72 @@ return ((IOCallback*)data)->DoIO(operation); } + +// #pragma mark - IOSchedulerNotificationService + + +/*static*/ IOSchedulerRoster IOSchedulerRoster::sDefaultInstance; + + +/*static*/ void +IOSchedulerRoster::Init() +{ + new(&sDefaultInstance) IOSchedulerRoster; +} + + +void +IOSchedulerRoster::AddScheduler(IOScheduler* scheduler) +{ + AutoLocker<IOSchedulerRoster> locker(this); + scheduler->SetID(fNextID++); + fSchedulers.Add(scheduler); + locker.Unlock(); + + Notify(IO_SCHEDULER_ADDED, scheduler); +} + + +void +IOSchedulerRoster::RemoveScheduler(IOScheduler* scheduler) +{ + AutoLocker<IOSchedulerRoster> locker(this); + fSchedulers.Remove(scheduler); + locker.Unlock(); + + Notify(IO_SCHEDULER_REMOVED, scheduler); +} + + +void +IOSchedulerRoster::Notify(uint32 eventCode, const IOScheduler* scheduler, + IORequest* request, IOOperation* operation) +{ + char eventBuffer[128]; + KMessage event; + event.SetTo(eventBuffer, sizeof(eventBuffer), IO_SCHEDULER_MONITOR); + event.AddInt32("event", eventCode); + event.AddPointer("scheduler", scheduler); + if (request != NULL) { + event.AddPointer("request", request); + if (operation != NULL) + event.AddPointer("operation", operation); + } + + fNotificationService.Notify(event, eventCode); +} + + +IOSchedulerRoster::IOSchedulerRoster() + : + fNextID(1), + fNotificationService("I/O") +{ + mutex_init(&fLock, "IOSchedulerRoster"); +} + + +IOSchedulerRoster::~IOSchedulerRoster() +{ + mutex_destroy(&fLock); +} Modified: haiku/trunk/src/system/kernel/device_manager/IOScheduler.h =================================================================== --- haiku/trunk/src/system/kernel/device_manager/IOScheduler.h 2009-12-19 14:23:44 UTC (rev 34701) +++ haiku/trunk/src/system/kernel/device_manager/IOScheduler.h 2009-12-19 14:32:14 UTC (rev 34702) @@ -1,15 +1,17 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@xxxxxxx * Copyright 2004-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * Distributed under the terms of the MIT License. */ #ifndef IO_SCHEDULER_H #define IO_SCHEDULER_H + #include <KernelExport.h> #include <condition_variable.h> #include <lock.h> +#include <Notifications.h> #include <util/DoublyLinkedList.h> #include <util/OpenHashTable.h> @@ -17,6 +19,16 @@ #include "IORequest.h" +// I/O scheduler notifications +#define IO_SCHEDULER_MONITOR '_io_' +#define IO_SCHEDULER_ADDED 0x01 +#define IO_SCHEDULER_REMOVED 0x02 +#define IO_SCHEDULER_REQUEST_SCHEDULED 0x04 +#define IO_SCHEDULER_REQUEST_FINISHED 0x08 +#define IO_SCHEDULER_OPERATION_STARTED 0x10 +#define IO_SCHEDULER_OPERATION_FINISHED 0x20 + + class IOCallback { public: virtual ~IOCallback(); @@ -45,12 +57,13 @@ }; -class IOScheduler { +class IOScheduler : public DoublyLinkedListLinkImpl<IOScheduler> { public: IOScheduler(DMAResource* resource); ~IOScheduler(); status_t Init(const char* name); + status_t InitCheck() const; void SetCallback(IOCallback& callback); void SetCallback(io_callback callback, void* data); @@ -65,6 +78,11 @@ // has been completed successfully or failed // for some reason + const char* Name() const { return fName; } + + int32 ID() const { return fID; } + void SetID(int32 id) { fID = id; } + void Dump() const; private: @@ -77,7 +95,7 @@ bool _FinisherWorkPending(); off_t _ComputeRequestOwnerBandwidth( int32 priority) const; - void _NextActiveRequestOwner(IORequestOwner*& owner, + bool _NextActiveRequestOwner(IORequestOwner*& owner, off_t& quantum); bool _PrepareRequestOperations(IORequest* request, IOOperationList& operations, @@ -102,6 +120,8 @@ private: DMAResource* fDMAResource; + char* fName; + int32 fID; spinlock fFinisherLock; mutex fLock; thread_id fSchedulerThread; @@ -126,6 +146,45 @@ off_t fIterationBandwidth; off_t fMinOwnerBandwidth; off_t fMaxOwnerBandwidth; + volatile bool fTerminating; }; +typedef DoublyLinkedList<IOScheduler> IOSchedulerList; + + +class IOSchedulerRoster { +public: + static void Init(); + static IOSchedulerRoster* Default() { return &sDefaultInstance; } + + bool Lock() { return mutex_lock(&fLock) == B_OK; } + void Unlock() { mutex_unlock(&fLock); } + + const IOSchedulerList& SchedulerList() const + { return fSchedulers; } + // caller must keep the roster locked, + // while accessing the list + + void AddScheduler(IOScheduler* scheduler); + void RemoveScheduler(IOScheduler* scheduler); + + void Notify(uint32 eventCode, + const IOScheduler* scheduler, + IORequest* request = NULL, + IOOperation* operation = NULL); + +private: + IOSchedulerRoster(); + ~IOSchedulerRoster(); + +private: + mutex fLock; + int32 fNextID; + IOSchedulerList fSchedulers; + DefaultNotificationService fNotificationService; + + static IOSchedulerRoster sDefaultInstance; +}; + + #endif // IO_SCHEDULER_H