diff --git a/headers/private/userlandfs/private/Port.h b/headers/private/userlandfs/private/Port.h index e3d931cf4b..6453a5d333 100644 --- a/headers/private/userlandfs/private/Port.h +++ b/headers/private/userlandfs/private/Port.h @@ -1,5 +1,7 @@ -// Port.h - +/* + * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ #ifndef USERLAND_FS_PORT_H #define USERLAND_FS_PORT_H @@ -38,8 +40,8 @@ public: int32 GetMessageSize() const; status_t Send(int32 size); - status_t SendAndReceive(int32 size); - status_t Receive(bigtime_t timeout = -1); + status_t Receive(void** _message, size_t* _size, + bigtime_t timeout = -1); private: friend class ::KernelDebug; diff --git a/headers/private/userlandfs/private/RequestAllocator.h b/headers/private/userlandfs/private/RequestAllocator.h index 7714d24974..6084c95fa0 100644 --- a/headers/private/userlandfs/private/RequestAllocator.h +++ b/headers/private/userlandfs/private/RequestAllocator.h @@ -1,5 +1,7 @@ -// RequestAllocator.h - +/* + * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ #ifndef USERLAND_FS_REQUEST_ALLOCATOR_H #define USERLAND_FS_REQUEST_ALLOCATOR_H @@ -28,7 +30,7 @@ public: void FinishDeferredInit(); status_t AllocateRequest(int32 size); - status_t ReadRequest(); + status_t ReadRequest(bigtime_t timeout); Request* GetRequest() const; int32 GetRequestSize() const; diff --git a/src/add-ons/kernel/file_systems/userlandfs/private/Port.cpp b/src/add-ons/kernel/file_systems/userlandfs/private/Port.cpp index f54dd50f2d..f7ed2248ca 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/private/Port.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/private/Port.cpp @@ -1,7 +1,12 @@ -// Port.cpp +/* + * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ #include +#include + #include "AreaSupport.h" #include "Compatibility.h" #include "Port.h" @@ -160,46 +165,62 @@ Port::Send(int32 size) return (fInitStatus = error); } -// SendAndReceive -status_t -Port::SendAndReceive(int32 size) -{ - status_t error = Send(size); - if (error != B_OK) - return error; - return Receive(); -} // Receive status_t -Port::Receive(bigtime_t timeout) +Port::Receive(void** _message, size_t* _size, bigtime_t timeout) { if (fInitStatus != B_OK) return fInitStatus; - port_id port = (fOwner ? fInfo.owner_port : fInfo.client_port); - status_t error = B_OK; - do { - int32 code; - ssize_t bytesRead; - if (timeout >= 0) { - bytesRead = read_port_etc(port, &code, fBuffer, fCapacity, - B_RELATIVE_TIMEOUT, timeout); - } else - bytesRead = read_port(port, &code, fBuffer, fCapacity); - if (bytesRead < 0) - error = bytesRead; - else - fMessageSize = bytesRead; - } while (error == B_INTERRUPTED); - if (error == B_TIMED_OUT || error == B_WOULD_BLOCK) { - return error; + + // convert to timeout to flags + timeout we can use in the loop + uint32 timeoutFlags = 0; + if (timeout < 0) { + timeout = 0; + } else if (timeout == 0) { + timeoutFlags = B_RELATIVE_TIMEOUT; + } else if (timeout >= 0) { + timeout += system_time(); + timeoutFlags = B_ABSOLUTE_TIMEOUT; } + + port_id port = (fOwner ? fInfo.owner_port : fInfo.client_port); + + // wait for the next message + status_t error = B_OK; + ssize_t bufferSize; + do { + // TODO: When compiling for userland, we might want to save this syscall + // by using read_port_etc() directly, using a sufficiently large + // on-stack buffer and copying onto the heap. + bufferSize = port_buffer_size_etc(port, timeoutFlags, timeout); + if (bufferSize < 0) + error = bufferSize; + } while (error == B_INTERRUPTED); + + if (error == B_TIMED_OUT || error == B_WOULD_BLOCK) + return error; if (error != B_OK) return (fInitStatus = error); - if (fMessageSize <= 0 || fMessageSize > fCapacity) { - fMessageSize = 0; - return B_BAD_DATA; - } + + // allocate memory for the message + void* message = malloc(bufferSize); + if (message == NULL) + return (fInitStatus = B_NO_MEMORY); + MemoryDeleter messageDeleter(message); + + // read the message + int32 code; + ssize_t bytesRead = read_port_etc(port, &code, message, bufferSize, + B_RELATIVE_TIMEOUT, 0); + if (bytesRead < 0) + return fInitStatus = bytesRead; + if (bytesRead != bufferSize) + return fInitStatus = B_BAD_DATA; + + messageDeleter.Detach(); + *_message = message; + *_size = bytesRead; + return B_OK; } - diff --git a/src/add-ons/kernel/file_systems/userlandfs/private/RequestAllocator.cpp b/src/add-ons/kernel/file_systems/userlandfs/private/RequestAllocator.cpp index d0a401fd16..ce164afb6e 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/private/RequestAllocator.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/private/RequestAllocator.cpp @@ -1,6 +1,9 @@ -// RequestAllocator.cpp +/* + * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ -#include +#include #include "AreaSupport.h" #include "Compatibility.h" @@ -8,7 +11,6 @@ #include "Port.h" #include "RequestAllocator.h" -using std::nothrow; // constructor RequestAllocator::RequestAllocator(Port* port) @@ -46,13 +48,13 @@ void RequestAllocator::Uninit() { if (!fRequestInPortBuffer) - delete[] (uint8*)fRequest; + free(fRequest); for (int32 i = 0; i < fAllocatedAreaCount; i++) delete_area(fAllocatedAreas[i]); fAllocatedAreaCount = 0; for (int32 i = 0; i < fDeferredInitInfoCount; i++) { if (fDeferredInitInfos[i].inPortBuffer) - delete[] fDeferredInitInfos[i].data; + free(fDeferredInitInfos[i].data); } fDeferredInitInfoCount = 0; fError = B_NO_INIT; @@ -79,7 +81,7 @@ RequestAllocator::FinishDeferredInit() if (info.inPortBuffer) { if (info.size > 0) memcpy((uint8*)fRequest + info.offset, info.data, info.size); - delete[] info.data; + free(info.data); } PRINT(("RequestAllocator::FinishDeferredInit(): area: %ld, " "offset: %ld, size: %ld\n", info.area, info.offset, info.size)); @@ -104,19 +106,32 @@ RequestAllocator::AllocateRequest(int32 size) // ReadRequest status_t -RequestAllocator::ReadRequest() +RequestAllocator::ReadRequest(bigtime_t timeout) { if (fError != B_OK) RETURN_ERROR(fError); - if (fPort->GetMessageSize() < (int32)sizeof(Request)) + + // read the message from the port + void* message; + size_t messageSize; + status_t error = fPort->Receive(&message, &messageSize, timeout); + if (error != B_OK) { + if (error != B_TIMED_OUT && error != B_WOULD_BLOCK) + RETURN_ERROR(fError = error); + return error; + } + + // shouldn't be shorter than the base Request + if (messageSize < (int32)sizeof(Request)) { + free(message); RETURN_ERROR(fError = B_BAD_DATA); - // clone the request - fRequest = (Request*)new(nothrow) uint8[fPort->GetMessageSize()]; - if (!fRequest) - RETURN_ERROR(fError = B_NO_MEMORY); - memcpy(fRequest, fPort->GetMessage(), fPort->GetMessageSize()); - fRequestSize = fPort->GetMessageSize(); + } + + // init the request + fRequest = (Request*)message; + fRequestSize = messageSize; fRequestInPortBuffer = false; + // relocate the request fError = relocate_request(fRequest, fRequestSize, fAllocatedAreas, &fAllocatedAreaCount); @@ -177,7 +192,7 @@ RequestAllocator::AllocateAddress(Address& address, int32 size, int32 align, DeferredInitInfo& info = fDeferredInitInfos[fDeferredInitInfoCount]; if (size > 0) { - info.data = new(nothrow) uint8[size]; + info.data = (uint8*)malloc(size); if (!info.data) RETURN_ERROR(B_NO_MEMORY); } else @@ -219,7 +234,7 @@ RequestAllocator::AllocateAddress(Address& address, int32 size, int32 align, info.target = &address; fDeferredInitInfoCount++; PRINT((" RequestAllocator::AllocateAddress(): deferred allocated area: " -"%ld, size: %ld (%ld), data: %p\n", area, size, areaSize, *data)); +"%ld, size: %ld (%ld), data: %p\n", area, size, areaSize, *data)); } else address.SetTo(area, 0, size); } diff --git a/src/add-ons/kernel/file_systems/userlandfs/private/RequestPort.cpp b/src/add-ons/kernel/file_systems/userlandfs/private/RequestPort.cpp index e36399fb47..38af9dfcc5 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/private/RequestPort.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/private/RequestPort.cpp @@ -122,22 +122,25 @@ RequestPort::ReceiveRequest(Request** request, bigtime_t timeout) RETURN_ERROR(InitCheck()); if (!request) RETURN_ERROR(B_BAD_VALUE); + // allocate a request allocator AllocatorNode* node = new(nothrow) AllocatorNode(&fPort); if (!node) RETURN_ERROR(B_NO_MEMORY); ObjectDeleter deleter(node); + // receive the message - status_t error = fPort.Receive(timeout); + status_t error = node->allocator.ReadRequest(timeout); if (error != B_OK) { if (error != B_TIMED_OUT && error != B_WOULD_BLOCK) RETURN_ERROR(error); return error; } + // allocate the request - error = node->allocator.ReadRequest(); if (error != B_OK) RETURN_ERROR(error); + // everything went fine: push the allocator *request = node->allocator.GetRequest(); node->previous = fCurrentAllocatorNode;