xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/RequestPortPool.cpp (revision 6aeea78c6e84f6f415b8de776135ccf5b5676bd1)
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 
11 typedef AutoLocker<RequestPortPool> PoolLocker;
12 
13 // constructor
RequestPortPool()14 RequestPortPool::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
~RequestPortPool()25 RequestPortPool::~RequestPortPool()
26 {
27 	delete_sem(fFreePortSemaphore);
28 	free(fPorts);
29 }
30 
31 // InitCheck
32 status_t
InitCheck() const33 RequestPortPool::InitCheck() const
34 {
35 	if (fFreePortSemaphore < 0)
36 		return fFreePortSemaphore;
37 	return B_OK;
38 }
39 
40 // IsDisconnected
41 bool
IsDisconnected() const42 RequestPortPool::IsDisconnected() const
43 {
44 	return fDisconnected;
45 }
46 
47 // AddPort
48 status_t
AddPort(RequestPort * port)49 RequestPortPool::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
70 RequestPort*
AcquirePort()71 RequestPortPool::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
106 void
ReleasePort(RequestPort * port)107 RequestPortPool::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