160f4376eSIngo Weinhold /*
260f4376eSIngo Weinhold * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
360f4376eSIngo Weinhold * Distributed under the terms of the MIT License.
460f4376eSIngo Weinhold */
583812f67SIngo Weinhold
683812f67SIngo Weinhold #include <new>
783812f67SIngo Weinhold
860f4376eSIngo Weinhold #include <AutoDeleter.h>
960f4376eSIngo Weinhold
1083812f67SIngo Weinhold #include "AreaSupport.h"
1183812f67SIngo Weinhold #include "Compatibility.h"
1283812f67SIngo Weinhold #include "Port.h"
1383812f67SIngo Weinhold
14c1f05b28SIngo Weinhold
156aeea78cSIngo Weinhold using std::nothrow;
166aeea78cSIngo Weinhold
1783812f67SIngo Weinhold // minimal and maximal port size
1883812f67SIngo Weinhold static const int32 kMinPortSize = 1024; // 1 kB
1983812f67SIngo Weinhold static const int32 kMaxPortSize = 64 * 1024; // 64 kB
2083812f67SIngo Weinhold
21c1f05b28SIngo Weinhold
2283812f67SIngo Weinhold // constructor
Port(int32 size)2383812f67SIngo Weinhold Port::Port(int32 size)
24*b19ee1e1SIngo Weinhold :
25*b19ee1e1SIngo Weinhold fBuffer(NULL),
2683812f67SIngo Weinhold fCapacity(0),
27*b19ee1e1SIngo Weinhold fReservedSize(0),
2883812f67SIngo Weinhold fInitStatus(B_NO_INIT),
2983812f67SIngo Weinhold fOwner(true)
3083812f67SIngo Weinhold {
3183812f67SIngo Weinhold // adjust size to be within the sane bounds
3283812f67SIngo Weinhold if (size < kMinPortSize)
3383812f67SIngo Weinhold size = kMinPortSize;
3483812f67SIngo Weinhold else if (size > kMaxPortSize)
3583812f67SIngo Weinhold size = kMaxPortSize;
3683812f67SIngo Weinhold // allocate the buffer
3783812f67SIngo Weinhold fBuffer = new(nothrow) uint8[size];
3883812f67SIngo Weinhold if (!fBuffer) {
3983812f67SIngo Weinhold fInitStatus = B_NO_MEMORY;
4083812f67SIngo Weinhold return;
4183812f67SIngo Weinhold }
4283812f67SIngo Weinhold // create the owner port
4383812f67SIngo Weinhold fInfo.owner_port = create_port(1, "port owner port");
4483812f67SIngo Weinhold if (fInfo.owner_port < 0) {
4583812f67SIngo Weinhold fInitStatus = fInfo.owner_port;
4683812f67SIngo Weinhold return;
4783812f67SIngo Weinhold }
4883812f67SIngo Weinhold // create the client port
4983812f67SIngo Weinhold fInfo.client_port = create_port(1, "port client port");
5083812f67SIngo Weinhold if (fInfo.client_port < 0) {
5183812f67SIngo Weinhold fInitStatus = fInfo.client_port;
5283812f67SIngo Weinhold return;
5383812f67SIngo Weinhold }
5483812f67SIngo Weinhold fInfo.size = size;
5583812f67SIngo Weinhold fCapacity = size;
5683812f67SIngo Weinhold fInitStatus = B_OK;
5783812f67SIngo Weinhold }
5883812f67SIngo Weinhold
59c1f05b28SIngo Weinhold
6083812f67SIngo Weinhold // constructor
Port(const Info * info)6183812f67SIngo Weinhold Port::Port(const Info* info)
62*b19ee1e1SIngo Weinhold :
63*b19ee1e1SIngo Weinhold fBuffer(NULL),
6483812f67SIngo Weinhold fCapacity(0),
65*b19ee1e1SIngo Weinhold fReservedSize(0),
6683812f67SIngo Weinhold fInitStatus(B_NO_INIT),
6783812f67SIngo Weinhold fOwner(false)
6883812f67SIngo Weinhold {
6983812f67SIngo Weinhold // check parameters
7083812f67SIngo Weinhold if (!info || info->owner_port < 0 || info->client_port < 0
7183812f67SIngo Weinhold || info->size < kMinPortSize || info->size > kMaxPortSize) {
7283812f67SIngo Weinhold return;
7383812f67SIngo Weinhold }
7483812f67SIngo Weinhold // allocate the buffer
7583812f67SIngo Weinhold fBuffer = new(nothrow) uint8[info->size];
7683812f67SIngo Weinhold if (!fBuffer) {
7783812f67SIngo Weinhold fInitStatus = B_NO_MEMORY;
7883812f67SIngo Weinhold return;
7983812f67SIngo Weinhold }
8083812f67SIngo Weinhold // init the info
8183812f67SIngo Weinhold fInfo.owner_port = info->owner_port;
8283812f67SIngo Weinhold fInfo.client_port = info->client_port;
8383812f67SIngo Weinhold fInfo.size = info->size;
8483812f67SIngo Weinhold // init the other members
8583812f67SIngo Weinhold fCapacity = info->size;
8683812f67SIngo Weinhold fInitStatus = B_OK;
8783812f67SIngo Weinhold }
8883812f67SIngo Weinhold
89c1f05b28SIngo Weinhold
9083812f67SIngo Weinhold // destructor
~Port()9183812f67SIngo Weinhold Port::~Port()
9283812f67SIngo Weinhold {
9383812f67SIngo Weinhold Close();
9483812f67SIngo Weinhold delete[] fBuffer;
9583812f67SIngo Weinhold }
9683812f67SIngo Weinhold
97c1f05b28SIngo Weinhold
9883812f67SIngo Weinhold // Close
9983812f67SIngo Weinhold void
Close()10083812f67SIngo Weinhold Port::Close()
10183812f67SIngo Weinhold {
10283812f67SIngo Weinhold if (fInitStatus != B_OK)
10383812f67SIngo Weinhold return;
10483812f67SIngo Weinhold fInitStatus = B_NO_INIT;
10583812f67SIngo Weinhold // delete the ports only if we are the owner
10683812f67SIngo Weinhold if (fOwner) {
10783812f67SIngo Weinhold if (fInfo.owner_port >= 0)
10883812f67SIngo Weinhold delete_port(fInfo.owner_port);
10983812f67SIngo Weinhold if (fInfo.client_port >= 0)
11083812f67SIngo Weinhold delete_port(fInfo.client_port);
11183812f67SIngo Weinhold }
11283812f67SIngo Weinhold fInfo.owner_port = -1;
11383812f67SIngo Weinhold fInfo.client_port = -1;
11483812f67SIngo Weinhold }
11583812f67SIngo Weinhold
116c1f05b28SIngo Weinhold
11783812f67SIngo Weinhold // InitCheck
11883812f67SIngo Weinhold status_t
InitCheck() const11983812f67SIngo Weinhold Port::InitCheck() const
12083812f67SIngo Weinhold {
12183812f67SIngo Weinhold return fInitStatus;
12283812f67SIngo Weinhold }
12383812f67SIngo Weinhold
124c1f05b28SIngo Weinhold
12583812f67SIngo Weinhold // GetInfo
12683812f67SIngo Weinhold const Port::Info*
GetInfo() const12783812f67SIngo Weinhold Port::GetInfo() const
12883812f67SIngo Weinhold {
12983812f67SIngo Weinhold return &fInfo;
13083812f67SIngo Weinhold }
13183812f67SIngo Weinhold
132c1f05b28SIngo Weinhold
133*b19ee1e1SIngo Weinhold // Reserve
134*b19ee1e1SIngo Weinhold void
Reserve(int32 endOffset)135*b19ee1e1SIngo Weinhold Port::Reserve(int32 endOffset)
13683812f67SIngo Weinhold {
137*b19ee1e1SIngo Weinhold if (endOffset > fReservedSize)
138*b19ee1e1SIngo Weinhold fReservedSize = endOffset;
13983812f67SIngo Weinhold }
14083812f67SIngo Weinhold
141c1f05b28SIngo Weinhold
142*b19ee1e1SIngo Weinhold // Unreserve
143*b19ee1e1SIngo Weinhold void
Unreserve(int32 endOffset)144*b19ee1e1SIngo Weinhold Port::Unreserve(int32 endOffset)
14583812f67SIngo Weinhold {
146*b19ee1e1SIngo Weinhold if (endOffset < fReservedSize)
147*b19ee1e1SIngo Weinhold fReservedSize = endOffset;
14883812f67SIngo Weinhold }
14983812f67SIngo Weinhold
15083812f67SIngo Weinhold
15183812f67SIngo Weinhold // Send
15283812f67SIngo Weinhold status_t
Send(const void * message,int32 size)153*b19ee1e1SIngo Weinhold Port::Send(const void* message, int32 size)
15483812f67SIngo Weinhold {
15583812f67SIngo Weinhold if (fInitStatus != B_OK)
15683812f67SIngo Weinhold return fInitStatus;
157*b19ee1e1SIngo Weinhold if (size <= 0)
15883812f67SIngo Weinhold return B_BAD_VALUE;
159*b19ee1e1SIngo Weinhold
16083812f67SIngo Weinhold port_id port = (fOwner ? fInfo.client_port : fInfo.owner_port);
16183812f67SIngo Weinhold status_t error;
16283812f67SIngo Weinhold do {
163*b19ee1e1SIngo Weinhold error = write_port(port, 0, message, size);
16483812f67SIngo Weinhold } while (error == B_INTERRUPTED);
165*b19ee1e1SIngo Weinhold
16683812f67SIngo Weinhold return (fInitStatus = error);
16783812f67SIngo Weinhold }
16883812f67SIngo Weinhold
16983812f67SIngo Weinhold
17083812f67SIngo Weinhold // Receive
17183812f67SIngo Weinhold status_t
Receive(void ** _message,size_t * _size,bigtime_t timeout)17260f4376eSIngo Weinhold Port::Receive(void** _message, size_t* _size, bigtime_t timeout)
17383812f67SIngo Weinhold {
17483812f67SIngo Weinhold if (fInitStatus != B_OK)
17583812f67SIngo Weinhold return fInitStatus;
17660f4376eSIngo Weinhold
17760f4376eSIngo Weinhold // convert to timeout to flags + timeout we can use in the loop
17860f4376eSIngo Weinhold uint32 timeoutFlags = 0;
17960f4376eSIngo Weinhold if (timeout < 0) {
18060f4376eSIngo Weinhold timeout = 0;
18160f4376eSIngo Weinhold } else if (timeout == 0) {
18260f4376eSIngo Weinhold timeoutFlags = B_RELATIVE_TIMEOUT;
18360f4376eSIngo Weinhold } else if (timeout >= 0) {
18460f4376eSIngo Weinhold timeout += system_time();
18560f4376eSIngo Weinhold timeoutFlags = B_ABSOLUTE_TIMEOUT;
18683812f67SIngo Weinhold }
18783812f67SIngo Weinhold
18860f4376eSIngo Weinhold port_id port = (fOwner ? fInfo.owner_port : fInfo.client_port);
18960f4376eSIngo Weinhold
19060f4376eSIngo Weinhold // wait for the next message
19160f4376eSIngo Weinhold status_t error = B_OK;
19260f4376eSIngo Weinhold ssize_t bufferSize;
19360f4376eSIngo Weinhold do {
19460f4376eSIngo Weinhold // TODO: When compiling for userland, we might want to save this syscall
19560f4376eSIngo Weinhold // by using read_port_etc() directly, using a sufficiently large
19660f4376eSIngo Weinhold // on-stack buffer and copying onto the heap.
19760f4376eSIngo Weinhold bufferSize = port_buffer_size_etc(port, timeoutFlags, timeout);
19860f4376eSIngo Weinhold if (bufferSize < 0)
19960f4376eSIngo Weinhold error = bufferSize;
20060f4376eSIngo Weinhold } while (error == B_INTERRUPTED);
20160f4376eSIngo Weinhold
20260f4376eSIngo Weinhold if (error == B_TIMED_OUT || error == B_WOULD_BLOCK)
20360f4376eSIngo Weinhold return error;
20460f4376eSIngo Weinhold if (error != B_OK)
20560f4376eSIngo Weinhold return (fInitStatus = error);
20660f4376eSIngo Weinhold
20760f4376eSIngo Weinhold // allocate memory for the message
20860f4376eSIngo Weinhold void* message = malloc(bufferSize);
20960f4376eSIngo Weinhold if (message == NULL)
21060f4376eSIngo Weinhold return (fInitStatus = B_NO_MEMORY);
21160f4376eSIngo Weinhold MemoryDeleter messageDeleter(message);
21260f4376eSIngo Weinhold
21360f4376eSIngo Weinhold // read the message
21460f4376eSIngo Weinhold int32 code;
21560f4376eSIngo Weinhold ssize_t bytesRead = read_port_etc(port, &code, message, bufferSize,
21660f4376eSIngo Weinhold B_RELATIVE_TIMEOUT, 0);
21760f4376eSIngo Weinhold if (bytesRead < 0)
21860f4376eSIngo Weinhold return fInitStatus = bytesRead;
21960f4376eSIngo Weinhold if (bytesRead != bufferSize)
22060f4376eSIngo Weinhold return fInitStatus = B_BAD_DATA;
22160f4376eSIngo Weinhold
22260f4376eSIngo Weinhold messageDeleter.Detach();
22360f4376eSIngo Weinhold *_message = message;
22460f4376eSIngo Weinhold *_size = bytesRead;
22560f4376eSIngo Weinhold
22660f4376eSIngo Weinhold return B_OK;
22760f4376eSIngo Weinhold }
228