xref: /haiku/src/system/kernel/device_manager/IORequest.h (revision 60b39cd7416028e61e3d30bb3ba28bd3526e6001)
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 struct 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 									const generic_io_vec* vecs, uint32 count,
44 									generic_size_t length, uint32 flags);
45 
46 			void				SetPhysical(bool physical)
47 									{ fPhysical = physical; }
48 			void				SetUser(bool user) { fUser = user; }
49 			void				SetLength(generic_size_t length)
50 									{ fLength = length; }
51 			void				SetVecCount(uint32 count) { fVecCount = count; }
52 
53 			generic_size_t		Length() const { return fLength; }
54 
55 			generic_io_vec*		Vecs() { return fVecs; }
56 			generic_io_vec&		VecAt(size_t index) { return fVecs[index]; }
57 			size_t				VecCount() const { return fVecCount; }
58 			size_t				Capacity() const { return fCapacity; }
59 
60 			status_t			GetNextVirtualVec(void*& cookie, iovec& vector);
61 			void				FreeVirtualVecCookie(void* cookie);
62 
63 			status_t			LockMemory(team_id team, bool isWrite);
64 			void				UnlockMemory(team_id team, bool isWrite);
65 			bool				IsMemoryLocked() const
66 									{ return fMemoryLocked; }
67 
68 			void				Dump() const;
69 
70 private:
71 								IOBuffer();
72 								~IOBuffer();
73 									// not implemented
74 			void				_UnlockMemory(team_id team, size_t count,
75 									bool isWrite);
76 
77 			bool				fUser;
78 			bool				fPhysical;
79 			bool				fVIP;
80 			bool				fMemoryLocked;
81 			generic_size_t		fLength;
82 			size_t				fVecCount;
83 			size_t				fCapacity;
84 			generic_io_vec		fVecs[1];
85 };
86 
87 
88 class IORequest;
89 class IORequestOwner;
90 
91 
92 class IORequestChunk {
93 public:
94 								IORequestChunk();
95 	virtual						~IORequestChunk();
96 
97 			IORequest*			Parent() const { return fParent; }
98 			void				SetParent(IORequest* parent)
99 									{ fParent = parent; }
100 
101 			status_t			Status() const { return fStatus; }
102 
103 			DoublyLinkedListLink<IORequestChunk>*
104 									ListLink()	{ return &fListLink; }
105 
106 protected:
107 			void				SetStatus(status_t status)
108 									{ fStatus = status; }
109 			void				ResetStatus()
110 									{ fStatus = 1; }
111 
112 protected:
113 			IORequest*			fParent;
114 			status_t			fStatus;
115 
116 public:
117 			DoublyLinkedListLink<IORequestChunk> fListLink;
118 };
119 
120 typedef DoublyLinkedList<IORequestChunk,
121 	DoublyLinkedListMemberGetLink<IORequestChunk, &IORequestChunk::fListLink> >
122 		IORequestChunkList;
123 
124 
125 struct IOOperation : IORequestChunk, DoublyLinkedListLinkImpl<IOOperation> {
126 public:
127 			bool				Finish();
128 									// returns true, if it can be recycled
129 
130 			status_t			Prepare(IORequest* request);
131 			void				SetOriginalRange(off_t offset,
132 									generic_size_t length);
133 									// also sets range
134 			void				SetRange(off_t offset, generic_size_t length);
135 
136 			void				SetStatus(status_t status)
137 									{ IORequestChunk::SetStatus(status); }
138 
139 			off_t				Offset() const;
140 			generic_size_t		Length() const;
141 			off_t				OriginalOffset() const
142 									{ return fOriginalOffset; }
143 			generic_size_t		OriginalLength() const
144 									{ return fOriginalLength; }
145 
146 			generic_size_t		TransferredBytes() const
147 									{ return fTransferredBytes; }
148 			void				SetTransferredBytes(generic_size_t bytes)
149 									{ fTransferredBytes = bytes; }
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 status_t (*io_request_finished_callback)(void* data,
203 			io_request* request, status_t status, bool partialTransfer,
204 			generic_size_t transferEndOffset);
205 			// TODO: Return type: status_t -> void
206 typedef status_t (*io_request_iterate_callback)(void* data,
207 			io_request* request, bool* _partialTransfer);
208 
209 
210 struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl<IORequest> {
211 								IORequest();
212 	virtual						~IORequest();
213 
214 	static	IORequest*			Create(bool vip);
215 
216 			status_t			Init(off_t offset, generic_addr_t buffer,
217 									generic_size_t length, bool write,
218 									uint32 flags);
219 			status_t			Init(off_t offset, const generic_io_vec* vecs,
220 									size_t count, generic_size_t length,
221 									bool write, uint32 flags)
222 									{ return Init(offset, 0, vecs, count,
223 										length, write, flags); }
224 			status_t			Init(off_t offset,
225 									generic_size_t firstVecOffset,
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 									status_t status, bool partialTransfer,
259 									generic_size_t transferEndOffset);
260 			void				SubRequestFinished(IORequest* request,
261 									status_t status, bool partialTransfer,
262 									generic_size_t transferEndOffset);
263 			void				SetUnfinished();
264 
265 			generic_size_t		RemainingBytes() const
266 									{ return fRemainingBytes; }
267 			generic_size_t		TransferredBytes() const
268 									{ return fTransferSize; }
269 			bool				IsPartialTransfer() const
270 									{ return fPartialTransfer; }
271 			void				SetTransferredBytes(bool partialTransfer,
272 									generic_size_t transferredBytes);
273 
274 			void				SetSuppressChildNotifications(bool suppress);
275 			bool				SuppressChildNotifications() const
276 									{ return fSuppressChildNotifications; }
277 
278 			bool				IsWrite() const	{ return fIsWrite; }
279 			bool				IsRead() const	{ return !fIsWrite; }
280 			team_id				TeamID() const		{ return fTeam; }
281 			thread_id			ThreadID() const	{ return fThread; }
282 			uint32				Flags() const	{ return fFlags; }
283 
284 			IOBuffer*			Buffer() const	{ return fBuffer; }
285 			off_t				Offset() const	{ return fOffset; }
286 			generic_size_t		Length() const	{ return fLength; }
287 
288 			void				SetOffset(off_t offset)	{ fOffset = offset; }
289 
290 			uint32				VecIndex() const	{ return fVecIndex; }
291 			generic_size_t		VecOffset() const	{ return fVecOffset; }
292 
293 			void				Advance(generic_size_t bySize);
294 
295 			IORequest*			FirstSubRequest();
296 			IORequest*			NextSubRequest(IORequest* previous);
297 
298 			void				AddOperation(IOOperation* operation);
299 			void				RemoveOperation(IOOperation* operation);
300 
301 			status_t			CopyData(off_t offset, void* buffer,
302 									size_t size);
303 			status_t			CopyData(const void* buffer, off_t offset,
304 									size_t size);
305 			status_t			ClearData(off_t offset, generic_size_t size);
306 
307 			void				Dump() const;
308 
309 private:
310 			status_t			_CopyData(void* buffer, off_t offset,
311 									size_t size, bool copyIn);
312 	static	status_t			_CopySimple(void* bounceBuffer,
313 									generic_addr_t external, size_t size,
314 									team_id team, bool copyIn);
315 	static	status_t			_CopyPhysical(void* bounceBuffer,
316 									generic_addr_t external, size_t size,
317 									team_id team, bool copyIn);
318 	static	status_t			_CopyUser(void* bounceBuffer,
319 									generic_addr_t external, size_t size,
320 									team_id team, bool copyIn);
321 	static	status_t			_ClearDataSimple(generic_addr_t external,
322 									generic_size_t size, team_id team);
323 	static	status_t			_ClearDataPhysical(generic_addr_t external,
324 									generic_size_t size, team_id team);
325 	static	status_t			_ClearDataUser(generic_addr_t external,
326 									generic_size_t size, team_id team);
327 
328 			mutex				fLock;
329 			IORequestOwner*		fOwner;
330 			IOBuffer*			fBuffer;
331 			off_t				fOffset;
332 			generic_size_t		fLength;
333 			generic_size_t		fTransferSize;
334 									// After all subrequests/operations have
335 									// finished, number of contiguous bytes at
336 									// the beginning of the request that have
337 									// actually been transferred.
338 			generic_size_t		fRelativeParentOffset;
339 									// offset of this request relative to its
340 									// parent
341 			IORequestChunkList	fChildren;
342 			int32				fPendingChildren;
343 			uint32				fFlags;
344 			team_id				fTeam;
345 			thread_id			fThread;
346 			bool				fIsWrite;
347 			bool				fPartialTransfer;
348 			bool				fSuppressChildNotifications;
349 			bool				fIsNotified;
350 
351 			io_request_finished_callback	fFinishedCallback;
352 			void*				fFinishedCookie;
353 			io_request_iterate_callback	fIterationCallback;
354 			void*				fIterationCookie;
355 			ConditionVariable	fFinishedCondition;
356 
357 			// these are for iteration
358 			uint32				fVecIndex;
359 			generic_size_t		fVecOffset;
360 			generic_size_t		fRemainingBytes;
361 };
362 
363 
364 typedef DoublyLinkedList<IORequest> IORequestList;
365 
366 
367 #endif	// IO_REQUEST_H
368