// RequestPort.cpp
#include <new>
#include "AutoDeleter.h"
#include "Debug.h"
#include "Request.h"
#include "RequestHandler.h"
#include "RequestPort.h"
using std::nothrow;
// TODO: Limit the stacking of requests?
// AllocatorNode
struct RequestPort::AllocatorNode {
AllocatorNode(Port* port) : allocator(port), previous(NULL) {}
RequestAllocator allocator;
AllocatorNode* previous;
};
// constructor
RequestPort::RequestPort(int32 size)
: fPort(size),
fCurrentAllocatorNode(NULL)
{
}
// constructor
RequestPort::RequestPort(const Port::Info* info)
: fPort(info),
fCurrentAllocatorNode(NULL)
{
}
// destructor
RequestPort::~RequestPort()
{
while (fCurrentAllocatorNode)
_PopAllocator();
}
// Close
void
RequestPort::Close()
{
fPort.Close();
}
// InitCheck
status_t
RequestPort::InitCheck() const
{
return fPort.InitCheck();
}
// GetPort
Port*
RequestPort::GetPort()
{
return &fPort;
}
// GetPortInfo
const Port::Info*
RequestPort::GetPortInfo() const
{
return fPort.GetInfo();
}
// SendRequest
status_t
RequestPort::SendRequest(RequestAllocator* allocator)
{
// check initialization and parameters
if (InitCheck() != B_OK)
RETURN_ERROR(InitCheck());
if (!allocator || allocator->GetRequest() == NULL
|| allocator->GetRequestSize() < (int32)sizeof(Request)) {
RETURN_ERROR(B_BAD_VALUE);
}
allocator->FinishDeferredInit();
//PRINT(("RequestPort::SendRequest(%lu)\n", allocator->GetRequest()->GetType()));
#if USER && !KERNEL_EMU
if (!is_userland_request(allocator->GetRequest()->GetType())) {
ERROR(("RequestPort::SendRequest(%" B_PRId32 "): request is not a "
"userland request\n", allocator->GetRequest()->GetType()));
debugger("Request is not a userland request.");
}
#else
if (!is_kernel_request(allocator->GetRequest()->GetType())) {
ERROR(("RequestPort::SendRequest(%" B_PRId32 "): request is not a "
"kernel request\n", allocator->GetRequest()->GetType()));
debugger("Request is not a kernel request.");
}
#endif
RETURN_ERROR(fPort.Send(allocator->GetRequest(),
allocator->GetRequestSize()));
}
// SendRequest
status_t
RequestPort::SendRequest(RequestAllocator* allocator,
RequestHandler* handler, Request** reply, bigtime_t timeout)
{
status_t error = SendRequest(allocator);
if (error != B_OK)
return error;
return HandleRequests(handler, reply, timeout);
}
// ReceiveRequest
//
// The caller is responsible for calling ReleaseRequest() with the request.
status_t
RequestPort::ReceiveRequest(Request** request, bigtime_t timeout)
{
// check initialization and parameters
if (InitCheck() != B_OK)
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 = 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
if (error != B_OK)
RETURN_ERROR(error);
// everything went fine: push the allocator
*request = node->allocator.GetRequest();
node->previous = fCurrentAllocatorNode;
fCurrentAllocatorNode = node;
deleter.Detach();
//PRINT(("RequestPort::RequestReceived(%lu)\n", (*request)->GetType()));
return B_OK;
}
// HandleRequests
//
// If request is not NULL, the caller is responsible for calling
// ReleaseRequest() with the request. If it is NULL, the request will already
// be gone, when the method returns.
status_t
RequestPort::HandleRequests(RequestHandler* handler, Request** request,
bigtime_t timeout)
{
// check initialization and parameters
if (InitCheck() != B_OK)
RETURN_ERROR(InitCheck());
if (!handler)
RETURN_ERROR(B_BAD_VALUE);
handler->SetPort(this);
Request* currentRequest = NULL;
do {
if (currentRequest)
ReleaseRequest(currentRequest);
status_t error = ReceiveRequest(¤tRequest, timeout);
if (error != B_OK)
return error;
// handle the request
error = handler->HandleRequest(currentRequest);
if (error != B_OK) {
ReleaseRequest(currentRequest);
RETURN_ERROR(error);
}
} while (!handler->IsDone());
if (request)
*request = currentRequest;
else
ReleaseRequest(currentRequest);
return B_OK;
}
// ReleaseRequest
void
RequestPort::ReleaseRequest(Request* request)
{
if (request && fCurrentAllocatorNode
&& request == fCurrentAllocatorNode->allocator.GetRequest()) {
_PopAllocator();
}
}
// _PopAllocator
void
RequestPort::_PopAllocator()
{
if (fCurrentAllocatorNode) {
AllocatorNode* node = fCurrentAllocatorNode->previous;
delete fCurrentAllocatorNode;
fCurrentAllocatorNode = node;
}
}
↑ V547 Expression 'error != ((int) 0)' is always false.