xref: /haiku/src/system/kernel/device_manager/IORequest.h (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 
131 			status_t			Prepare(IORequest* request);
132 			void				SetOriginalRange(off_t offset,
133 									generic_size_t length);
134 									// also sets range
135 			void				SetRange(off_t offset, generic_size_t length);
136 
137 			void				SetStatus(status_t status)
138 									{ IORequestChunk::SetStatus(status); }
139 
140 			off_t				Offset() const;
141 			generic_size_t		Length() const;
142 			off_t				OriginalOffset() const
143 									{ return fOriginalOffset; }
144 			generic_size_t		OriginalLength() const
145 									{ return fOriginalLength; }
146 
147 			generic_size_t		TransferredBytes() const
148 									{ return fTransferredBytes; }
149 			void				SetTransferredBytes(generic_size_t bytes)
150 									{ fTransferredBytes = bytes; }
151 
152 			generic_io_vec*		Vecs() const;
153 			uint32				VecCount() const;
154 
155 			void				SetPartial(bool partialBegin, bool partialEnd);
156 			bool				HasPartialBegin() const
157 									{ return fPartialBegin; }
158 			bool				HasPartialEnd() const
159 									{ return fPartialEnd; }
160 			bool				IsWrite() const;
161 			bool				IsRead() const;
162 
163 			void				SetBlockSize(generic_size_t blockSize)
164 									{ fBlockSize  = blockSize; }
165 
166 			bool				UsesBounceBuffer() const
167 									{ return fUsesBounceBuffer; }
168 			void				SetUsesBounceBuffer(bool uses)
169 									{ fUsesBounceBuffer = uses; }
170 
171 			DMABuffer*			Buffer() const { return fDMABuffer; }
172 			void				SetBuffer(DMABuffer* buffer)
173 									{ fDMABuffer = buffer; }
174 
175 			void				Dump() const;
176 
177 protected:
178 			void				_PrepareVecs();
179 			status_t			_CopyPartialBegin(bool isWrite,
180 									bool& partialBlockOnly);
181 			status_t			_CopyPartialEnd(bool isWrite);
182 
183 			DMABuffer*			fDMABuffer;
184 			off_t				fOffset;
185 			off_t				fOriginalOffset;
186 			generic_size_t		fLength;
187 			generic_size_t		fOriginalLength;
188 			generic_size_t		fTransferredBytes;
189 			generic_size_t		fBlockSize;
190 			uint16				fSavedVecIndex;
191 			uint16				fSavedVecLength;
192 			uint8				fPhase;
193 			bool				fPartialBegin;
194 			bool				fPartialEnd;
195 			bool				fUsesBounceBuffer;
196 };
197 
198 
199 typedef IOOperation io_operation;
200 typedef DoublyLinkedList<IOOperation> IOOperationList;
201 
202 typedef struct IORequest io_request;
203 typedef status_t (*io_request_finished_callback)(void* data,
204 			io_request* request, status_t status, bool partialTransfer,
205 			generic_size_t transferEndOffset);
206 			// TODO: Return type: status_t -> void
207 typedef status_t (*io_request_iterate_callback)(void* data,
208 			io_request* request, bool* _partialTransfer);
209 
210 
211 struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl<IORequest> {
212 								IORequest();
213 	virtual						~IORequest();
214 
215 	static	IORequest*			Create(bool vip);
216 
217 			status_t			Init(off_t offset, generic_addr_t buffer,
218 									generic_size_t length, bool write,
219 									uint32 flags);
220 			status_t			Init(off_t offset, const generic_io_vec* vecs,
221 									size_t count, generic_size_t length,
222 									bool write, uint32 flags)
223 									{ return Init(offset, 0, 0, vecs, count,
224 										length, write, flags); }
225 			status_t			Init(off_t offset,
226 									generic_size_t firstVecOffset,
227 									generic_size_t lastVecSize,
228 									const generic_io_vec* vecs, size_t count,
229 									generic_size_t length, bool write,
230 									uint32 flags);
231 
232 			void				SetOwner(IORequestOwner* owner)
233 									{ fOwner = owner; }
234 			IORequestOwner*		Owner() const	{ return fOwner; }
235 
236 			status_t			CreateSubRequest(off_t parentOffset,
237 									off_t offset, generic_size_t length,
238 									IORequest*& subRequest);
239 			void				DeleteSubRequests();
240 
241 			void				SetFinishedCallback(
242 									io_request_finished_callback callback,
243 									void* cookie);
244 			void				SetIterationCallback(
245 									io_request_iterate_callback callback,
246 									void* cookie);
247 			io_request_finished_callback FinishedCallback(
248 									void** _cookie = NULL) const;
249 
250 			status_t			Wait(uint32 flags = 0, bigtime_t timeout = 0);
251 
252 			bool				IsFinished() const
253 									{ return fStatus != 1
254 										&& fPendingChildren == 0; }
255 			void				NotifyFinished();
256 			bool				HasCallbacks() const;
257 			void				SetStatusAndNotify(status_t status);
258 
259 			void				OperationFinished(IOOperation* operation,
260 									status_t status, bool partialTransfer,
261 									generic_size_t transferEndOffset);
262 			void				SubRequestFinished(IORequest* request,
263 									status_t status, bool partialTransfer,
264 									generic_size_t transferEndOffset);
265 			void				SetUnfinished();
266 
267 			generic_size_t		RemainingBytes() const
268 									{ return fRemainingBytes; }
269 			generic_size_t		TransferredBytes() const
270 									{ return fTransferSize; }
271 			bool				IsPartialTransfer() const
272 									{ return fPartialTransfer; }
273 			void				SetTransferredBytes(bool partialTransfer,
274 									generic_size_t transferredBytes);
275 
276 			void				SetSuppressChildNotifications(bool suppress);
277 			bool				SuppressChildNotifications() const
278 									{ return fSuppressChildNotifications; }
279 
280 			bool				IsWrite() const	{ return fIsWrite; }
281 			bool				IsRead() const	{ return !fIsWrite; }
282 			team_id				TeamID() const		{ return fTeam; }
283 			thread_id			ThreadID() const	{ return fThread; }
284 			uint32				Flags() const	{ return fFlags; }
285 
286 			IOBuffer*			Buffer() const	{ return fBuffer; }
287 			off_t				Offset() const	{ return fOffset; }
288 			generic_size_t		Length() const	{ return fLength; }
289 
290 			void				SetOffset(off_t offset)	{ fOffset = offset; }
291 
292 			uint32				VecIndex() const	{ return fVecIndex; }
293 			generic_size_t		VecOffset() const	{ return fVecOffset; }
294 
295 			void				Advance(generic_size_t bySize);
296 
297 			IORequest*			FirstSubRequest();
298 			IORequest*			NextSubRequest(IORequest* previous);
299 
300 			void				AddOperation(IOOperation* operation);
301 			void				RemoveOperation(IOOperation* operation);
302 
303 			status_t			CopyData(off_t offset, void* buffer,
304 									size_t size);
305 			status_t			CopyData(const void* buffer, off_t offset,
306 									size_t size);
307 			status_t			ClearData(off_t offset, generic_size_t size);
308 
309 			void				Dump() const;
310 
311 private:
312 			status_t			_CopyData(void* buffer, off_t offset,
313 									size_t size, bool copyIn);
314 	static	status_t			_CopySimple(void* bounceBuffer,
315 									generic_addr_t external, size_t size,
316 									team_id team, bool copyIn);
317 	static	status_t			_CopyPhysical(void* bounceBuffer,
318 									generic_addr_t external, size_t size,
319 									team_id team, bool copyIn);
320 	static	status_t			_CopyUser(void* bounceBuffer,
321 									generic_addr_t external, size_t size,
322 									team_id team, bool copyIn);
323 	static	status_t			_ClearDataSimple(generic_addr_t external,
324 									generic_size_t size, team_id team);
325 	static	status_t			_ClearDataPhysical(generic_addr_t external,
326 									generic_size_t size, team_id team);
327 	static	status_t			_ClearDataUser(generic_addr_t external,
328 									generic_size_t size, team_id team);
329 
330 			mutex				fLock;
331 			IORequestOwner*		fOwner;
332 			IOBuffer*			fBuffer;
333 			off_t				fOffset;
334 			generic_size_t		fLength;
335 			generic_size_t		fTransferSize;
336 									// After all subrequests/operations have
337 									// finished, number of contiguous bytes at
338 									// the beginning of the request that have
339 									// actually been transferred.
340 			generic_size_t		fRelativeParentOffset;
341 									// offset of this request relative to its
342 									// parent
343 			IORequestChunkList	fChildren;
344 			int32				fPendingChildren;
345 			uint32				fFlags;
346 			team_id				fTeam;
347 			thread_id			fThread;
348 			bool				fIsWrite;
349 			bool				fPartialTransfer;
350 			bool				fSuppressChildNotifications;
351 			bool				fIsNotified;
352 
353 			io_request_finished_callback	fFinishedCallback;
354 			void*				fFinishedCookie;
355 			io_request_iterate_callback	fIterationCallback;
356 			void*				fIterationCookie;
357 			ConditionVariable	fFinishedCondition;
358 
359 			// these are for iteration
360 			uint32				fVecIndex;
361 			generic_size_t		fVecOffset;
362 			generic_size_t		fRemainingBytes;
363 };
364 
365 
366 typedef DoublyLinkedList<IORequest> IORequestList;
367 
368 
369 #endif	// IO_REQUEST_H
370