* 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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user