* Added parameter "size_t firstVecOffset" to IOBuffer::SetVecs() and
added an IORequest::Init() version with that parameter. This makes splitting an iovec array into IOBuffers/IORequests easier. * Added IORequest::CreateSubRequest(). It creates and adds an IORequest that covers a part of the range of the parent request, but may use another file offset. This will be used e.g. in the way that the parent request describes an I/O operation for a file while its subrequests describe the same operation translated to the underlying device. * Added IORequest::DeleteSubRequests(), which does the obvious. It's also invoked in the destructor. * Added method for iterating through subrequests. * Made IORequestChunk::{Set,Reset}Status() protected. For both subclasses some locking is needed (though different locking), so we rather make this more explicit. * Added IORequest::SetStatusAndNotify(), which is SetStatus() + NotifyFinished() with proper locking. * Changed the I/O request finished and iteration callback signatures. The finished callback has got an additional "status" argument, since the request itself may already be inaccessible at the time the callback is executed. * Changed IORequest::NotifyFinished(). The policy is now that if the iteration callback fails, the method will do the finished notifications. This simplifies things in the iteration callbacks. * Fixed bug in IORequest::_CopyPhysical(): It didn't take into account that the physical buffer could not be page aligned. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26654 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
9e637dd94b
commit
09f0e0ec68
@ -66,9 +66,15 @@ IOBuffer::Create(size_t count)
|
||||
|
||||
|
||||
void
|
||||
IOBuffer::SetVecs(const iovec* vecs, uint32 count, size_t length, uint32 flags)
|
||||
IOBuffer::SetVecs(size_t firstVecOffset, const iovec* vecs, uint32 count,
|
||||
size_t length, uint32 flags)
|
||||
{
|
||||
memcpy(fVecs, vecs, sizeof(iovec) * count);
|
||||
if (count > 0 && firstVecOffset > 0) {
|
||||
fVecs[0].iov_base = (uint8*)fVecs[0].iov_base + firstVecOffset;
|
||||
fVecs[0].iov_len -= firstVecOffset;
|
||||
}
|
||||
|
||||
fVecCount = count;
|
||||
fLength = length;
|
||||
fUser = IS_USER_ADDRESS(vecs[0].iov_base);
|
||||
@ -499,6 +505,7 @@ IORequest::IORequest()
|
||||
IORequest::~IORequest()
|
||||
{
|
||||
mutex_lock(&fLock);
|
||||
DeleteSubRequests();
|
||||
mutex_destroy(&fLock);
|
||||
}
|
||||
|
||||
@ -515,14 +522,14 @@ IORequest::Init(off_t offset, void* buffer, size_t length, bool write,
|
||||
|
||||
|
||||
status_t
|
||||
IORequest::Init(off_t offset, iovec* vecs, size_t count, size_t length,
|
||||
bool write, uint32 flags)
|
||||
IORequest::Init(off_t offset, size_t firstVecOffset, iovec* vecs, size_t count,
|
||||
size_t length, bool write, uint32 flags)
|
||||
{
|
||||
fBuffer = IOBuffer::Create(count);
|
||||
if (fBuffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fBuffer->SetVecs(vecs, count, length, flags);
|
||||
fBuffer->SetVecs(firstVecOffset, vecs, count, length, flags);
|
||||
|
||||
fOffset = offset;
|
||||
fLength = length;
|
||||
@ -543,8 +550,72 @@ IORequest::Init(off_t offset, iovec* vecs, size_t count, size_t length,
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IORequest::CreateSubRequest(off_t parentOffset, off_t offset, size_t length,
|
||||
IORequest*& _subRequest)
|
||||
{
|
||||
ASSERT(parentOffset >= fOffset && length <= fLength
|
||||
&& parentOffset - fOffset <= fLength - length);
|
||||
|
||||
// find start vec
|
||||
size_t vecOffset = parentOffset - fOffset;
|
||||
iovec* vecs = fBuffer->Vecs();
|
||||
int32 vecCount = fBuffer->VecCount();
|
||||
int32 startVec = 0;
|
||||
for (; startVec < vecCount; startVec++) {
|
||||
const iovec& vec = vecs[startVec];
|
||||
if (vecOffset < vec.iov_len)
|
||||
break;
|
||||
|
||||
vecOffset -= vec.iov_len;
|
||||
}
|
||||
|
||||
// count vecs
|
||||
size_t currentVecOffset = vecOffset;
|
||||
int32 endVec = startVec;
|
||||
size_t remainingLength = length;
|
||||
for (; endVec < vecCount; endVec++) {
|
||||
const iovec& vec = vecs[endVec];
|
||||
if (vec.iov_len - currentVecOffset >= remainingLength)
|
||||
break;
|
||||
|
||||
remainingLength -= vec.iov_len - currentVecOffset;
|
||||
currentVecOffset = 0;
|
||||
}
|
||||
|
||||
// create subrequest
|
||||
IORequest* subRequest = new(std::nothrow) IORequest;
|
||||
// TODO: Heed B_VIP_IO_REQUEST!
|
||||
if (subRequest == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t error = subRequest->Init(offset, vecOffset, vecs + startVec,
|
||||
endVec - startVec + 1, length, fIsWrite, fFlags);
|
||||
if (error != B_OK) {
|
||||
delete subRequest;
|
||||
return error;
|
||||
}
|
||||
|
||||
MutexLocker _(fLock);
|
||||
|
||||
fChildren.Add(subRequest);
|
||||
fPendingChildren++;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
IORequest::SetFinishedCallback(io_request_callback callback, void* cookie)
|
||||
IORequest::DeleteSubRequests()
|
||||
{
|
||||
while (IORequestChunk* chunk = fChildren.RemoveHead())
|
||||
delete chunk;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
IORequest::SetFinishedCallback(io_request_finished_callback callback,
|
||||
void* cookie)
|
||||
{
|
||||
fFinishedCallback = callback;
|
||||
fFinishedCookie = cookie;
|
||||
@ -552,13 +623,23 @@ IORequest::SetFinishedCallback(io_request_callback callback, void* cookie)
|
||||
|
||||
|
||||
void
|
||||
IORequest::SetIterationCallback(io_request_callback callback, void* cookie)
|
||||
IORequest::SetIterationCallback(io_request_iterate_callback callback,
|
||||
void* cookie)
|
||||
{
|
||||
fIterationCallback = callback;
|
||||
fIterationCookie = cookie;
|
||||
}
|
||||
|
||||
|
||||
io_request_finished_callback
|
||||
IORequest::FinishedCallback(void** _cookie) const
|
||||
{
|
||||
if (_cookie != NULL)
|
||||
*_cookie = fFinishedCookie;
|
||||
return fFinishedCallback;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IORequest::Wait(uint32 flags, bigtime_t timeout)
|
||||
{
|
||||
@ -591,31 +672,39 @@ IORequest::NotifyFinished()
|
||||
// The request is not really done yet. If it has an iteration callback,
|
||||
// call it.
|
||||
if (fIterationCallback != NULL) {
|
||||
ResetStatus();
|
||||
locker.Unlock();
|
||||
fIterationCallback(fIterationCookie, this);
|
||||
status_t error = fIterationCallback(fIterationCookie, this);
|
||||
if (error == B_OK)
|
||||
return;
|
||||
|
||||
// Iteration failed, which means we're responsible for notifying the
|
||||
// requests finished.
|
||||
locker.Lock();
|
||||
fStatus = error;
|
||||
}
|
||||
} else {
|
||||
// Cache the callbacks before we unblock waiters and unlock. Any of the
|
||||
// following could delete this request, so we don't want to touch it
|
||||
// once we have started telling others that it is done.
|
||||
IORequest* parent = fParent;
|
||||
io_request_callback finishedCallback = fFinishedCallback;
|
||||
void* finishedCookie = fFinishedCookie;
|
||||
status_t status = fStatus;
|
||||
|
||||
// unblock waiters
|
||||
fFinishedCondition.NotifyAll();
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
// notify callback
|
||||
if (finishedCallback != NULL)
|
||||
finishedCallback(finishedCookie, this);
|
||||
|
||||
// notify parent
|
||||
if (parent != NULL)
|
||||
parent->SubrequestFinished(this, status);
|
||||
}
|
||||
|
||||
// Cache the callbacks before we unblock waiters and unlock. Any of the
|
||||
// following could delete this request, so we don't want to touch it
|
||||
// once we have started telling others that it is done.
|
||||
IORequest* parent = fParent;
|
||||
io_request_finished_callback finishedCallback = fFinishedCallback;
|
||||
void* finishedCookie = fFinishedCookie;
|
||||
status_t status = fStatus;
|
||||
|
||||
// unblock waiters
|
||||
fFinishedCondition.NotifyAll();
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
// notify callback
|
||||
if (finishedCallback != NULL)
|
||||
finishedCallback(finishedCookie, this, status);
|
||||
|
||||
// notify parent
|
||||
if (parent != NULL)
|
||||
parent->SubRequestFinished(this, status);
|
||||
}
|
||||
|
||||
|
||||
@ -633,6 +722,22 @@ IORequest::HasCallbacks() const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
IORequest::SetStatusAndNotify(status_t status)
|
||||
{
|
||||
MutexLocker locker(fLock);
|
||||
|
||||
if (fStatus != 1)
|
||||
return;
|
||||
|
||||
fStatus = status;
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
NotifyFinished();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
IORequest::OperationFinished(IOOperation* operation, status_t status)
|
||||
{
|
||||
@ -665,7 +770,7 @@ IORequest::OperationFinished(IOOperation* operation, status_t status)
|
||||
|
||||
|
||||
void
|
||||
IORequest::SubrequestFinished(IORequest* request, status_t status)
|
||||
IORequest::SubRequestFinished(IORequest* request, status_t status)
|
||||
{
|
||||
TRACE("IORequest::SubrequestFinished(%p, %#lx): request: %p\n", request,
|
||||
status, this);
|
||||
@ -708,6 +813,22 @@ IORequest::Advance(size_t bySize)
|
||||
}
|
||||
|
||||
|
||||
IORequest*
|
||||
IORequest::FirstSubRequest()
|
||||
{
|
||||
return dynamic_cast<IORequest*>(fChildren.Head());
|
||||
}
|
||||
|
||||
|
||||
IORequest*
|
||||
IORequest::NextSubRequest(IORequest* previous)
|
||||
{
|
||||
if (previous == NULL)
|
||||
return NULL;
|
||||
return dynamic_cast<IORequest*>(fChildren.GetNext(previous));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
IORequest::AddOperation(IOOperation* operation)
|
||||
{
|
||||
@ -818,13 +939,16 @@ IORequest::_CopyPhysical(void* _bounceBuffer, void* _external, size_t size,
|
||||
addr_t external = (addr_t)_external;
|
||||
|
||||
while (size > 0) {
|
||||
addr_t pageOffset = external % B_PAGE_SIZE;
|
||||
addr_t virtualAddress;
|
||||
status_t error = vm_get_physical_page(external, &virtualAddress, 0);
|
||||
status_t error = vm_get_physical_page(external - pageOffset,
|
||||
&virtualAddress, 0);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
size_t toCopy = min_c(size, B_PAGE_SIZE);
|
||||
_CopySimple(bounceBuffer, (void*)virtualAddress, toCopy, team, copyIn);
|
||||
size_t toCopy = min_c(size, B_PAGE_SIZE - pageOffset);
|
||||
_CopySimple(bounceBuffer, (void*)(virtualAddress + pageOffset), toCopy,
|
||||
team, copyIn);
|
||||
|
||||
vm_put_physical_page(virtualAddress);
|
||||
|
||||
|
@ -34,7 +34,8 @@ public:
|
||||
bool IsPhysical() const { return fPhysical; }
|
||||
bool IsUser() const { return fUser; }
|
||||
|
||||
void SetVecs(const iovec* vecs, uint32 count,
|
||||
void SetVecs(size_t firstVecOffset,
|
||||
const iovec* vecs, uint32 count,
|
||||
size_t length, uint32 flags);
|
||||
|
||||
void SetPhysical(bool physical)
|
||||
@ -81,14 +82,16 @@ public:
|
||||
{ fParent = parent; }
|
||||
|
||||
status_t Status() const { return fStatus; }
|
||||
|
||||
DoublyLinkedListLink<IORequestChunk>*
|
||||
ListLink() { return &fListLink; }
|
||||
|
||||
protected:
|
||||
void SetStatus(status_t status)
|
||||
{ fStatus = status; }
|
||||
void ResetStatus()
|
||||
{ fStatus = 1; }
|
||||
|
||||
DoublyLinkedListLink<IORequestChunk>*
|
||||
ListLink() { return &fListLink; }
|
||||
|
||||
protected:
|
||||
IORequest* fParent;
|
||||
status_t fStatus;
|
||||
@ -112,6 +115,9 @@ public:
|
||||
// also sets range
|
||||
void SetRange(off_t offset, size_t length);
|
||||
|
||||
void SetStatus(status_t status)
|
||||
{ IORequestChunk::SetStatus(status); }
|
||||
|
||||
off_t Offset() const;
|
||||
size_t Length() const;
|
||||
off_t OriginalOffset() const
|
||||
@ -162,11 +168,15 @@ protected:
|
||||
bool fUsesBounceBuffer;
|
||||
};
|
||||
|
||||
|
||||
typedef IOOperation io_operation;
|
||||
typedef DoublyLinkedList<IOOperation> IOOperationList;
|
||||
|
||||
typedef struct IORequest io_request;
|
||||
typedef status_t (*io_request_callback)(void* data, io_request* request);
|
||||
typedef status_t (*io_request_finished_callback)(void* data,
|
||||
io_request* request, status_t status);
|
||||
typedef status_t (*io_request_iterate_callback)(void* data,
|
||||
io_request* request);
|
||||
|
||||
|
||||
struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl<IORequest> {
|
||||
@ -176,14 +186,26 @@ struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl<IORequest> {
|
||||
status_t Init(off_t offset, void* buffer, size_t length,
|
||||
bool write, uint32 flags);
|
||||
status_t Init(off_t offset, iovec* vecs, size_t count,
|
||||
size_t length, bool write, uint32 flags);
|
||||
size_t length, bool write, uint32 flags)
|
||||
{ return Init(offset, 0, vecs, count,
|
||||
length, write, flags); }
|
||||
status_t Init(off_t offset, size_t firstVecOffset,
|
||||
iovec* vecs, size_t count, size_t length,
|
||||
bool write, uint32 flags);
|
||||
|
||||
status_t CreateSubRequest(off_t parentOffset,
|
||||
off_t offset, size_t length,
|
||||
IORequest*& subRequest);
|
||||
void DeleteSubRequests();
|
||||
|
||||
void SetFinishedCallback(
|
||||
io_request_callback callback,
|
||||
io_request_finished_callback callback,
|
||||
void* cookie);
|
||||
void SetIterationCallback(
|
||||
io_request_callback callback,
|
||||
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);
|
||||
|
||||
@ -192,10 +214,11 @@ struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl<IORequest> {
|
||||
&& fPendingChildren == 0; }
|
||||
void NotifyFinished();
|
||||
bool HasCallbacks() const;
|
||||
void SetStatusAndNotify(status_t status);
|
||||
|
||||
void OperationFinished(IOOperation* operation,
|
||||
status_t status);
|
||||
void SubrequestFinished(IORequest* request,
|
||||
void SubRequestFinished(IORequest* request,
|
||||
status_t status);
|
||||
|
||||
size_t RemainingBytes() const
|
||||
@ -214,6 +237,9 @@ struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl<IORequest> {
|
||||
|
||||
void Advance(size_t bySize);
|
||||
|
||||
IORequest* FirstSubRequest();
|
||||
IORequest* NextSubRequest(IORequest* previous);
|
||||
|
||||
void AddOperation(IOOperation* operation);
|
||||
void RemoveOperation(IOOperation* operation);
|
||||
|
||||
@ -243,9 +269,9 @@ private:
|
||||
team_id fTeam;
|
||||
bool fIsWrite;
|
||||
|
||||
io_request_callback fFinishedCallback;
|
||||
io_request_finished_callback fFinishedCallback;
|
||||
void* fFinishedCookie;
|
||||
io_request_callback fIterationCallback;
|
||||
io_request_iterate_callback fIterationCallback;
|
||||
void* fIterationCookie;
|
||||
ConditionVariable fFinishedCondition;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user