1// RequestPort.cpp 2 3#include <new> 4 5#include "AutoDeleter.h" 6#include "Debug.h" 7#include "Request.h" 8#include "RequestHandler.h" 9#include "RequestPort.h" 10 11// TODO: Limit the stacking of requests? 12 13// AllocatorNode 14struct RequestPort::AllocatorNode { 15 AllocatorNode(Port* port) : allocator(port), previous(NULL) {} 16 17 RequestAllocator allocator; 18 AllocatorNode* previous; 19}; 20 21 22// constructor 23RequestPort::RequestPort(int32 size) 24 : fPort(size), 25 fCurrentAllocatorNode(NULL) 26{ 27} 28 29// constructor 30RequestPort::RequestPort(const Port::Info* info) 31 : fPort(info), 32 fCurrentAllocatorNode(NULL) 33{ 34} 35 36// destructor 37RequestPort::~RequestPort() 38{ 39 while (fCurrentAllocatorNode) 40 _PopAllocator(); 41} 42 43// Close 44void 45RequestPort::Close() 46{ 47 fPort.Close(); 48} 49 50// InitCheck 51status_t 52RequestPort::InitCheck() const 53{ 54 return fPort.InitCheck(); 55} 56 57// GetPort 58Port* 59RequestPort::GetPort() 60{ 61 return &fPort; 62} 63 64// GetPortInfo 65const Port::Info* 66RequestPort::GetPortInfo() const 67{ 68 return fPort.GetInfo(); 69} 70 71// SendRequest 72status_t 73RequestPort::SendRequest(RequestAllocator* allocator) 74{ 75 // check initialization and parameters 76 if (InitCheck() != B_OK) 77 RETURN_ERROR(InitCheck()); 78 if (!allocator || allocator->GetRequest() != fPort.GetBuffer() 79 || allocator->GetRequestSize() < (int32)sizeof(Request) 80 || allocator->GetRequestSize() > fPort.GetCapacity()) { 81 RETURN_ERROR(B_BAD_VALUE); 82 } 83 allocator->FinishDeferredInit(); 84//PRINT(("RequestPort::SendRequest(%lu)\n", allocator->GetRequest()->GetType())); 85#if USER && !KERNEL_EMU 86 if (!is_userland_request(allocator->GetRequest()->GetType())) { 87 ERROR(("RequestPort::SendRequest(%lu): request is not a userland " 88 "request\n", allocator->GetRequest()->GetType())); 89 debugger("Request is not a userland request."); 90 } 91#else 92 if (!is_kernel_request(allocator->GetRequest()->GetType())) { 93 ERROR(("RequestPort::SendRequest(%lu): request is not a userland " 94 "request\n", allocator->GetRequest()->GetType())); 95 debugger("Request is not a userland request."); 96 } 97#endif 98 RETURN_ERROR(fPort.Send(allocator->GetRequestSize())); 99} 100 101// SendRequest 102status_t 103RequestPort::SendRequest(RequestAllocator* allocator, 104 RequestHandler* handler, Request** reply, bigtime_t timeout) 105{ 106 status_t error = SendRequest(allocator); 107 if (error != B_OK) 108 return error; 109 return HandleRequests(handler, reply, timeout); 110} 111 112// ReceiveRequest 113// 114// The caller is responsible for calling ReleaseRequest() with the request. 115status_t 116RequestPort::ReceiveRequest(Request** request, bigtime_t timeout) 117{ 118 // check initialization and parameters 119 if (InitCheck() != B_OK) 120 RETURN_ERROR(InitCheck()); 121 if (!request) 122 RETURN_ERROR(B_BAD_VALUE); 123 // allocate a request allocator 124 AllocatorNode* node = new(nothrow) AllocatorNode(&fPort); 125 if (!node) 126 RETURN_ERROR(B_NO_MEMORY); 127 ObjectDeleter<AllocatorNode> deleter(node); 128 // receive the message 129 status_t error = fPort.Receive(timeout); 130 if (error != B_OK) { 131 if (error != B_TIMED_OUT && error != B_WOULD_BLOCK) 132 RETURN_ERROR(error); 133 return error; 134 } 135 // allocate the request 136 error = node->allocator.ReadRequest(); 137 if (error != B_OK) 138 RETURN_ERROR(error); 139 // everything went fine: push the allocator 140 *request = node->allocator.GetRequest(); 141 node->previous = fCurrentAllocatorNode; 142 fCurrentAllocatorNode = node; 143 deleter.Detach(); 144//PRINT(("RequestPort::RequestReceived(%lu)\n", (*request)->GetType())); 145 return B_OK; 146} 147 148// HandleRequests 149// 150// If request is not NULL, the caller is responsible for calling 151// ReleaseRequest() with the request. If it is NULL, the request will already 152// be gone, when the method returns. 153status_t 154RequestPort::HandleRequests(RequestHandler* handler, Request** request, 155 bigtime_t timeout) 156{ 157 // check initialization and parameters 158 if (InitCheck() != B_OK) 159 RETURN_ERROR(InitCheck()); 160 if (!handler) 161 RETURN_ERROR(B_BAD_VALUE); 162 handler->SetPort(this); 163 Request* currentRequest = NULL; 164 do { 165 if (currentRequest) 166 ReleaseRequest(currentRequest); 167 status_t error = ReceiveRequest(¤tRequest, timeout); 168 if (error != B_OK) 169 return error; 170 // handle the request 171 error = handler->HandleRequest(currentRequest); 172 if (error != B_OK) { 173 ReleaseRequest(currentRequest); 174 RETURN_ERROR(error); 175 } 176 } while (!handler->IsDone()); 177 if (request) 178 *request = currentRequest; 179 else 180 ReleaseRequest(currentRequest); 181 return B_OK; 182} 183 184// ReleaseRequest 185void 186RequestPort::ReleaseRequest(Request* request) 187{ 188 if (request && fCurrentAllocatorNode 189 && request == fCurrentAllocatorNode->allocator.GetRequest()) { 190 _PopAllocator(); 191 } 192} 193 194// _PopAllocator 195void 196RequestPort::_PopAllocator() 197{ 198 if (fCurrentAllocatorNode) { 199 AllocatorNode* node = fCurrentAllocatorNode->previous; 200 delete fCurrentAllocatorNode; 201 fCurrentAllocatorNode = node; 202 } 203} 204 205