1 /* 2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 #ifndef IO_SCHEDULER_H 7 #define IO_SCHEDULER_H 8 9 10 #include <KernelExport.h> 11 12 #include <condition_variable.h> 13 #include <lock.h> 14 #include <Notifications.h> 15 #include <util/DoublyLinkedList.h> 16 #include <util/OpenHashTable.h> 17 18 #include "dma_resources.h" 19 #include "IORequest.h" 20 21 22 // I/O scheduler notifications 23 #define IO_SCHEDULER_MONITOR '_io_' 24 #define IO_SCHEDULER_ADDED 0x01 25 #define IO_SCHEDULER_REMOVED 0x02 26 #define IO_SCHEDULER_REQUEST_SCHEDULED 0x04 27 #define IO_SCHEDULER_REQUEST_FINISHED 0x08 28 #define IO_SCHEDULER_OPERATION_STARTED 0x10 29 #define IO_SCHEDULER_OPERATION_FINISHED 0x20 30 31 32 class IOCallback { 33 public: 34 virtual ~IOCallback(); 35 36 virtual status_t DoIO(IOOperation* operation) = 0; 37 }; 38 39 typedef status_t (*io_callback)(void* data, io_operation* operation); 40 41 42 struct IORequestOwner : DoublyLinkedListLinkImpl<IORequestOwner> { 43 team_id team; 44 thread_id thread; 45 int32 priority; 46 IORequestList requests; 47 IORequestList completed_requests; 48 IOOperationList operations; 49 IORequestOwner* hash_link; 50 51 bool IsActive() const 52 { return !requests.IsEmpty() 53 || !completed_requests.IsEmpty() 54 || !operations.IsEmpty(); } 55 56 void Dump() const; 57 }; 58 59 60 class IOScheduler : public DoublyLinkedListLinkImpl<IOScheduler> { 61 public: 62 IOScheduler(DMAResource* resource); 63 ~IOScheduler(); 64 65 status_t Init(const char* name); 66 status_t InitCheck() const; 67 68 void SetCallback(IOCallback& callback); 69 void SetCallback(io_callback callback, void* data); 70 71 status_t ScheduleRequest(IORequest* request); 72 73 void AbortRequest(IORequest* request, 74 status_t status = B_CANCELED); 75 void OperationCompleted(IOOperation* operation, 76 status_t status, size_t transferredBytes); 77 // called by the driver when the operation 78 // has been completed successfully or failed 79 // for some reason 80 81 const char* Name() const { return fName; } 82 83 int32 ID() const { return fID; } 84 85 void Dump() const; 86 87 private: 88 typedef DoublyLinkedList<IORequestOwner> RequestOwnerList; 89 90 struct RequestOwnerHashDefinition; 91 struct RequestOwnerHashTable; 92 93 void _Finisher(); 94 bool _FinisherWorkPending(); 95 off_t _ComputeRequestOwnerBandwidth( 96 int32 priority) const; 97 bool _NextActiveRequestOwner(IORequestOwner*& owner, 98 off_t& quantum); 99 bool _PrepareRequestOperations(IORequest* request, 100 IOOperationList& operations, 101 int32& operationsPrepared); 102 bool _PrepareRequestOperations(IORequest* request, 103 IOOperationList& operations, 104 int32& operationsPrepared, off_t quantum, 105 off_t& usedBandwidth); 106 void _SortOperations(IOOperationList& operations, 107 off_t& lastOffset); 108 status_t _Scheduler(); 109 static status_t _SchedulerThread(void* self); 110 status_t _RequestNotifier(); 111 static status_t _RequestNotifierThread(void* self); 112 113 void _AddRequestOwner(IORequestOwner* owner); 114 IORequestOwner* _GetRequestOwner(team_id team, thread_id thread, 115 bool allocate); 116 117 static status_t _IOCallbackWrapper(void* data, 118 io_operation* operation); 119 120 private: 121 DMAResource* fDMAResource; 122 char* fName; 123 int32 fID; 124 spinlock fFinisherLock; 125 mutex fLock; 126 thread_id fSchedulerThread; 127 thread_id fRequestNotifierThread; 128 io_callback fIOCallback; 129 void* fIOCallbackData; 130 IORequestList fUnscheduledRequests; 131 IORequestList fFinishedRequests; 132 ConditionVariable fNewRequestCondition; 133 ConditionVariable fFinishedOperationCondition; 134 ConditionVariable fFinishedRequestCondition; 135 IOOperation** fOperationArray; 136 IOOperationList fUnusedOperations; 137 IOOperationList fCompletedOperations; 138 IORequestOwner* fAllocatedRequestOwners; 139 int32 fAllocatedRequestOwnerCount; 140 RequestOwnerList fActiveRequestOwners; 141 RequestOwnerList fUnusedRequestOwners; 142 RequestOwnerHashTable* fRequestOwners; 143 size_t fBlockSize; 144 int32 fPendingOperations; 145 off_t fIterationBandwidth; 146 off_t fMinOwnerBandwidth; 147 off_t fMaxOwnerBandwidth; 148 volatile bool fTerminating; 149 }; 150 151 typedef DoublyLinkedList<IOScheduler> IOSchedulerList; 152 153 154 class IOSchedulerRoster { 155 public: 156 static void Init(); 157 static IOSchedulerRoster* Default() { return &sDefaultInstance; } 158 159 bool Lock() { return mutex_lock(&fLock) == B_OK; } 160 void Unlock() { mutex_unlock(&fLock); } 161 162 const IOSchedulerList& SchedulerList() const 163 { return fSchedulers; } 164 // caller must keep the roster locked, 165 // while accessing the list 166 167 void AddScheduler(IOScheduler* scheduler); 168 void RemoveScheduler(IOScheduler* scheduler); 169 170 void Notify(uint32 eventCode, 171 const IOScheduler* scheduler, 172 IORequest* request = NULL, 173 IOOperation* operation = NULL); 174 175 int32 NextID(); 176 177 private: 178 IOSchedulerRoster(); 179 ~IOSchedulerRoster(); 180 181 private: 182 mutex fLock; 183 int32 fNextID; 184 IOSchedulerList fSchedulers; 185 DefaultNotificationService fNotificationService; 186 char fEventBuffer[256]; 187 188 static IOSchedulerRoster sDefaultInstance; 189 }; 190 191 192 #endif // IO_SCHEDULER_H 193