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