From 60f4376e26566eea7e6e61751ec60976e1b7a0e0 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 17 Mar 2009 00:33:07 +0000 Subject: [PATCH] * Removed the unused Port::SendAndReceive(). * Change Port::Receive() semantics. It does no longer use the buffer associated with the object. Instead it allocates heap memory for the caller. Since there's only one caller who clones the message anyway, we save one copy this way (though we have an additional syscall in userland) and don't overwrite a request being prepared for sending. * Changed RequestAllocator::ReadRequest() to also read the request from the port. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29563 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/userlandfs/private/Port.h | 10 ++- .../userlandfs/private/RequestAllocator.h | 8 +- .../file_systems/userlandfs/private/Port.cpp | 87 ++++++++++++------- .../userlandfs/private/RequestAllocator.cpp | 47 ++++++---- .../userlandfs/private/RequestPort.cpp | 7 +- 5 files changed, 101 insertions(+), 58 deletions(-) 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;