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