* 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
This commit is contained in:
Ingo Weinhold
2009-03-17 00:33:07 +00:00
parent c0f674824c
commit 60f4376e26
5 changed files with 101 additions and 58 deletions
+6 -4
View File
@@ -1,5 +1,7 @@
// Port.h /*
* Copyright 2001-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef USERLAND_FS_PORT_H #ifndef USERLAND_FS_PORT_H
#define USERLAND_FS_PORT_H #define USERLAND_FS_PORT_H
@@ -38,8 +40,8 @@ public:
int32 GetMessageSize() const; int32 GetMessageSize() const;
status_t Send(int32 size); status_t Send(int32 size);
status_t SendAndReceive(int32 size); status_t Receive(void** _message, size_t* _size,
status_t Receive(bigtime_t timeout = -1); bigtime_t timeout = -1);
private: private:
friend class ::KernelDebug; friend class ::KernelDebug;
@@ -1,5 +1,7 @@
// RequestAllocator.h /*
* Copyright 2001-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef USERLAND_FS_REQUEST_ALLOCATOR_H #ifndef USERLAND_FS_REQUEST_ALLOCATOR_H
#define USERLAND_FS_REQUEST_ALLOCATOR_H #define USERLAND_FS_REQUEST_ALLOCATOR_H
@@ -28,7 +30,7 @@ public:
void FinishDeferredInit(); void FinishDeferredInit();
status_t AllocateRequest(int32 size); status_t AllocateRequest(int32 size);
status_t ReadRequest(); status_t ReadRequest(bigtime_t timeout);
Request* GetRequest() const; Request* GetRequest() const;
int32 GetRequestSize() const; int32 GetRequestSize() const;
@@ -1,7 +1,12 @@
// Port.cpp /*
* Copyright 2001-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include <new> #include <new>
#include <AutoDeleter.h>
#include "AreaSupport.h" #include "AreaSupport.h"
#include "Compatibility.h" #include "Compatibility.h"
#include "Port.h" #include "Port.h"
@@ -160,46 +165,62 @@ Port::Send(int32 size)
return (fInitStatus = error); return (fInitStatus = error);
} }
// SendAndReceive
status_t
Port::SendAndReceive(int32 size)
{
status_t error = Send(size);
if (error != B_OK)
return error;
return Receive();
}
// Receive // Receive
status_t status_t
Port::Receive(bigtime_t timeout) Port::Receive(void** _message, size_t* _size, bigtime_t timeout)
{ {
if (fInitStatus != B_OK) if (fInitStatus != B_OK)
return fInitStatus; return fInitStatus;
port_id port = (fOwner ? fInfo.owner_port : fInfo.client_port);
status_t error = B_OK; // convert to timeout to flags + timeout we can use in the loop
do { uint32 timeoutFlags = 0;
int32 code; if (timeout < 0) {
ssize_t bytesRead; timeout = 0;
if (timeout >= 0) { } else if (timeout == 0) {
bytesRead = read_port_etc(port, &code, fBuffer, fCapacity, timeoutFlags = B_RELATIVE_TIMEOUT;
B_RELATIVE_TIMEOUT, timeout); } else if (timeout >= 0) {
} else timeout += system_time();
bytesRead = read_port(port, &code, fBuffer, fCapacity); timeoutFlags = B_ABSOLUTE_TIMEOUT;
if (bytesRead < 0)
error = bytesRead;
else
fMessageSize = bytesRead;
} while (error == B_INTERRUPTED);
if (error == B_TIMED_OUT || error == B_WOULD_BLOCK) {
return error;
} }
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) if (error != B_OK)
return (fInitStatus = error); return (fInitStatus = error);
if (fMessageSize <= 0 || fMessageSize > fCapacity) {
fMessageSize = 0; // allocate memory for the message
return B_BAD_DATA; 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; return B_OK;
} }
@@ -1,6 +1,9 @@
// RequestAllocator.cpp /*
* Copyright 2001-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include <new> #include <stdlib.h>
#include "AreaSupport.h" #include "AreaSupport.h"
#include "Compatibility.h" #include "Compatibility.h"
@@ -8,7 +11,6 @@
#include "Port.h" #include "Port.h"
#include "RequestAllocator.h" #include "RequestAllocator.h"
using std::nothrow;
// constructor // constructor
RequestAllocator::RequestAllocator(Port* port) RequestAllocator::RequestAllocator(Port* port)
@@ -46,13 +48,13 @@ void
RequestAllocator::Uninit() RequestAllocator::Uninit()
{ {
if (!fRequestInPortBuffer) if (!fRequestInPortBuffer)
delete[] (uint8*)fRequest; free(fRequest);
for (int32 i = 0; i < fAllocatedAreaCount; i++) for (int32 i = 0; i < fAllocatedAreaCount; i++)
delete_area(fAllocatedAreas[i]); delete_area(fAllocatedAreas[i]);
fAllocatedAreaCount = 0; fAllocatedAreaCount = 0;
for (int32 i = 0; i < fDeferredInitInfoCount; i++) { for (int32 i = 0; i < fDeferredInitInfoCount; i++) {
if (fDeferredInitInfos[i].inPortBuffer) if (fDeferredInitInfos[i].inPortBuffer)
delete[] fDeferredInitInfos[i].data; free(fDeferredInitInfos[i].data);
} }
fDeferredInitInfoCount = 0; fDeferredInitInfoCount = 0;
fError = B_NO_INIT; fError = B_NO_INIT;
@@ -79,7 +81,7 @@ RequestAllocator::FinishDeferredInit()
if (info.inPortBuffer) { if (info.inPortBuffer) {
if (info.size > 0) if (info.size > 0)
memcpy((uint8*)fRequest + info.offset, info.data, info.size); memcpy((uint8*)fRequest + info.offset, info.data, info.size);
delete[] info.data; free(info.data);
} }
PRINT(("RequestAllocator::FinishDeferredInit(): area: %ld, " PRINT(("RequestAllocator::FinishDeferredInit(): area: %ld, "
"offset: %ld, size: %ld\n", info.area, info.offset, info.size)); "offset: %ld, size: %ld\n", info.area, info.offset, info.size));
@@ -104,19 +106,32 @@ RequestAllocator::AllocateRequest(int32 size)
// ReadRequest // ReadRequest
status_t status_t
RequestAllocator::ReadRequest() RequestAllocator::ReadRequest(bigtime_t timeout)
{ {
if (fError != B_OK) if (fError != B_OK)
RETURN_ERROR(fError); 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); RETURN_ERROR(fError = B_BAD_DATA);
// clone the request }
fRequest = (Request*)new(nothrow) uint8[fPort->GetMessageSize()];
if (!fRequest) // init the request
RETURN_ERROR(fError = B_NO_MEMORY); fRequest = (Request*)message;
memcpy(fRequest, fPort->GetMessage(), fPort->GetMessageSize()); fRequestSize = messageSize;
fRequestSize = fPort->GetMessageSize();
fRequestInPortBuffer = false; fRequestInPortBuffer = false;
// relocate the request // relocate the request
fError = relocate_request(fRequest, fRequestSize, fAllocatedAreas, fError = relocate_request(fRequest, fRequestSize, fAllocatedAreas,
&fAllocatedAreaCount); &fAllocatedAreaCount);
@@ -177,7 +192,7 @@ RequestAllocator::AllocateAddress(Address& address, int32 size, int32 align,
DeferredInitInfo& info DeferredInitInfo& info
= fDeferredInitInfos[fDeferredInitInfoCount]; = fDeferredInitInfos[fDeferredInitInfoCount];
if (size > 0) { if (size > 0) {
info.data = new(nothrow) uint8[size]; info.data = (uint8*)malloc(size);
if (!info.data) if (!info.data)
RETURN_ERROR(B_NO_MEMORY); RETURN_ERROR(B_NO_MEMORY);
} else } else
@@ -122,22 +122,25 @@ RequestPort::ReceiveRequest(Request** request, bigtime_t timeout)
RETURN_ERROR(InitCheck()); RETURN_ERROR(InitCheck());
if (!request) if (!request)
RETURN_ERROR(B_BAD_VALUE); RETURN_ERROR(B_BAD_VALUE);
// allocate a request allocator // allocate a request allocator
AllocatorNode* node = new(nothrow) AllocatorNode(&fPort); AllocatorNode* node = new(nothrow) AllocatorNode(&fPort);
if (!node) if (!node)
RETURN_ERROR(B_NO_MEMORY); RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<AllocatorNode> deleter(node); ObjectDeleter<AllocatorNode> deleter(node);
// receive the message // receive the message
status_t error = fPort.Receive(timeout); status_t error = node->allocator.ReadRequest(timeout);
if (error != B_OK) { if (error != B_OK) {
if (error != B_TIMED_OUT && error != B_WOULD_BLOCK) if (error != B_TIMED_OUT && error != B_WOULD_BLOCK)
RETURN_ERROR(error); RETURN_ERROR(error);
return error; return error;
} }
// allocate the request // allocate the request
error = node->allocator.ReadRequest();
if (error != B_OK) if (error != B_OK)
RETURN_ERROR(error); RETURN_ERROR(error);
// everything went fine: push the allocator // everything went fine: push the allocator
*request = node->allocator.GetRequest(); *request = node->allocator.GetRequest();
node->previous = fCurrentAllocatorNode; node->previous = fCurrentAllocatorNode;