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