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