xref: /haiku/src/system/kernel/device_manager/IOScheduler.h (revision b3de82492af3b6412ffaf7eb87fd6e1995755685)
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