1// RequestPortPool.cpp
2
3#include "RequestPortPool.h"
4
5#include <stdlib.h>
6
7#include "AutoLocker.h"
8#include "Debug.h"
9#include "RequestPort.h"
10
11typedef AutoLocker<RequestPortPool> PoolLocker;
12
13// constructor
14RequestPortPool::RequestPortPool()
15	: fPorts(NULL),
16	  fPortCount(0),
17	  fFreePorts(0),
18	  fFreePortSemaphore(-1),
19	  fDisconnected(false)
20{
21	fFreePortSemaphore = create_sem(0, "request port pool");
22}
23
24// destructor
25RequestPortPool::~RequestPortPool()
26{
27	delete_sem(fFreePortSemaphore);
28	free(fPorts);
29}
30
31// InitCheck
32status_t
33RequestPortPool::InitCheck() const
34{
35	if (fFreePortSemaphore < 0)
36		return fFreePortSemaphore;
37	return B_OK;
38}
39
40// IsDisconnected
41bool
42RequestPortPool::IsDisconnected() const
43{
44	return fDisconnected;
45}
46
47// AddPort
48status_t
49RequestPortPool::AddPort(RequestPort* port)
50{
51	if (!port)
52		return B_BAD_VALUE;
53	PoolLocker _(this);
54	// resize the port array
55	PortAcquirationInfo* ports = (PortAcquirationInfo*)realloc(fPorts,
56		(fPortCount + 1) * sizeof(PortAcquirationInfo));
57	if (!ports)
58		return B_NO_MEMORY;
59	fPorts = ports;
60	// add the port as used port and let AcquirePort() free it
61	fPorts[fPortCount].port = port;
62	fPorts[fPortCount].owner = -1;
63	fPorts[fPortCount].count = 1;
64	fPortCount++;
65	ReleasePort(port);
66	return B_OK;
67}
68
69// AcquirePort
70RequestPort*
71RequestPortPool::AcquirePort()
72{
73	// first check whether the thread does already own a port
74	thread_id thread = find_thread(NULL);
75	{
76		PoolLocker _(this);
77		if (fDisconnected)
78			return NULL;
79		for (int32 i = fFreePorts; i < fPortCount; i++) {
80			PortAcquirationInfo& info = fPorts[i];
81			if (info.owner == thread) {
82				info.count++;
83				return info.port;
84			}
85		}
86	}
87	// the thread doesn't own a port yet, find a free one
88	status_t error = acquire_sem(fFreePortSemaphore);
89	if (error != B_OK)
90		return NULL;
91	PoolLocker _(this);
92	if (fDisconnected)
93		return NULL;
94	if (fFreePorts < 1) {
95		FATAL(("Inconsistent request port pool: We acquired the free port "
96			"semaphore, but there are no free ports.\n"));
97		return NULL;
98	}
99	PortAcquirationInfo& info = fPorts[--fFreePorts];
100	info.owner = find_thread(NULL);
101	info.count = 1;
102	return info.port;
103}
104
105// ReleasePort
106void
107RequestPortPool::ReleasePort(RequestPort* port)
108{
109	if (!port)
110		return;
111	PoolLocker _(this);
112	// find the port
113	for (int32 i = fFreePorts; i < fPortCount; i++) {
114		PortAcquirationInfo& info = fPorts[i];
115		if (info.port == port) {
116			if (--info.count == 0) {
117				// swap with first used port
118				if (i != fFreePorts) {
119					fPorts[i] = fPorts[fFreePorts];
120					fPorts[fFreePorts].port = port;
121				}
122				fFreePorts++;
123				release_sem(fFreePortSemaphore);
124			}
125			if (port->InitCheck() != B_OK)
126				fDisconnected = true;
127			return;
128		}
129	}
130	WARN(("RequestPortPool::ReleasePort(%p): port not found\n", port));
131	// Not found!
132}
133
134