* 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
#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;
@@ -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
#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;
@@ -1,7 +1,12 @@
// Port.cpp
/*
* Copyright 2001-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include <new>
#include <AutoDeleter.h>
#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;
}
@@ -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 "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);
}
@@ -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<AllocatorNode> 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;