xref: /haiku/src/system/kernel/device_manager/IORequest.h (revision eea5774f46bba925156498abf9cb1a1165647bf7)
1 /*
2  * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
4  * Distributed under the terms of the MIT License.
5  */
6 #ifndef IO_REQUEST_H
7 #define IO_REQUEST_H
8 
9 
10 #include <sys/uio.h>
11 
12 #include <new>
13 
14 #include <fs_interface.h>
15 
16 #include <condition_variable.h>
17 #include <lock.h>
18 #include <util/DoublyLinkedList.h>
19 
20 #include "dma_resources.h"
21 
22 
23 #define B_PHYSICAL_IO_REQUEST	0x01	/* buffer points to physical memory */
24 #define B_VIP_IO_REQUEST		0x02	/* used by the page writer -- make sure
25 										   allocations won't fail */
26 #define B_DELETE_IO_REQUEST		0x04	/* delete request when finished */
27 
28 class DMABuffer;
29 struct IOOperation;
30 
31 typedef struct IOOperation io_operation;
32 
33 class IOBuffer : public DoublyLinkedListLinkImpl<IOBuffer> {
34 public:
35 	static	IOBuffer*			Create(uint32 count, bool vip);
36 			void				Delete();
37 
38 			bool				IsVirtual() const { return !fPhysical; }
39 			bool				IsPhysical() const { return fPhysical; }
40 			bool				IsUser() const { return fUser; }
41 
42 			void				SetVecs(generic_size_t firstVecOffset,
43 									generic_size_t lastVecSize,
44 									const generic_io_vec* vecs, uint32 count,
45 									generic_size_t length, uint32 flags);
46 
47 			void				SetPhysical(bool physical)
48 									{ fPhysical = physical; }
49 			void				SetUser(bool user) { fUser = user; }
50 			void				SetLength(generic_size_t length)
51 									{ fLength = length; }
52 			void				SetVecCount(uint32 count) { fVecCount = count; }
53 
54 			generic_size_t		Length() const { return fLength; }
55 
56 			generic_io_vec*		Vecs() { return fVecs; }
57 			generic_io_vec&		VecAt(size_t index) { return fVecs[index]; }
58 			size_t				VecCount() const { return fVecCount; }
59 			size_t				Capacity() const { return fCapacity; }
60 
61 			status_t			GetNextVirtualVec(void*& cookie, iovec& vector);
62 			void				FreeVirtualVecCookie(void* cookie);
63 
64 			status_t			LockMemory(team_id team, bool isWrite);
65 			void				UnlockMemory(team_id team, bool isWrite);
66 			bool				IsMemoryLocked() const
67 									{ return fMemoryLocked; }
68 
69 			void				Dump() const;
70 
71 private:
72 								IOBuffer();
73 								~IOBuffer();
74 									// not implemented
75 			void				_UnlockMemory(team_id team, size_t count,
76 									bool isWrite);
77 
78 			bool				fUser;
79 			bool				fPhysical;
80 			bool				fVIP;
81 			bool				fMemoryLocked;
82 			generic_size_t		fLength;
83 			size_t				fVecCount;
84 			size_t				fCapacity;
85 			generic_io_vec		fVecs[1];
86 };
87 
88 
89 struct IORequest;
90 struct IORequestOwner;
91 
92 
93 class IORequestChunk {
94 public:
95 								IORequestChunk();
96 	virtual						~IORequestChunk();
97 
98 			IORequest*			Parent() const { return fParent; }
99 			void				SetParent(IORequest* parent)
100 									{ fParent = parent; }
101 
102 			status_t			Status() const { return fStatus; }
103 
104 			DoublyLinkedListLink<IORequestChunk>*
105 									ListLink()	{ return &fListLink; }
106 
107 protected:
108 			void				SetStatus(status_t status)
109 									{ fStatus = status; }
110 			void				ResetStatus()
111 									{ fStatus = 1; }
112 
113 protected:
114 			IORequest*			fParent;
115 			status_t			fStatus;
116 
117 public:
118 			DoublyLinkedListLink<IORequestChunk> fListLink;
119 };
120 
121 typedef DoublyLinkedList<IORequestChunk,
122 	DoublyLinkedListMemberGetLink<IORequestChunk, &IORequestChunk::fListLink> >
123 		IORequestChunkList;
124 
125 
126 struct IOOperation : IORequestChunk, DoublyLinkedListLinkImpl<IOOperation> {
127 public:
128 			bool				Finish();
129 									// returns true, if it can be recycled
130 									// otherwise, there is more to be done
131 
132 			void				SetStatus(status_t status, generic_size_t completedLength);
133 
134 			status_t			Prepare(IORequest* request);
135 			void				SetOriginalRange(off_t offset,
136 									generic_size_t length);
137 									// also sets range
138 			void				SetRange(off_t offset, generic_size_t length);
139 
140 			off_t				Offset() const;
141 			generic_size_t		Length() const;
142 
143 			off_t				OriginalOffset() const
144 									{ return fOriginalOffset; }
145 			generic_size_t		OriginalLength() const
146 									{ return fOriginalLength; }
147 
148 			generic_size_t		TransferredBytes() const
149 									{ return fTransferredBytes; }
150 
151 			generic_io_vec*		Vecs() const;
152 			uint32				VecCount() const;
153 
154 			void				SetPartial(bool partialBegin, bool partialEnd);
155 			bool				HasPartialBegin() const
156 									{ return fPartialBegin; }
157 			bool				HasPartialEnd() const
158 									{ return fPartialEnd; }
159 			bool				IsWrite() const;
160 			bool				IsRead() const;
161 
162 			void				SetBlockSize(generic_size_t blockSize)
163 									{ fBlockSize  = blockSize; }
164 
165 			bool				UsesBounceBuffer() const
166 									{ return fUsesBounceBuffer; }
167 			void				SetUsesBounceBuffer(bool uses)
168 									{ fUsesBounceBuffer = uses; }
169 
170 			DMABuffer*			Buffer() const { return fDMABuffer; }
171 			void				SetBuffer(DMABuffer* buffer)
172 									{ fDMABuffer = buffer; }
173 
174 			void				Dump() const;
175 
176 protected:
177 			void				_PrepareVecs();
178 			status_t			_CopyPartialBegin(bool isWrite,
179 									bool& partialBlockOnly);
180 			status_t			_CopyPartialEnd(bool isWrite);
181 
182 			DMABuffer*			fDMABuffer;
183 			off_t				fOffset;
184 			off_t				fOriginalOffset;
185 			generic_size_t		fLength;
186 			generic_size_t		fOriginalLength;
187 			generic_size_t		fTransferredBytes;
188 			generic_size_t		fBlockSize;
189 			uint16				fSavedVecIndex;
190 			uint16				fSavedVecLength;
191 			uint8				fPhase;
192 			bool				fPartialBegin;
193 			bool				fPartialEnd;
194 			bool				fUsesBounceBuffer;
195 };
196 
197 
198 typedef IOOperation io_operation;
199 typedef DoublyLinkedList<IOOperation> IOOperationList;
200 
201 typedef struct IORequest io_request;
202 typedef void (*io_request_finished_callback)(void* data,
203 			io_request* request, status_t status, bool partialTransfer,
204 			generic_size_t transferredBytes);
205 typedef status_t (*io_request_iterate_callback)(void* data,
206 			io_request* request, bool* _partialTransfer);
207 
208 
209 struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl<IORequest> {
210 								IORequest();
211 	virtual						~IORequest();
212 
213 	static	IORequest*			Create(bool vip);
214 
215 			status_t			Init(off_t offset, generic_addr_t buffer,
216 									generic_size_t length, bool write,
217 									uint32 flags);
218 			status_t			Init(off_t offset, const generic_io_vec* vecs,
219 									size_t count, generic_size_t length,
220 									bool write, uint32 flags)
221 									{ return Init(offset, 0, 0, vecs, count,
222 										length, write, flags); }
223 			status_t			Init(off_t offset,
224 									generic_size_t firstVecOffset,
225 									generic_size_t lastVecSize,
226 									const generic_io_vec* vecs, size_t count,
227 									generic_size_t length, bool write,
228 									uint32 flags);
229 
230 			void				SetOwner(IORequestOwner* owner)
231 									{ fOwner = owner; }
232 			IORequestOwner*		Owner() const	{ return fOwner; }
233 
234 			status_t			CreateSubRequest(off_t parentOffset,
235 									off_t offset, generic_size_t length,
236 									IORequest*& subRequest);
237 			void				DeleteSubRequests();
238 
239 			void				SetFinishedCallback(
240 									io_request_finished_callback callback,
241 									void* cookie);
242 			void				SetIterationCallback(
243 									io_request_iterate_callback callback,
244 									void* cookie);
245 			io_request_finished_callback FinishedCallback(
246 									void** _cookie = NULL) const;
247 
248 			status_t			Wait(uint32 flags = 0, bigtime_t timeout = 0);
249 
250 			bool				IsFinished() const
251 									{ return fStatus != 1
252 										&& fPendingChildren == 0; }
253 			void				NotifyFinished();
254 			bool				HasCallbacks() const;
255 			void				SetStatusAndNotify(status_t status);
256 
257 			void				OperationFinished(IOOperation* operation);
258 			void				SubRequestFinished(IORequest* request,
259 									status_t status, bool partialTransfer,
260 									generic_size_t transferEndOffset);
261 			void				SetUnfinished();
262 
263 			generic_size_t		RemainingBytes() const
264 									{ return fRemainingBytes; }
265 			generic_size_t		TransferredBytes() const
266 									{ return fTransferSize; }
267 			bool				IsPartialTransfer() const
268 									{ return fPartialTransfer; }
269 			void				SetTransferredBytes(bool partialTransfer,
270 									generic_size_t transferredBytes);
271 
272 			void				SetSuppressChildNotifications(bool suppress);
273 			bool				SuppressChildNotifications() const
274 									{ return fSuppressChildNotifications; }
275 
276 			bool				IsWrite() const	{ return fIsWrite; }
277 			bool				IsRead() const	{ return !fIsWrite; }
278 			team_id				TeamID() const		{ return fTeam; }
279 			thread_id			ThreadID() const	{ return fThread; }
280 			uint32				Flags() const	{ return fFlags; }
281 
282 			IOBuffer*			Buffer() const	{ return fBuffer; }
283 			off_t				Offset() const	{ return fOffset; }
284 			generic_size_t		Length() const	{ return fLength; }
285 
286 			void				SetOffset(off_t offset)	{ fOffset = offset; }
287 
288 			uint32				VecIndex() const	{ return fVecIndex; }
289 			generic_size_t		VecOffset() const	{ return fVecOffset; }
290 
291 			void				Advance(generic_size_t bySize);
292 
293 			IORequest*			FirstSubRequest();
294 			IORequest*			NextSubRequest(IORequest* previous);
295 
296 			void				AddOperation(IOOperation* operation);
297 			void				RemoveOperation(IOOperation* operation);
298 
299 			status_t			CopyData(off_t offset, void* buffer,
300 									size_t size);
301 			status_t			CopyData(const void* buffer, off_t offset,
302 									size_t size);
303 			status_t			ClearData(off_t offset, generic_size_t size);
304 
305 			void				Dump() const;
306 
307 private:
308 			status_t			_CopyData(void* buffer, off_t offset,
309 									size_t size, bool copyIn);
310 	static	status_t			_CopySimple(void* bounceBuffer,
311 									generic_addr_t external, size_t size,
312 									team_id team, bool copyIn);
313 	static	status_t			_CopyPhysical(void* bounceBuffer,
314 									generic_addr_t external, size_t size,
315 									team_id team, bool copyIn);
316 	static	status_t			_CopyUser(void* bounceBuffer,
317 									generic_addr_t external, size_t size,
318 									team_id team, bool copyIn);
319 	static	status_t			_ClearDataSimple(generic_addr_t external,
320 									generic_size_t size, team_id team);
321 	static	status_t			_ClearDataPhysical(generic_addr_t external,
322 									generic_size_t size, team_id team);
323 	static	status_t			_ClearDataUser(generic_addr_t external,
324 									generic_size_t size, team_id team);
325 
326 			mutex				fLock;
327 			IORequestOwner*		fOwner;
328 			IOBuffer*			fBuffer;
329 			off_t				fOffset;
330 			generic_size_t		fLength;
331 			generic_size_t		fTransferSize;
332 									// After all subrequests/operations have
333 									// finished, number of contiguous bytes at
334 									// the beginning of the request that have
335 									// actually been transferred.
336 			generic_size_t		fRelativeParentOffset;
337 									// offset of this request relative to its
338 									// parent
339 			IORequestChunkList	fChildren;
340 			int32				fPendingChildren;
341 			uint32				fFlags;
342 			team_id				fTeam;
343 			thread_id			fThread;
344 			bool				fIsWrite;
345 			bool				fPartialTransfer;
346 			bool				fSuppressChildNotifications;
347 			bool				fIsNotified;
348 
349 			io_request_finished_callback	fFinishedCallback;
350 			void*				fFinishedCookie;
351 			io_request_iterate_callback	fIterationCallback;
352 			void*				fIterationCookie;
353 			ConditionVariable	fFinishedCondition;
354 
355 			// these are for iteration
356 			uint32				fVecIndex;
357 			generic_size_t		fVecOffset;
358 			generic_size_t		fRemainingBytes;
359 };
360 
361 
362 typedef DoublyLinkedList<IORequest> IORequestList;
363 
364 
365 #endif	// IO_REQUEST_H
366