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 struct 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 const generic_io_vec* vecs, uint32 count, 44 generic_size_t length, uint32 flags); 45 46 void SetPhysical(bool physical) 47 { fPhysical = physical; } 48 void SetUser(bool user) { fUser = user; } 49 void SetLength(generic_size_t length) 50 { fLength = length; } 51 void SetVecCount(uint32 count) { fVecCount = count; } 52 53 generic_size_t Length() const { return fLength; } 54 55 generic_io_vec* Vecs() { return fVecs; } 56 generic_io_vec& VecAt(size_t index) { return fVecs[index]; } 57 size_t VecCount() const { return fVecCount; } 58 size_t Capacity() const { return fCapacity; } 59 60 status_t GetNextVirtualVec(void*& cookie, iovec& vector); 61 void FreeVirtualVecCookie(void* cookie); 62 63 status_t LockMemory(team_id team, bool isWrite); 64 void UnlockMemory(team_id team, bool isWrite); 65 bool IsMemoryLocked() const 66 { return fMemoryLocked; } 67 68 void Dump() const; 69 70 private: 71 IOBuffer(); 72 ~IOBuffer(); 73 // not implemented 74 void _UnlockMemory(team_id team, size_t count, 75 bool isWrite); 76 77 bool fUser; 78 bool fPhysical; 79 bool fVIP; 80 bool fMemoryLocked; 81 generic_size_t fLength; 82 size_t fVecCount; 83 size_t fCapacity; 84 generic_io_vec fVecs[1]; 85 }; 86 87 88 class IORequest; 89 class IORequestOwner; 90 91 92 class IORequestChunk { 93 public: 94 IORequestChunk(); 95 virtual ~IORequestChunk(); 96 97 IORequest* Parent() const { return fParent; } 98 void SetParent(IORequest* parent) 99 { fParent = parent; } 100 101 status_t Status() const { return fStatus; } 102 103 DoublyLinkedListLink<IORequestChunk>* 104 ListLink() { return &fListLink; } 105 106 protected: 107 void SetStatus(status_t status) 108 { fStatus = status; } 109 void ResetStatus() 110 { fStatus = 1; } 111 112 protected: 113 IORequest* fParent; 114 status_t fStatus; 115 116 public: 117 DoublyLinkedListLink<IORequestChunk> fListLink; 118 }; 119 120 typedef DoublyLinkedList<IORequestChunk, 121 DoublyLinkedListMemberGetLink<IORequestChunk, &IORequestChunk::fListLink> > 122 IORequestChunkList; 123 124 125 struct IOOperation : IORequestChunk, DoublyLinkedListLinkImpl<IOOperation> { 126 public: 127 bool Finish(); 128 // returns true, if it can be recycled 129 130 status_t Prepare(IORequest* request); 131 void SetOriginalRange(off_t offset, 132 generic_size_t length); 133 // also sets range 134 void SetRange(off_t offset, generic_size_t length); 135 136 void SetStatus(status_t status) 137 { IORequestChunk::SetStatus(status); } 138 139 off_t Offset() const; 140 generic_size_t Length() const; 141 off_t OriginalOffset() const 142 { return fOriginalOffset; } 143 generic_size_t OriginalLength() const 144 { return fOriginalLength; } 145 146 generic_size_t TransferredBytes() const 147 { return fTransferredBytes; } 148 void SetTransferredBytes(generic_size_t bytes) 149 { fTransferredBytes = bytes; } 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, vecs, count, 223 length, write, flags); } 224 status_t Init(off_t offset, 225 generic_size_t firstVecOffset, 226 const generic_io_vec* vecs, size_t count, 227 generic_size_t length, bool write, 228 uint32 flags); 229 230 void SetOwner(IORequestOwner* owner) 231 { fOwner = owner; } 232 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 250 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 status_t status, bool partialTransfer, 259 generic_size_t transferEndOffset); 260 void SubRequestFinished(IORequest* request, 261 status_t status, bool partialTransfer, 262 generic_size_t transferEndOffset); 263 void SetUnfinished(); 264 265 generic_size_t RemainingBytes() const 266 { return fRemainingBytes; } 267 generic_size_t TransferredBytes() const 268 { return fTransferSize; } 269 bool IsPartialTransfer() const 270 { return fPartialTransfer; } 271 void SetTransferredBytes(bool partialTransfer, 272 generic_size_t transferredBytes); 273 274 void SetSuppressChildNotifications(bool suppress); 275 bool SuppressChildNotifications() const 276 { return fSuppressChildNotifications; } 277 278 bool IsWrite() const { return fIsWrite; } 279 bool IsRead() const { return !fIsWrite; } 280 team_id TeamID() const { return fTeam; } 281 thread_id ThreadID() const { return fThread; } 282 uint32 Flags() const { return fFlags; } 283 284 IOBuffer* Buffer() const { return fBuffer; } 285 off_t Offset() const { return fOffset; } 286 generic_size_t Length() const { return fLength; } 287 288 void SetOffset(off_t offset) { fOffset = offset; } 289 290 uint32 VecIndex() const { return fVecIndex; } 291 generic_size_t VecOffset() const { return fVecOffset; } 292 293 void Advance(generic_size_t bySize); 294 295 IORequest* FirstSubRequest(); 296 IORequest* NextSubRequest(IORequest* previous); 297 298 void AddOperation(IOOperation* operation); 299 void RemoveOperation(IOOperation* operation); 300 301 status_t CopyData(off_t offset, void* buffer, 302 size_t size); 303 status_t CopyData(const void* buffer, off_t offset, 304 size_t size); 305 status_t ClearData(off_t offset, generic_size_t size); 306 307 void Dump() const; 308 309 private: 310 status_t _CopyData(void* buffer, off_t offset, 311 size_t size, bool copyIn); 312 static status_t _CopySimple(void* bounceBuffer, 313 generic_addr_t external, size_t size, 314 team_id team, bool copyIn); 315 static status_t _CopyPhysical(void* bounceBuffer, 316 generic_addr_t external, size_t size, 317 team_id team, bool copyIn); 318 static status_t _CopyUser(void* bounceBuffer, 319 generic_addr_t external, size_t size, 320 team_id team, bool copyIn); 321 static status_t _ClearDataSimple(generic_addr_t external, 322 generic_size_t size, team_id team); 323 static status_t _ClearDataPhysical(generic_addr_t external, 324 generic_size_t size, team_id team); 325 static status_t _ClearDataUser(generic_addr_t external, 326 generic_size_t size, team_id team); 327 328 mutex fLock; 329 IORequestOwner* fOwner; 330 IOBuffer* fBuffer; 331 off_t fOffset; 332 generic_size_t fLength; 333 generic_size_t fTransferSize; 334 // After all subrequests/operations have 335 // finished, number of contiguous bytes at 336 // the beginning of the request that have 337 // actually been transferred. 338 generic_size_t fRelativeParentOffset; 339 // offset of this request relative to its 340 // parent 341 IORequestChunkList fChildren; 342 int32 fPendingChildren; 343 uint32 fFlags; 344 team_id fTeam; 345 thread_id fThread; 346 bool fIsWrite; 347 bool fPartialTransfer; 348 bool fSuppressChildNotifications; 349 bool fIsNotified; 350 351 io_request_finished_callback fFinishedCallback; 352 void* fFinishedCookie; 353 io_request_iterate_callback fIterationCallback; 354 void* fIterationCookie; 355 ConditionVariable fFinishedCondition; 356 357 // these are for iteration 358 uint32 fVecIndex; 359 generic_size_t fVecOffset; 360 generic_size_t fRemainingBytes; 361 }; 362 363 364 typedef DoublyLinkedList<IORequest> IORequestList; 365 366 367 #endif // IO_REQUEST_H 368