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 IsVirtual()38 bool IsVirtual() const { return !fPhysical; } IsPhysical()39 bool IsPhysical() const { return fPhysical; } IsUser()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 SetPhysical(bool physical)47 void SetPhysical(bool physical) 48 { fPhysical = physical; } SetUser(bool user)49 void SetUser(bool user) { fUser = user; } SetLength(generic_size_t length)50 void SetLength(generic_size_t length) 51 { fLength = length; } SetVecCount(uint32 count)52 void SetVecCount(uint32 count) { fVecCount = count; } 53 Length()54 generic_size_t Length() const { return fLength; } 55 Vecs()56 generic_io_vec* Vecs() { return fVecs; } VecAt(size_t index)57 generic_io_vec& VecAt(size_t index) { return fVecs[index]; } VecCount()58 size_t VecCount() const { return fVecCount; } Capacity()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); IsMemoryLocked()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 Parent()98 IORequest* Parent() const { return fParent; } SetParent(IORequest * parent)99 void SetParent(IORequest* parent) 100 { fParent = parent; } 101 Status()102 status_t Status() const { return fStatus; } 103 104 DoublyLinkedListLink<IORequestChunk>* ListLink()105 ListLink() { return &fListLink; } 106 107 protected: SetStatus(status_t status)108 void SetStatus(status_t status) 109 { fStatus = status; } ResetStatus()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 OriginalOffsetIOOperation143 off_t OriginalOffset() const 144 { return fOriginalOffset; } OriginalLengthIOOperation145 generic_size_t OriginalLength() const 146 { return fOriginalLength; } 147 TransferredBytesIOOperation148 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); HasPartialBeginIOOperation155 bool HasPartialBegin() const 156 { return fPartialBegin; } HasPartialEndIOOperation157 bool HasPartialEnd() const 158 { return fPartialEnd; } 159 bool IsWrite() const; 160 bool IsRead() const; 161 SetBlockSizeIOOperation162 void SetBlockSize(generic_size_t blockSize) 163 { fBlockSize = blockSize; } 164 UsesBounceBufferIOOperation165 bool UsesBounceBuffer() const 166 { return fUsesBounceBuffer; } SetUsesBounceBufferIOOperation167 void SetUsesBounceBuffer(bool uses) 168 { fUsesBounceBuffer = uses; } 169 BufferIOOperation170 DMABuffer* Buffer() const { return fDMABuffer; } SetBufferIOOperation171 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); InitIORequest218 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 SetOwnerIORequest230 void SetOwner(IORequestOwner* owner) 231 { fOwner = owner; } OwnerIORequest232 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 IsFinishedIORequest250 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 RemainingBytesIORequest263 generic_size_t RemainingBytes() const 264 { return fRemainingBytes; } TransferredBytesIORequest265 generic_size_t TransferredBytes() const 266 { return fTransferSize; } IsPartialTransferIORequest267 bool IsPartialTransfer() const 268 { return fPartialTransfer; } 269 void SetTransferredBytes(bool partialTransfer, 270 generic_size_t transferredBytes); 271 272 void SetSuppressChildNotifications(bool suppress); SuppressChildNotificationsIORequest273 bool SuppressChildNotifications() const 274 { return fSuppressChildNotifications; } 275 IsWriteIORequest276 bool IsWrite() const { return fIsWrite; } IsReadIORequest277 bool IsRead() const { return !fIsWrite; } TeamIDIORequest278 team_id TeamID() const { return fTeam; } ThreadIDIORequest279 thread_id ThreadID() const { return fThread; } FlagsIORequest280 uint32 Flags() const { return fFlags; } 281 BufferIORequest282 IOBuffer* Buffer() const { return fBuffer; } OffsetIORequest283 off_t Offset() const { return fOffset; } LengthIORequest284 generic_size_t Length() const { return fLength; } 285 SetOffsetIORequest286 void SetOffset(off_t offset) { fOffset = offset; } 287 VecIndexIORequest288 uint32 VecIndex() const { return fVecIndex; } VecOffsetIORequest289 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