/* * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #ifndef IO_REQUEST_H #define IO_REQUEST_H #include #include #include #include #include #include #include "dma_resources.h" #define B_PHYSICAL_IO_REQUEST 0x01 /* buffer points to physical memory */ #define B_VIP_IO_REQUEST 0x02 /* used by the page writer -- make sure allocations won't fail */ #define B_DELETE_IO_REQUEST 0x04 /* delete request when finished */ class DMABuffer; struct IOOperation; typedef struct IOOperation io_operation; class IOBuffer : public DoublyLinkedListLinkImpl { public: static IOBuffer* Create(uint32 count, bool vip); void Delete(); bool IsVirtual() const { return !fPhysical; } bool IsPhysical() const { return fPhysical; } bool IsUser() const { return fUser; } void SetVecs(generic_size_t firstVecOffset, generic_size_t lastVecSize, const generic_io_vec* vecs, uint32 count, generic_size_t length, uint32 flags); void SetPhysical(bool physical) { fPhysical = physical; } void SetUser(bool user) { fUser = user; } void SetLength(generic_size_t length) { fLength = length; } void SetVecCount(uint32 count) { fVecCount = count; } generic_size_t Length() const { return fLength; } generic_io_vec* Vecs() { return fVecs; } generic_io_vec& VecAt(size_t index) { return fVecs[index]; } size_t VecCount() const { return fVecCount; } size_t Capacity() const { return fCapacity; } status_t GetNextVirtualVec(void*& cookie, iovec& vector); void FreeVirtualVecCookie(void* cookie); status_t LockMemory(team_id team, bool isWrite); void UnlockMemory(team_id team, bool isWrite); bool IsMemoryLocked() const { return fMemoryLocked; } void Dump() const; private: IOBuffer(); ~IOBuffer(); // not implemented void _UnlockMemory(team_id team, size_t count, bool isWrite); bool fUser; bool fPhysical; bool fVIP; bool fMemoryLocked; generic_size_t fLength; size_t fVecCount; size_t fCapacity; generic_io_vec fVecs[1]; }; struct IORequest; struct IORequestOwner; class IORequestChunk { public: IORequestChunk(); virtual ~IORequestChunk(); IORequest* Parent() const { return fParent; } void SetParent(IORequest* parent) { fParent = parent; } status_t Status() const { return fStatus; } DoublyLinkedListLink* ListLink() { return &fListLink; } protected: void SetStatus(status_t status) { fStatus = status; } void ResetStatus() { fStatus = 1; } protected: IORequest* fParent; status_t fStatus; public: DoublyLinkedListLink fListLink; }; typedef DoublyLinkedList > IORequestChunkList; struct IOOperation : IORequestChunk, DoublyLinkedListLinkImpl { public: bool Finish(); // returns true, if it can be recycled // otherwise, there is more to be done void SetStatus(status_t status, generic_size_t completedLength); status_t Prepare(IORequest* request); void SetOriginalRange(off_t offset, generic_size_t length); // also sets range void SetRange(off_t offset, generic_size_t length); off_t Offset() const; generic_size_t Length() const; off_t OriginalOffset() const { return fOriginalOffset; } generic_size_t OriginalLength() const { return fOriginalLength; } generic_size_t TransferredBytes() const { return fTransferredBytes; } generic_io_vec* Vecs() const; uint32 VecCount() const; void SetPartial(bool partialBegin, bool partialEnd); bool HasPartialBegin() const { return fPartialBegin; } bool HasPartialEnd() const { return fPartialEnd; } bool IsWrite() const; bool IsRead() const; void SetBlockSize(generic_size_t blockSize) { fBlockSize = blockSize; } bool UsesBounceBuffer() const { return fUsesBounceBuffer; } void SetUsesBounceBuffer(bool uses) { fUsesBounceBuffer = uses; } DMABuffer* Buffer() const { return fDMABuffer; } void SetBuffer(DMABuffer* buffer) { fDMABuffer = buffer; } void Dump() const; protected: void _PrepareVecs(); status_t _CopyPartialBegin(bool isWrite, bool& partialBlockOnly); status_t _CopyPartialEnd(bool isWrite); DMABuffer* fDMABuffer; off_t fOffset; off_t fOriginalOffset; generic_size_t fLength; generic_size_t fOriginalLength; generic_size_t fTransferredBytes; generic_size_t fBlockSize; uint16 fSavedVecIndex; uint16 fSavedVecLength; uint8 fPhase; bool fPartialBegin; bool fPartialEnd; bool fUsesBounceBuffer; }; typedef IOOperation io_operation; typedef DoublyLinkedList IOOperationList; typedef struct IORequest io_request; typedef status_t (*io_request_finished_callback)(void* data, io_request* request, status_t status, bool partialTransfer, generic_size_t transferEndOffset); // TODO: Return type: status_t -> void typedef status_t (*io_request_iterate_callback)(void* data, io_request* request, bool* _partialTransfer); struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl { IORequest(); virtual ~IORequest(); static IORequest* Create(bool vip); status_t Init(off_t offset, generic_addr_t buffer, generic_size_t length, bool write, uint32 flags); status_t Init(off_t offset, const generic_io_vec* vecs, size_t count, generic_size_t length, bool write, uint32 flags) { return Init(offset, 0, 0, vecs, count, length, write, flags); } status_t Init(off_t offset, generic_size_t firstVecOffset, generic_size_t lastVecSize, const generic_io_vec* vecs, size_t count, generic_size_t length, bool write, uint32 flags); void SetOwner(IORequestOwner* owner) { fOwner = owner; } IORequestOwner* Owner() const { return fOwner; } status_t CreateSubRequest(off_t parentOffset, off_t offset, generic_size_t length, IORequest*& subRequest); void DeleteSubRequests(); void SetFinishedCallback( io_request_finished_callback callback, void* cookie); void SetIterationCallback( io_request_iterate_callback callback, void* cookie); io_request_finished_callback FinishedCallback( void** _cookie = NULL) const; status_t Wait(uint32 flags = 0, bigtime_t timeout = 0); bool IsFinished() const { return fStatus != 1 && fPendingChildren == 0; } void NotifyFinished(); bool HasCallbacks() const; void SetStatusAndNotify(status_t status); void OperationFinished(IOOperation* operation); void SubRequestFinished(IORequest* request, status_t status, bool partialTransfer, generic_size_t transferEndOffset); void SetUnfinished(); generic_size_t RemainingBytes() const { return fRemainingBytes; } generic_size_t TransferredBytes() const { return fTransferSize; } bool IsPartialTransfer() const { return fPartialTransfer; } void SetTransferredBytes(bool partialTransfer, generic_size_t transferredBytes); void SetSuppressChildNotifications(bool suppress); bool SuppressChildNotifications() const { return fSuppressChildNotifications; } bool IsWrite() const { return fIsWrite; } bool IsRead() const { return !fIsWrite; } team_id TeamID() const { return fTeam; } thread_id ThreadID() const { return fThread; } uint32 Flags() const { return fFlags; } IOBuffer* Buffer() const { return fBuffer; } off_t Offset() const { return fOffset; } generic_size_t Length() const { return fLength; } void SetOffset(off_t offset) { fOffset = offset; } uint32 VecIndex() const { return fVecIndex; } generic_size_t VecOffset() const { return fVecOffset; } void Advance(generic_size_t bySize); IORequest* FirstSubRequest(); IORequest* NextSubRequest(IORequest* previous); void AddOperation(IOOperation* operation); void RemoveOperation(IOOperation* operation); status_t CopyData(off_t offset, void* buffer, size_t size); status_t CopyData(const void* buffer, off_t offset, size_t size); status_t ClearData(off_t offset, generic_size_t size); void Dump() const; private: status_t _CopyData(void* buffer, off_t offset, size_t size, bool copyIn); static status_t _CopySimple(void* bounceBuffer, generic_addr_t external, size_t size, team_id team, bool copyIn); static status_t _CopyPhysical(void* bounceBuffer, generic_addr_t external, size_t size, team_id team, bool copyIn); static status_t _CopyUser(void* bounceBuffer, generic_addr_t external, size_t size, team_id team, bool copyIn); static status_t _ClearDataSimple(generic_addr_t external, generic_size_t size, team_id team); static status_t _ClearDataPhysical(generic_addr_t external, generic_size_t size, team_id team); static status_t _ClearDataUser(generic_addr_t external, generic_size_t size, team_id team); mutex fLock; IORequestOwner* fOwner; IOBuffer* fBuffer; off_t fOffset; generic_size_t fLength; generic_size_t fTransferSize; // After all subrequests/operations have // finished, number of contiguous bytes at // the beginning of the request that have // actually been transferred. generic_size_t fRelativeParentOffset; // offset of this request relative to its // parent IORequestChunkList fChildren; int32 fPendingChildren; uint32 fFlags; team_id fTeam; thread_id fThread; bool fIsWrite; bool fPartialTransfer; bool fSuppressChildNotifications; bool fIsNotified; io_request_finished_callback fFinishedCallback; void* fFinishedCookie; io_request_iterate_callback fIterationCallback; void* fIterationCookie; ConditionVariable fFinishedCondition; // these are for iteration uint32 fVecIndex; generic_size_t fVecOffset; generic_size_t fRemainingBytes; }; typedef DoublyLinkedList IORequestList; #endif // IO_REQUEST_H