xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/private/Port.cpp (revision b19ee1e164ffad53dff3600cdac7e9781c636581)
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