xref: /haiku/src/system/kernel/port.cpp (revision c3bc71d6e23aef3299cc021cc53b271d3e885b4c)
1224aee3fSIngo Weinhold /*
251755cf8SAxel Dörfler  * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
3224aee3fSIngo Weinhold  * Distributed under the terms of the MIT License.
4224aee3fSIngo Weinhold  *
5224aee3fSIngo Weinhold  * Copyright 2001, Mark-Jan Bastian. All rights reserved.
6224aee3fSIngo Weinhold  * Distributed under the terms of the NewOS License.
7224aee3fSIngo Weinhold  */
8224aee3fSIngo Weinhold 
9f28dd36bSAxel Dörfler 
10224aee3fSIngo Weinhold /*!	Ports for IPC */
11224aee3fSIngo Weinhold 
12f28dd36bSAxel Dörfler 
134048494cSIngo Weinhold #include <port.h>
144048494cSIngo Weinhold 
154048494cSIngo Weinhold #include <ctype.h>
164048494cSIngo Weinhold #include <iovec.h>
174048494cSIngo Weinhold #include <stdlib.h>
184048494cSIngo Weinhold #include <string.h>
19224aee3fSIngo Weinhold 
20224aee3fSIngo Weinhold #include <OS.h>
21224aee3fSIngo Weinhold 
22224aee3fSIngo Weinhold #include <arch/int.h>
23e8885f20SAxel Dörfler #include <heap.h>
244048494cSIngo Weinhold #include <kernel.h>
2551755cf8SAxel Dörfler #include <Notifications.h>
264048494cSIngo Weinhold #include <sem.h>
274048494cSIngo Weinhold #include <syscall_restart.h>
284048494cSIngo Weinhold #include <team.h>
29f28dd36bSAxel Dörfler #include <tracing.h>
30b4ec7b8eSIngo Weinhold #include <util/AutoLock.h>
314048494cSIngo Weinhold #include <util/list.h>
32224aee3fSIngo Weinhold #include <wait_for_objects.h>
33224aee3fSIngo Weinhold 
34224aee3fSIngo Weinhold 
35224aee3fSIngo Weinhold //#define TRACE_PORTS
36224aee3fSIngo Weinhold #ifdef TRACE_PORTS
37224aee3fSIngo Weinhold #	define TRACE(x) dprintf x
38224aee3fSIngo Weinhold #else
39224aee3fSIngo Weinhold #	define TRACE(x)
40224aee3fSIngo Weinhold #endif
41224aee3fSIngo Weinhold 
42224aee3fSIngo Weinhold 
43e8885f20SAxel Dörfler struct port_message : DoublyLinkedListLinkImpl<port_message> {
44224aee3fSIngo Weinhold 	int32				code;
45224aee3fSIngo Weinhold 	size_t				size;
467727e08eSIngo Weinhold 	uid_t				sender;
477727e08eSIngo Weinhold 	gid_t				sender_group;
487727e08eSIngo Weinhold 	team_id				sender_team;
49e8885f20SAxel Dörfler 	char				buffer[0];
50e8885f20SAxel Dörfler };
51e8885f20SAxel Dörfler 
52e8885f20SAxel Dörfler typedef DoublyLinkedList<port_message> MessageList;
53224aee3fSIngo Weinhold 
54224aee3fSIngo Weinhold struct port_entry {
5586a999adSAxel Dörfler 	struct list_link	team_link;
56224aee3fSIngo Weinhold 	port_id				id;
57224aee3fSIngo Weinhold 	team_id				owner;
58224aee3fSIngo Weinhold 	int32		 		capacity;
59e8885f20SAxel Dörfler 	mutex				lock;
607d592ec4SAxel Dörfler 	uint32				read_count;
61e8885f20SAxel Dörfler 	int32				write_count;
62e8885f20SAxel Dörfler 	ConditionVariable	read_condition;
63e8885f20SAxel Dörfler 	ConditionVariable	write_condition;
64e8885f20SAxel Dörfler 	int32				total_count;
65e8885f20SAxel Dörfler 		// messages read from port since creation
66224aee3fSIngo Weinhold 	select_info*		select_infos;
67e8885f20SAxel Dörfler 	MessageList			messages;
68224aee3fSIngo Weinhold };
69224aee3fSIngo Weinhold 
7051755cf8SAxel Dörfler class PortNotificationService : public DefaultNotificationService {
7151755cf8SAxel Dörfler public:
7251755cf8SAxel Dörfler 							PortNotificationService();
7351755cf8SAxel Dörfler 
7451755cf8SAxel Dörfler 			void			Notify(uint32 opcode, port_id team);
7551755cf8SAxel Dörfler };
76224aee3fSIngo Weinhold 
77f28dd36bSAxel Dörfler 
78f28dd36bSAxel Dörfler #if PORT_TRACING
79f28dd36bSAxel Dörfler namespace PortTracing {
80f28dd36bSAxel Dörfler 
81f28dd36bSAxel Dörfler class Create : public AbstractTraceEntry {
82f28dd36bSAxel Dörfler public:
83f28dd36bSAxel Dörfler 	Create(port_entry& port)
84f28dd36bSAxel Dörfler 		:
85f28dd36bSAxel Dörfler 		fID(port.id),
86f28dd36bSAxel Dörfler 		fOwner(port.owner),
87f28dd36bSAxel Dörfler 		fCapacity(port.capacity)
88f28dd36bSAxel Dörfler 	{
89f28dd36bSAxel Dörfler 		fName = alloc_tracing_buffer_strcpy(port.lock.name, B_OS_NAME_LENGTH,
90f28dd36bSAxel Dörfler 			false);
91f28dd36bSAxel Dörfler 
92f28dd36bSAxel Dörfler 		Initialized();
93f28dd36bSAxel Dörfler 	}
94f28dd36bSAxel Dörfler 
95f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
96f28dd36bSAxel Dörfler 	{
97f28dd36bSAxel Dörfler 		out.Print("port %ld created, name \"%s\", owner %ld, capacity %ld",
98f28dd36bSAxel Dörfler 			fID, fName, fOwner, fCapacity);
99f28dd36bSAxel Dörfler 	}
100f28dd36bSAxel Dörfler 
101f28dd36bSAxel Dörfler private:
102f28dd36bSAxel Dörfler 	port_id				fID;
103f28dd36bSAxel Dörfler 	char*				fName;
104f28dd36bSAxel Dörfler 	team_id				fOwner;
105f28dd36bSAxel Dörfler 	int32		 		fCapacity;
106f28dd36bSAxel Dörfler };
107f28dd36bSAxel Dörfler 
108f28dd36bSAxel Dörfler 
109f28dd36bSAxel Dörfler class Delete : public AbstractTraceEntry {
110f28dd36bSAxel Dörfler public:
111f28dd36bSAxel Dörfler 	Delete(port_entry& port)
112f28dd36bSAxel Dörfler 		:
113f28dd36bSAxel Dörfler 		fID(port.id)
114f28dd36bSAxel Dörfler 	{
115f28dd36bSAxel Dörfler 		Initialized();
116f28dd36bSAxel Dörfler 	}
117f28dd36bSAxel Dörfler 
118f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
119f28dd36bSAxel Dörfler 	{
120f28dd36bSAxel Dörfler 		out.Print("port %ld deleted", fID);
121f28dd36bSAxel Dörfler 	}
122f28dd36bSAxel Dörfler 
123f28dd36bSAxel Dörfler private:
124f28dd36bSAxel Dörfler 	port_id				fID;
125f28dd36bSAxel Dörfler };
126f28dd36bSAxel Dörfler 
127f28dd36bSAxel Dörfler 
128f28dd36bSAxel Dörfler class Read : public AbstractTraceEntry {
129f28dd36bSAxel Dörfler public:
130f28dd36bSAxel Dörfler 	Read(port_entry& port, int32 code, ssize_t result)
131f28dd36bSAxel Dörfler 		:
132f28dd36bSAxel Dörfler 		fID(port.id),
133f28dd36bSAxel Dörfler 		fReadCount(port.read_count),
134f28dd36bSAxel Dörfler 		fWriteCount(port.write_count),
135f28dd36bSAxel Dörfler 		fCode(code),
136f28dd36bSAxel Dörfler 		fResult(result)
137f28dd36bSAxel Dörfler 	{
138f28dd36bSAxel Dörfler 		Initialized();
139f28dd36bSAxel Dörfler 	}
140f28dd36bSAxel Dörfler 
141f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
142f28dd36bSAxel Dörfler 	{
143f28dd36bSAxel Dörfler 		out.Print("port %ld read, read %ld, write %ld, code %lx: %ld",
144f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fResult);
145f28dd36bSAxel Dörfler 	}
146f28dd36bSAxel Dörfler 
147f28dd36bSAxel Dörfler private:
148f28dd36bSAxel Dörfler 	port_id				fID;
149f28dd36bSAxel Dörfler 	int32				fReadCount;
150f28dd36bSAxel Dörfler 	int32				fWriteCount;
151f28dd36bSAxel Dörfler 	int32				fCode;
152f28dd36bSAxel Dörfler 	ssize_t				fResult;
153f28dd36bSAxel Dörfler };
154f28dd36bSAxel Dörfler 
155f28dd36bSAxel Dörfler 
156f28dd36bSAxel Dörfler class Write : public AbstractTraceEntry {
157f28dd36bSAxel Dörfler public:
158f28dd36bSAxel Dörfler 	Write(port_entry& port, int32 code, size_t bufferSize, ssize_t result)
159f28dd36bSAxel Dörfler 		:
160f28dd36bSAxel Dörfler 		fID(port.id),
161f28dd36bSAxel Dörfler 		fReadCount(port.read_count),
162f28dd36bSAxel Dörfler 		fWriteCount(port.write_count),
163f28dd36bSAxel Dörfler 		fCode(code),
164f28dd36bSAxel Dörfler 		fBufferSize(bufferSize),
165f28dd36bSAxel Dörfler 		fResult(result)
166f28dd36bSAxel Dörfler 	{
167f28dd36bSAxel Dörfler 		Initialized();
168f28dd36bSAxel Dörfler 	}
169f28dd36bSAxel Dörfler 
170f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
171f28dd36bSAxel Dörfler 	{
172f28dd36bSAxel Dörfler 		out.Print("port %ld write, read %ld, write %ld, code %lx, size %ld: %ld",
173f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fBufferSize, fResult);
174f28dd36bSAxel Dörfler 	}
175f28dd36bSAxel Dörfler 
176f28dd36bSAxel Dörfler private:
177f28dd36bSAxel Dörfler 	port_id				fID;
178f28dd36bSAxel Dörfler 	int32				fReadCount;
179f28dd36bSAxel Dörfler 	int32				fWriteCount;
180f28dd36bSAxel Dörfler 	int32				fCode;
181f28dd36bSAxel Dörfler 	size_t				fBufferSize;
182f28dd36bSAxel Dörfler 	ssize_t				fResult;
183f28dd36bSAxel Dörfler };
184f28dd36bSAxel Dörfler 
185f28dd36bSAxel Dörfler 
186f28dd36bSAxel Dörfler class Info : public AbstractTraceEntry {
187f28dd36bSAxel Dörfler public:
188f28dd36bSAxel Dörfler 	Info(port_entry& port, int32 code, ssize_t result)
189f28dd36bSAxel Dörfler 		:
190f28dd36bSAxel Dörfler 		fID(port.id),
191f28dd36bSAxel Dörfler 		fReadCount(port.read_count),
192f28dd36bSAxel Dörfler 		fWriteCount(port.write_count),
193f28dd36bSAxel Dörfler 		fCode(code),
194f28dd36bSAxel Dörfler 		fResult(result)
195f28dd36bSAxel Dörfler 	{
196f28dd36bSAxel Dörfler 		Initialized();
197f28dd36bSAxel Dörfler 	}
198f28dd36bSAxel Dörfler 
199f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
200f28dd36bSAxel Dörfler 	{
201f28dd36bSAxel Dörfler 		out.Print("port %ld info, read %ld, write %ld, code %lx: %ld",
202f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fResult);
203f28dd36bSAxel Dörfler 	}
204f28dd36bSAxel Dörfler 
205f28dd36bSAxel Dörfler private:
206f28dd36bSAxel Dörfler 	port_id				fID;
207f28dd36bSAxel Dörfler 	int32				fReadCount;
208f28dd36bSAxel Dörfler 	int32				fWriteCount;
209f28dd36bSAxel Dörfler 	int32				fCode;
210f28dd36bSAxel Dörfler 	ssize_t				fResult;
211f28dd36bSAxel Dörfler };
212f28dd36bSAxel Dörfler 
213f28dd36bSAxel Dörfler 
214f28dd36bSAxel Dörfler class OwnerChange : public AbstractTraceEntry {
215f28dd36bSAxel Dörfler public:
216f28dd36bSAxel Dörfler 	OwnerChange(port_entry& port, team_id newOwner, status_t status)
217f28dd36bSAxel Dörfler 		:
218f28dd36bSAxel Dörfler 		fID(port.id),
219f28dd36bSAxel Dörfler 		fOldOwner(port.owner),
220f28dd36bSAxel Dörfler 		fNewOwner(newOwner),
221f28dd36bSAxel Dörfler 		fStatus(status)
222f28dd36bSAxel Dörfler 	{
223f28dd36bSAxel Dörfler 		Initialized();
224f28dd36bSAxel Dörfler 	}
225f28dd36bSAxel Dörfler 
226f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
227f28dd36bSAxel Dörfler 	{
228f28dd36bSAxel Dörfler 		out.Print("port %ld owner change from %ld to %ld: %s", fID, fOldOwner,
229f28dd36bSAxel Dörfler 			fNewOwner, strerror(fStatus));
230f28dd36bSAxel Dörfler 	}
231f28dd36bSAxel Dörfler 
232f28dd36bSAxel Dörfler private:
233f28dd36bSAxel Dörfler 	port_id				fID;
234f28dd36bSAxel Dörfler 	team_id				fOldOwner;
235f28dd36bSAxel Dörfler 	team_id				fNewOwner;
236f28dd36bSAxel Dörfler 	status_t	 		fStatus;
237f28dd36bSAxel Dörfler };
238f28dd36bSAxel Dörfler 
239f28dd36bSAxel Dörfler }	// namespace PortTracing
240f28dd36bSAxel Dörfler 
241f28dd36bSAxel Dörfler #	define T(x) new(std::nothrow) PortTracing::x;
242f28dd36bSAxel Dörfler #else
243f28dd36bSAxel Dörfler #	define T(x) ;
244f28dd36bSAxel Dörfler #endif
245f28dd36bSAxel Dörfler 
246f28dd36bSAxel Dörfler 
247e8885f20SAxel Dörfler static const size_t kInitialPortBufferSize = 4 * 1024 * 1024;
248f28dd36bSAxel Dörfler static const size_t kTotalSpaceLimit = 64 * 1024 * 1024;
249f28dd36bSAxel Dörfler static const size_t kTeamSpaceLimit = 8 * 1024 * 1024;
250f28dd36bSAxel Dörfler static const size_t kBufferGrowRate = kInitialPortBufferSize;
251f28dd36bSAxel Dörfler 
252224aee3fSIngo Weinhold #define MAX_QUEUE_LENGTH 4096
2535f87692cSIngo Weinhold #define PORT_MAX_MESSAGE_SIZE (256 * 1024)
254224aee3fSIngo Weinhold 
255224aee3fSIngo Weinhold // sMaxPorts must be power of 2
256224aee3fSIngo Weinhold static int32 sMaxPorts = 4096;
257224aee3fSIngo Weinhold static int32 sUsedPorts = 0;
258224aee3fSIngo Weinhold 
259e8885f20SAxel Dörfler static struct port_entry* sPorts;
260e8885f20SAxel Dörfler static area_id sPortArea;
261e8885f20SAxel Dörfler static heap_allocator* sPortAllocator;
262f28dd36bSAxel Dörfler static ConditionVariable sNoSpaceCondition;
263f28dd36bSAxel Dörfler static vint32 sTotalSpaceInUse;
264f28dd36bSAxel Dörfler static vint32 sAreaChangeCounter;
265f28dd36bSAxel Dörfler static vint32 sAllocatingArea;
266224aee3fSIngo Weinhold static bool sPortsActive = false;
267224aee3fSIngo Weinhold static port_id sNextPort = 1;
268224aee3fSIngo Weinhold static int32 sFirstFreeSlot = 1;
269e8885f20SAxel Dörfler static mutex sPortsLock = MUTEX_INITIALIZER("ports list");
270224aee3fSIngo Weinhold 
27151755cf8SAxel Dörfler static PortNotificationService sNotificationService;
27251755cf8SAxel Dörfler 
273224aee3fSIngo Weinhold 
27451755cf8SAxel Dörfler //	#pragma mark - TeamNotificationService
27551755cf8SAxel Dörfler 
27651755cf8SAxel Dörfler 
27751755cf8SAxel Dörfler PortNotificationService::PortNotificationService()
278e8885f20SAxel Dörfler 	:
279e8885f20SAxel Dörfler 	DefaultNotificationService("ports")
28051755cf8SAxel Dörfler {
28151755cf8SAxel Dörfler }
28251755cf8SAxel Dörfler 
28351755cf8SAxel Dörfler 
28451755cf8SAxel Dörfler void
28551755cf8SAxel Dörfler PortNotificationService::Notify(uint32 opcode, port_id port)
28651755cf8SAxel Dörfler {
28751755cf8SAxel Dörfler 	char eventBuffer[64];
28851755cf8SAxel Dörfler 	KMessage event;
28951755cf8SAxel Dörfler 	event.SetTo(eventBuffer, sizeof(eventBuffer), PORT_MONITOR);
290efd536ffSIngo Weinhold 	event.AddInt32("event", opcode);
29151755cf8SAxel Dörfler 	event.AddInt32("port", port);
29251755cf8SAxel Dörfler 
293efd536ffSIngo Weinhold 	DefaultNotificationService::Notify(event, opcode);
29451755cf8SAxel Dörfler }
29551755cf8SAxel Dörfler 
29651755cf8SAxel Dörfler 
29751755cf8SAxel Dörfler //	#pragma mark -
29851755cf8SAxel Dörfler 
29951755cf8SAxel Dörfler 
300224aee3fSIngo Weinhold static int
301224aee3fSIngo Weinhold dump_port_list(int argc, char** argv)
302224aee3fSIngo Weinhold {
303224aee3fSIngo Weinhold 	const char* name = NULL;
304224aee3fSIngo Weinhold 	team_id owner = -1;
305224aee3fSIngo Weinhold 	int32 i;
306224aee3fSIngo Weinhold 
307224aee3fSIngo Weinhold 	if (argc > 2) {
308224aee3fSIngo Weinhold 		if (!strcmp(argv[1], "team") || !strcmp(argv[1], "owner"))
309224aee3fSIngo Weinhold 			owner = strtoul(argv[2], NULL, 0);
310224aee3fSIngo Weinhold 		else if (!strcmp(argv[1], "name"))
311224aee3fSIngo Weinhold 			name = argv[2];
312224aee3fSIngo Weinhold 	} else if (argc > 1)
313224aee3fSIngo Weinhold 		owner = strtoul(argv[1], NULL, 0);
314224aee3fSIngo Weinhold 
315e8885f20SAxel Dörfler 	kprintf("port             id  cap  read-cnt  write-cnt   total   team  "
316e8885f20SAxel Dörfler 		"name\n");
317224aee3fSIngo Weinhold 
318224aee3fSIngo Weinhold 	for (i = 0; i < sMaxPorts; i++) {
319224aee3fSIngo Weinhold 		struct port_entry* port = &sPorts[i];
320224aee3fSIngo Weinhold 		if (port->id < 0
321224aee3fSIngo Weinhold 			|| (owner != -1 && port->owner != owner)
322e8885f20SAxel Dörfler 			|| (name != NULL && strstr(port->lock.name, name) == NULL))
323224aee3fSIngo Weinhold 			continue;
324224aee3fSIngo Weinhold 
325e8885f20SAxel Dörfler 		kprintf("%p %8ld %4ld %9ld %9ld %8ld %6ld  %s\n", port,
326e8885f20SAxel Dörfler 			port->id, port->capacity, port->read_count, port->write_count,
327e8885f20SAxel Dörfler 			port->total_count, port->owner, port->lock.name);
328224aee3fSIngo Weinhold 	}
329e8885f20SAxel Dörfler 
330224aee3fSIngo Weinhold 	return 0;
331224aee3fSIngo Weinhold }
332224aee3fSIngo Weinhold 
333224aee3fSIngo Weinhold 
334224aee3fSIngo Weinhold static void
335224aee3fSIngo Weinhold _dump_port_info(struct port_entry* port)
336224aee3fSIngo Weinhold {
337224aee3fSIngo Weinhold 	kprintf("PORT: %p\n", port);
3383cad4daeSMarcus Overhagen 	kprintf(" id:              %ld\n", port->id);
339e8885f20SAxel Dörfler 	kprintf(" name:            \"%s\"\n", port->lock.name);
3403cad4daeSMarcus Overhagen 	kprintf(" owner:           %ld\n", port->owner);
341224aee3fSIngo Weinhold 	kprintf(" capacity:        %ld\n", port->capacity);
342e8885f20SAxel Dörfler 	kprintf(" read_count:      %ld\n", port->read_count);
343e8885f20SAxel Dörfler 	kprintf(" write_count:     %ld\n", port->write_count);
344224aee3fSIngo Weinhold 	kprintf(" total count:     %ld\n", port->total_count);
3455aee691eSIngo Weinhold 
346f28dd36bSAxel Dörfler 	if (!port->messages.IsEmpty()) {
347f28dd36bSAxel Dörfler 		kprintf("messages:\n");
348f28dd36bSAxel Dörfler 
349f28dd36bSAxel Dörfler 		MessageList::Iterator iterator = port->messages.GetIterator();
350f28dd36bSAxel Dörfler 		while (port_message* message = iterator.Next()) {
351f28dd36bSAxel Dörfler 			kprintf(" %p  %08lx  %ld\n", message, message->code, message->size);
352f28dd36bSAxel Dörfler 		}
353f28dd36bSAxel Dörfler 	}
354f28dd36bSAxel Dörfler 
3555aee691eSIngo Weinhold 	set_debug_variable("_port", (addr_t)port);
3565aee691eSIngo Weinhold 	set_debug_variable("_portID", port->id);
3575aee691eSIngo Weinhold 	set_debug_variable("_owner", port->owner);
358224aee3fSIngo Weinhold }
359224aee3fSIngo Weinhold 
360224aee3fSIngo Weinhold 
361224aee3fSIngo Weinhold static int
362224aee3fSIngo Weinhold dump_port_info(int argc, char** argv)
363224aee3fSIngo Weinhold {
364e8885f20SAxel Dörfler 	ConditionVariable* condition = NULL;
365f28dd36bSAxel Dörfler 	const char* name = NULL;
366224aee3fSIngo Weinhold 
367224aee3fSIngo Weinhold 	if (argc < 2) {
368ce637fdaSIngo Weinhold 		print_debugger_command_usage(argv[0]);
369224aee3fSIngo Weinhold 		return 0;
370224aee3fSIngo Weinhold 	}
371224aee3fSIngo Weinhold 
372224aee3fSIngo Weinhold 	if (argc > 2) {
373224aee3fSIngo Weinhold 		if (!strcmp(argv[1], "address")) {
374f28dd36bSAxel Dörfler 			_dump_port_info((struct port_entry*)parse_expression(argv[2]));
375224aee3fSIngo Weinhold 			return 0;
376e8885f20SAxel Dörfler 		} else if (!strcmp(argv[1], "condition"))
377f28dd36bSAxel Dörfler 			condition = (ConditionVariable*)parse_expression(argv[2]);
378224aee3fSIngo Weinhold 		else if (!strcmp(argv[1], "name"))
379224aee3fSIngo Weinhold 			name = argv[2];
380f28dd36bSAxel Dörfler 	} else if (parse_expression(argv[1]) > 0) {
381224aee3fSIngo Weinhold 		// if the argument looks like a number, treat it as such
382f28dd36bSAxel Dörfler 		int32 num = parse_expression(argv[1]);
383f28dd36bSAxel Dörfler 		int32 slot = num % sMaxPorts;
384f28dd36bSAxel Dörfler 		if (sPorts[slot].id != num) {
385224aee3fSIngo Weinhold 			kprintf("port %ld (%#lx) doesn't exist!\n", num, num);
386224aee3fSIngo Weinhold 			return 0;
387224aee3fSIngo Weinhold 		}
388224aee3fSIngo Weinhold 		_dump_port_info(&sPorts[slot]);
389224aee3fSIngo Weinhold 		return 0;
390224aee3fSIngo Weinhold 	} else
391224aee3fSIngo Weinhold 		name = argv[1];
392224aee3fSIngo Weinhold 
393224aee3fSIngo Weinhold 	// walk through the ports list, trying to match name
394f28dd36bSAxel Dörfler 	for (int32 i = 0; i < sMaxPorts; i++) {
395e8885f20SAxel Dörfler 		if ((name != NULL && sPorts[i].lock.name != NULL
396e8885f20SAxel Dörfler 				&& !strcmp(name, sPorts[i].lock.name))
397e8885f20SAxel Dörfler 			|| (condition != NULL && (&sPorts[i].read_condition == condition
398e8885f20SAxel Dörfler 				|| &sPorts[i].write_condition == condition))) {
399224aee3fSIngo Weinhold 			_dump_port_info(&sPorts[i]);
400224aee3fSIngo Weinhold 			return 0;
401224aee3fSIngo Weinhold 		}
402224aee3fSIngo Weinhold 	}
403224aee3fSIngo Weinhold 
404224aee3fSIngo Weinhold 	return 0;
405224aee3fSIngo Weinhold }
406224aee3fSIngo Weinhold 
407224aee3fSIngo Weinhold 
408224aee3fSIngo Weinhold static void
409224aee3fSIngo Weinhold notify_port_select_events(int slot, uint16 events)
410224aee3fSIngo Weinhold {
411224aee3fSIngo Weinhold 	if (sPorts[slot].select_infos)
412224aee3fSIngo Weinhold 		notify_select_events_list(sPorts[slot].select_infos, events);
413224aee3fSIngo Weinhold }
414224aee3fSIngo Weinhold 
415224aee3fSIngo Weinhold 
416224aee3fSIngo Weinhold static void
417e8885f20SAxel Dörfler put_port_message(port_message* message)
418224aee3fSIngo Weinhold {
419f28dd36bSAxel Dörfler 	size_t size = sizeof(port_message) + message->size;
420e8885f20SAxel Dörfler 	heap_free(sPortAllocator, message);
421f28dd36bSAxel Dörfler 
422f28dd36bSAxel Dörfler 	atomic_add(&sTotalSpaceInUse, -size);
423f28dd36bSAxel Dörfler 	sNoSpaceCondition.NotifyAll();
424224aee3fSIngo Weinhold }
425224aee3fSIngo Weinhold 
426224aee3fSIngo Weinhold 
427f28dd36bSAxel Dörfler static status_t
428f28dd36bSAxel Dörfler get_port_message(int32 code, size_t bufferSize, uint32 flags, bigtime_t timeout,
429f28dd36bSAxel Dörfler 	port_message** _message)
430224aee3fSIngo Weinhold {
431f28dd36bSAxel Dörfler 	size_t size = sizeof(port_message) + bufferSize;
432f28dd36bSAxel Dörfler 	bool limitReached = false;
433f28dd36bSAxel Dörfler 
434f28dd36bSAxel Dörfler 	while (true) {
435f28dd36bSAxel Dörfler 		if (atomic_add(&sTotalSpaceInUse, size)
436f28dd36bSAxel Dörfler 				> int32(kTotalSpaceLimit - size)) {
437f28dd36bSAxel Dörfler 			// TODO: add per team limit
438f28dd36bSAxel Dörfler 			// We are not allowed to create another heap area, as our
439f28dd36bSAxel Dörfler 			// space limit has been reached - just wait until we get
440f28dd36bSAxel Dörfler 			// some free space again.
441f28dd36bSAxel Dörfler 			limitReached = true;
442f28dd36bSAxel Dörfler 
443f28dd36bSAxel Dörfler 		wait:
444f28dd36bSAxel Dörfler 			MutexLocker locker(sPortsLock);
445f28dd36bSAxel Dörfler 
446f28dd36bSAxel Dörfler 			atomic_add(&sTotalSpaceInUse, -size);
447f28dd36bSAxel Dörfler 
448f28dd36bSAxel Dörfler 			// TODO: we don't want to wait - but does that also mean we
449f28dd36bSAxel Dörfler 			// shouldn't wait for the area creation?
450f28dd36bSAxel Dörfler 			if (limitReached && (flags & B_RELATIVE_TIMEOUT) != 0
451f28dd36bSAxel Dörfler 				&& timeout <= 0)
452f28dd36bSAxel Dörfler 				return B_WOULD_BLOCK;
453f28dd36bSAxel Dörfler 
454f28dd36bSAxel Dörfler 			ConditionVariableEntry entry;
455f28dd36bSAxel Dörfler 			sNoSpaceCondition.Add(&entry);
456f28dd36bSAxel Dörfler 
457f28dd36bSAxel Dörfler 			locker.Unlock();
458f28dd36bSAxel Dörfler 
459f28dd36bSAxel Dörfler 			status_t status = entry.Wait(flags, timeout);
460f28dd36bSAxel Dörfler 			if (status == B_TIMED_OUT)
461f28dd36bSAxel Dörfler 				return B_TIMED_OUT;
462f28dd36bSAxel Dörfler 
463f28dd36bSAxel Dörfler 			// just try again
464f28dd36bSAxel Dörfler 			limitReached = false;
465f28dd36bSAxel Dörfler 			continue;
466224aee3fSIngo Weinhold 		}
467224aee3fSIngo Weinhold 
468f28dd36bSAxel Dörfler 		int32 areaChangeCounter = atomic_get(&sAreaChangeCounter);
469f28dd36bSAxel Dörfler 
470f28dd36bSAxel Dörfler 		// Quota is fulfilled, try to allocate the buffer
471f28dd36bSAxel Dörfler 
472f28dd36bSAxel Dörfler 		port_message* message
473f28dd36bSAxel Dörfler 			= (port_message*)heap_memalign(sPortAllocator, 0, size);
474f28dd36bSAxel Dörfler 		if (message != NULL) {
475e8885f20SAxel Dörfler 			message->code = code;
476e8885f20SAxel Dörfler 			message->size = bufferSize;
477e8885f20SAxel Dörfler 
478f28dd36bSAxel Dörfler 			*_message = message;
479f28dd36bSAxel Dörfler 			return B_OK;
480f28dd36bSAxel Dörfler 		}
481f28dd36bSAxel Dörfler 
482f28dd36bSAxel Dörfler 		if (atomic_or(&sAllocatingArea, 1) != 0) {
483f28dd36bSAxel Dörfler 			// Just wait for someone else to create an area for us
484f28dd36bSAxel Dörfler 			goto wait;
485f28dd36bSAxel Dörfler 		}
486f28dd36bSAxel Dörfler 
487f28dd36bSAxel Dörfler 		if (areaChangeCounter != atomic_get(&sAreaChangeCounter)) {
488f28dd36bSAxel Dörfler 			atomic_add(&sTotalSpaceInUse, -size);
489f28dd36bSAxel Dörfler 			continue;
490f28dd36bSAxel Dörfler 		}
491f28dd36bSAxel Dörfler 
492f28dd36bSAxel Dörfler 		// Create a new area for the heap to use
493f28dd36bSAxel Dörfler 
494f28dd36bSAxel Dörfler 		addr_t base;
495f28dd36bSAxel Dörfler 		area_id area = create_area("port grown buffer", (void**)&base,
496f28dd36bSAxel Dörfler 			B_ANY_KERNEL_ADDRESS, kBufferGrowRate, B_NO_LOCK,
497f28dd36bSAxel Dörfler 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
498f28dd36bSAxel Dörfler 		if (area < 0) {
499f28dd36bSAxel Dörfler 			// it's time to let the userland feel our pain
500f28dd36bSAxel Dörfler 			sNoSpaceCondition.NotifyAll();
501f28dd36bSAxel Dörfler 			return B_NO_MEMORY;
502f28dd36bSAxel Dörfler 		}
503f28dd36bSAxel Dörfler 
504f28dd36bSAxel Dörfler 		heap_add_area(sPortAllocator, area, base, kBufferGrowRate);
505f28dd36bSAxel Dörfler 
506f28dd36bSAxel Dörfler 		atomic_add(&sAreaChangeCounter, 1);
507f28dd36bSAxel Dörfler 		sNoSpaceCondition.NotifyAll();
508f28dd36bSAxel Dörfler 		atomic_and(&sAllocatingArea, 0);
509f28dd36bSAxel Dörfler 	}
510224aee3fSIngo Weinhold }
511224aee3fSIngo Weinhold 
512224aee3fSIngo Weinhold 
513224aee3fSIngo Weinhold /*!	You need to own the port's lock when calling this function */
514224aee3fSIngo Weinhold static bool
515224aee3fSIngo Weinhold is_port_closed(int32 slot)
516224aee3fSIngo Weinhold {
517224aee3fSIngo Weinhold 	return sPorts[slot].capacity == 0;
518224aee3fSIngo Weinhold }
519224aee3fSIngo Weinhold 
520224aee3fSIngo Weinhold 
521224aee3fSIngo Weinhold /*!	Fills the port_info structure with information from the specified
522224aee3fSIngo Weinhold 	port.
523224aee3fSIngo Weinhold 	The port lock must be held when called.
524224aee3fSIngo Weinhold */
525224aee3fSIngo Weinhold static void
526224aee3fSIngo Weinhold fill_port_info(struct port_entry* port, port_info* info, size_t size)
527224aee3fSIngo Weinhold {
528224aee3fSIngo Weinhold 	info->port = port->id;
529224aee3fSIngo Weinhold 	info->team = port->owner;
530224aee3fSIngo Weinhold 	info->capacity = port->capacity;
531224aee3fSIngo Weinhold 
5327d592ec4SAxel Dörfler 	info->queue_count = port->read_count;
533224aee3fSIngo Weinhold 	info->total_count = port->total_count;
534224aee3fSIngo Weinhold 
535e8885f20SAxel Dörfler 	strlcpy(info->name, port->lock.name, B_OS_NAME_LENGTH);
536e8885f20SAxel Dörfler }
537e8885f20SAxel Dörfler 
538e8885f20SAxel Dörfler 
539e8885f20SAxel Dörfler static ssize_t
540e8885f20SAxel Dörfler copy_port_message(port_message* message, int32* _code, void* buffer,
541e8885f20SAxel Dörfler 	size_t bufferSize, bool userCopy)
542e8885f20SAxel Dörfler {
543e8885f20SAxel Dörfler 	// check output buffer size
544e8885f20SAxel Dörfler 	size_t size = min_c(bufferSize, message->size);
545e8885f20SAxel Dörfler 
546e8885f20SAxel Dörfler 	// copy message
547e8885f20SAxel Dörfler 	if (_code != NULL)
548e8885f20SAxel Dörfler 		*_code = message->code;
549e8885f20SAxel Dörfler 
550e8885f20SAxel Dörfler 	if (size > 0) {
551e8885f20SAxel Dörfler 		if (userCopy) {
552e8885f20SAxel Dörfler 			status_t status = user_memcpy(buffer, message->buffer, size);
553e8885f20SAxel Dörfler 			if (status != B_OK)
554e8885f20SAxel Dörfler 				return status;
555e8885f20SAxel Dörfler 		} else
556e8885f20SAxel Dörfler 			memcpy(buffer, message->buffer, size);
557e8885f20SAxel Dörfler 	}
558e8885f20SAxel Dörfler 
559e8885f20SAxel Dörfler 	return size;
560224aee3fSIngo Weinhold }
561224aee3fSIngo Weinhold 
562224aee3fSIngo Weinhold 
56386a999adSAxel Dörfler static void
56486a999adSAxel Dörfler uninit_port_locked(struct port_entry& port)
56586a999adSAxel Dörfler {
56686a999adSAxel Dörfler 	int32 id = port.id;
56786a999adSAxel Dörfler 
56886a999adSAxel Dörfler 	// mark port as invalid
56986a999adSAxel Dörfler 	port.id = -1;
57086a999adSAxel Dörfler 	free((char*)port.lock.name);
57186a999adSAxel Dörfler 	port.lock.name = NULL;
57286a999adSAxel Dörfler 
57386a999adSAxel Dörfler 	while (port_message* message = port.messages.RemoveHead()) {
57486a999adSAxel Dörfler 		put_port_message(message);
57586a999adSAxel Dörfler 	}
57686a999adSAxel Dörfler 
57786a999adSAxel Dörfler 	notify_port_select_events(id % sMaxPorts, B_EVENT_INVALID);
57886a999adSAxel Dörfler 	port.select_infos = NULL;
57986a999adSAxel Dörfler 
58086a999adSAxel Dörfler 	// Release the threads that were blocking on this port.
58186a999adSAxel Dörfler 	// read_port() will see the B_BAD_PORT_ID return value, and act accordingly
58286a999adSAxel Dörfler 	port.read_condition.NotifyAll(B_BAD_PORT_ID);
58386a999adSAxel Dörfler 	port.write_condition.NotifyAll(B_BAD_PORT_ID);
58486a999adSAxel Dörfler 	sNotificationService.Notify(PORT_REMOVED, id);
58586a999adSAxel Dörfler }
58686a999adSAxel Dörfler 
58786a999adSAxel Dörfler 
588224aee3fSIngo Weinhold //	#pragma mark - private kernel API
589224aee3fSIngo Weinhold 
590224aee3fSIngo Weinhold 
59186a999adSAxel Dörfler /*! This function delets all the ports that are owned by the passed team.
592224aee3fSIngo Weinhold */
59386a999adSAxel Dörfler void
59486a999adSAxel Dörfler delete_owned_ports(struct team* team)
595224aee3fSIngo Weinhold {
59686a999adSAxel Dörfler 	TRACE(("delete_owned_ports(owner = %ld)\n", team->id));
597224aee3fSIngo Weinhold 
59886a999adSAxel Dörfler 	struct list queue;
599224aee3fSIngo Weinhold 
60086a999adSAxel Dörfler 	{
60186a999adSAxel Dörfler 		InterruptsSpinLocker locker(gTeamSpinlock);
60286a999adSAxel Dörfler 		list_move_to_list(&team->port_list, &queue);
603224aee3fSIngo Weinhold 	}
604224aee3fSIngo Weinhold 
6058cd9a524SAxel Dörfler 	int32 firstSlot = sMaxPorts;
6068cd9a524SAxel Dörfler 	int32 count = 0;
6078cd9a524SAxel Dörfler 
60886a999adSAxel Dörfler 	while (port_entry* port = (port_entry*)list_remove_head_item(&queue)) {
6098cd9a524SAxel Dörfler 		if (firstSlot > port->id % sMaxPorts)
6108cd9a524SAxel Dörfler 			firstSlot = port->id % sMaxPorts;
6118cd9a524SAxel Dörfler 		count++;
6128cd9a524SAxel Dörfler 
61386a999adSAxel Dörfler 		MutexLocker locker(port->lock);
61486a999adSAxel Dörfler 		uninit_port_locked(*port);
61586a999adSAxel Dörfler 	}
6168cd9a524SAxel Dörfler 
6178cd9a524SAxel Dörfler 	MutexLocker _(sPortsLock);
6188cd9a524SAxel Dörfler 
6198cd9a524SAxel Dörfler 	// update the first free slot hint in the array
6208cd9a524SAxel Dörfler 	if (firstSlot < sFirstFreeSlot)
6218cd9a524SAxel Dörfler 		sFirstFreeSlot = firstSlot;
6228cd9a524SAxel Dörfler 
6238cd9a524SAxel Dörfler 	sUsedPorts -= count;
624224aee3fSIngo Weinhold }
625224aee3fSIngo Weinhold 
626224aee3fSIngo Weinhold 
627224aee3fSIngo Weinhold int32
628224aee3fSIngo Weinhold port_max_ports(void)
629224aee3fSIngo Weinhold {
630224aee3fSIngo Weinhold 	return sMaxPorts;
631224aee3fSIngo Weinhold }
632224aee3fSIngo Weinhold 
633224aee3fSIngo Weinhold 
634224aee3fSIngo Weinhold int32
635224aee3fSIngo Weinhold port_used_ports(void)
636224aee3fSIngo Weinhold {
637224aee3fSIngo Weinhold 	return sUsedPorts;
638224aee3fSIngo Weinhold }
639224aee3fSIngo Weinhold 
640224aee3fSIngo Weinhold 
641224aee3fSIngo Weinhold status_t
642224aee3fSIngo Weinhold port_init(kernel_args *args)
643224aee3fSIngo Weinhold {
644224aee3fSIngo Weinhold 	size_t size = sizeof(struct port_entry) * sMaxPorts;
645224aee3fSIngo Weinhold 
646224aee3fSIngo Weinhold 	// create and initialize ports table
647e8885f20SAxel Dörfler 	sPortArea = create_area("port_table",
648e8885f20SAxel Dörfler 		(void**)&sPorts, B_ANY_KERNEL_ADDRESS, size, B_FULL_LOCK,
649e8885f20SAxel Dörfler 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
650224aee3fSIngo Weinhold 	if (sPortArea < 0) {
651224aee3fSIngo Weinhold 		panic("unable to allocate kernel port table!\n");
652224aee3fSIngo Weinhold 		return sPortArea;
653224aee3fSIngo Weinhold 	}
654224aee3fSIngo Weinhold 
655224aee3fSIngo Weinhold 	memset(sPorts, 0, size);
656e8885f20SAxel Dörfler 	for (int32 i = 0; i < sMaxPorts; i++) {
657e8885f20SAxel Dörfler 		mutex_init(&sPorts[i].lock, NULL);
658224aee3fSIngo Weinhold 		sPorts[i].id = -1;
659e8885f20SAxel Dörfler 		sPorts[i].read_condition.Init(&sPorts[i], "port read");
660e8885f20SAxel Dörfler 		sPorts[i].write_condition.Init(&sPorts[i], "port write");
661e8885f20SAxel Dörfler 	}
662e8885f20SAxel Dörfler 
663e8885f20SAxel Dörfler 	addr_t base;
664e8885f20SAxel Dörfler 	if (create_area("port heap", (void**)&base, B_ANY_KERNEL_ADDRESS,
665e8885f20SAxel Dörfler 			kInitialPortBufferSize, B_NO_LOCK,
666e8885f20SAxel Dörfler 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA) < 0) {
667e8885f20SAxel Dörfler 		panic("unable to allocate port area!\n");
668e8885f20SAxel Dörfler 		return B_ERROR;
669e8885f20SAxel Dörfler 	}
670e8885f20SAxel Dörfler 
671e8885f20SAxel Dörfler 	static const heap_class kBufferHeapClass = {"default", 100,
672e8885f20SAxel Dörfler 		PORT_MAX_MESSAGE_SIZE + sizeof(port_message), 2 * 1024,
673e8885f20SAxel Dörfler 		sizeof(port_message), 8, 4, 64};
674e8885f20SAxel Dörfler 	sPortAllocator = heap_create_allocator("port buffer", base,
675e8885f20SAxel Dörfler 		kInitialPortBufferSize, &kBufferHeapClass, true);
676f28dd36bSAxel Dörfler 	if (sPortAllocator == NULL) {
677f28dd36bSAxel Dörfler 		panic("unable to create port heap");
678f28dd36bSAxel Dörfler 		return B_NO_MEMORY;
679f28dd36bSAxel Dörfler 	}
680f28dd36bSAxel Dörfler 
681f28dd36bSAxel Dörfler 	sNoSpaceCondition.Init(sPorts, "port space");
682224aee3fSIngo Weinhold 
683224aee3fSIngo Weinhold 	// add debugger commands
684ce637fdaSIngo Weinhold 	add_debugger_command_etc("ports", &dump_port_list,
685ce637fdaSIngo Weinhold 		"Dump a list of all active ports (for team, with name, etc.)",
686ce637fdaSIngo Weinhold 		"[ ([ \"team\" | \"owner\" ] <team>) | (\"name\" <name>) ]\n"
687ce637fdaSIngo Weinhold 		"Prints a list of all active ports meeting the given\n"
688ce637fdaSIngo Weinhold 		"requirement. If no argument is given, all ports are listed.\n"
689ce637fdaSIngo Weinhold 		"  <team>             - The team owning the ports.\n"
690ce637fdaSIngo Weinhold 		"  <name>             - Part of the name of the ports.\n", 0);
691ce637fdaSIngo Weinhold 	add_debugger_command_etc("port", &dump_port_info,
692ce637fdaSIngo Weinhold 		"Dump info about a particular port",
693f28dd36bSAxel Dörfler 		"(<id> | [ \"address\" ] <address>) | ([ \"name\" ] <name>) "
694f28dd36bSAxel Dörfler 			"| (\"condition\" <address>)\n"
695ce637fdaSIngo Weinhold 		"Prints info about the specified port.\n"
696ce637fdaSIngo Weinhold 		"  <address>   - Pointer to the port structure.\n"
697ce637fdaSIngo Weinhold 		"  <name>      - Name of the port.\n"
698f28dd36bSAxel Dörfler 		"  <condition> - address of the port's read or write condition.\n", 0);
699224aee3fSIngo Weinhold 
70051755cf8SAxel Dörfler 	new(&sNotificationService) PortNotificationService();
701224aee3fSIngo Weinhold 	sPortsActive = true;
702224aee3fSIngo Weinhold 	return B_OK;
703224aee3fSIngo Weinhold }
704224aee3fSIngo Weinhold 
705224aee3fSIngo Weinhold 
706224aee3fSIngo Weinhold //	#pragma mark - public kernel API
707224aee3fSIngo Weinhold 
708224aee3fSIngo Weinhold 
709224aee3fSIngo Weinhold port_id
710224aee3fSIngo Weinhold create_port(int32 queueLength, const char* name)
711224aee3fSIngo Weinhold {
71251755cf8SAxel Dörfler 	TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength,
71351755cf8SAxel Dörfler 		name));
714224aee3fSIngo Weinhold 
715e8885f20SAxel Dörfler 	if (!sPortsActive) {
716e8885f20SAxel Dörfler 		panic("ports used too early!\n");
717224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
718e8885f20SAxel Dörfler 	}
719e8885f20SAxel Dörfler 	if (queueLength < 1 || queueLength > MAX_QUEUE_LENGTH)
720224aee3fSIngo Weinhold 		return B_BAD_VALUE;
721224aee3fSIngo Weinhold 
72286a999adSAxel Dörfler 	struct team* team = thread_get_current_thread()->team;
72386a999adSAxel Dörfler 	if (team == NULL)
72486a999adSAxel Dörfler 		return B_BAD_TEAM_ID;
72586a999adSAxel Dörfler 
726e8885f20SAxel Dörfler 	MutexLocker locker(sPortsLock);
727e8885f20SAxel Dörfler 
728224aee3fSIngo Weinhold 	// check early on if there are any free port slots to use
729e8885f20SAxel Dörfler 	if (sUsedPorts >= sMaxPorts)
730e8885f20SAxel Dörfler 		return B_NO_MORE_PORTS;
731224aee3fSIngo Weinhold 
732224aee3fSIngo Weinhold 	// check & dup name
733e8885f20SAxel Dörfler 	char* nameBuffer = strdup(name != NULL ? name : "unnamed port");
734e8885f20SAxel Dörfler 	if (nameBuffer == NULL)
735e8885f20SAxel Dörfler 		return B_NO_MEMORY;
736224aee3fSIngo Weinhold 
737e8885f20SAxel Dörfler 	sUsedPorts++;
738224aee3fSIngo Weinhold 
739224aee3fSIngo Weinhold 	// find the first empty spot
740e8885f20SAxel Dörfler 	for (int32 slot = 0; slot < sMaxPorts; slot++) {
741224aee3fSIngo Weinhold 		int32 i = (slot + sFirstFreeSlot) % sMaxPorts;
742224aee3fSIngo Weinhold 
743224aee3fSIngo Weinhold 		if (sPorts[i].id == -1) {
744224aee3fSIngo Weinhold 			// make the port_id be a multiple of the slot it's in
745224aee3fSIngo Weinhold 			if (i >= sNextPort % sMaxPorts)
746224aee3fSIngo Weinhold 				sNextPort += i - sNextPort % sMaxPorts;
747224aee3fSIngo Weinhold 			else
748224aee3fSIngo Weinhold 				sNextPort += sMaxPorts - (sNextPort % sMaxPorts - i);
749224aee3fSIngo Weinhold 			sFirstFreeSlot = slot + 1;
750224aee3fSIngo Weinhold 
751e8885f20SAxel Dörfler 			MutexLocker portLocker(sPorts[i].lock);
752224aee3fSIngo Weinhold 			sPorts[i].id = sNextPort++;
753e8885f20SAxel Dörfler 			locker.Unlock();
754224aee3fSIngo Weinhold 
755224aee3fSIngo Weinhold 			sPorts[i].capacity = queueLength;
756e8885f20SAxel Dörfler 			sPorts[i].owner = team_get_current_team_id();
757e8885f20SAxel Dörfler 			sPorts[i].lock.name = nameBuffer;
758e8885f20SAxel Dörfler 			sPorts[i].read_count = 0;
759e8885f20SAxel Dörfler 			sPorts[i].write_count = queueLength;
760224aee3fSIngo Weinhold 			sPorts[i].total_count = 0;
761224aee3fSIngo Weinhold 			sPorts[i].select_infos = NULL;
762224aee3fSIngo Weinhold 
76386a999adSAxel Dörfler 			{
76486a999adSAxel Dörfler 				InterruptsSpinLocker teamLocker(gTeamSpinlock);
76586a999adSAxel Dörfler 				list_add_item(&team->port_list, &sPorts[i].team_link);
76686a999adSAxel Dörfler 			}
76786a999adSAxel Dörfler 
768e8885f20SAxel Dörfler 			port_id id = sPorts[i].id;
769f28dd36bSAxel Dörfler 
770f28dd36bSAxel Dörfler 			T(Create(sPorts[i]));
771e8885f20SAxel Dörfler 			portLocker.Unlock();
772224aee3fSIngo Weinhold 
773224aee3fSIngo Weinhold 			TRACE(("create_port() done: port created %ld\n", id));
774224aee3fSIngo Weinhold 
77551755cf8SAxel Dörfler 			sNotificationService.Notify(PORT_ADDED, id);
776224aee3fSIngo Weinhold 			return id;
777224aee3fSIngo Weinhold 		}
778224aee3fSIngo Weinhold 	}
779224aee3fSIngo Weinhold 
780e8885f20SAxel Dörfler 	// Still not enough ports... - due to sUsedPorts, this cannot really
781e8885f20SAxel Dörfler 	// happen anymore.
782e8885f20SAxel Dörfler 	panic("out of ports, but sUsedPorts is broken");
783e8885f20SAxel Dörfler 	return B_NO_MORE_PORTS;
784224aee3fSIngo Weinhold }
785224aee3fSIngo Weinhold 
786224aee3fSIngo Weinhold 
787224aee3fSIngo Weinhold status_t
788224aee3fSIngo Weinhold close_port(port_id id)
789224aee3fSIngo Weinhold {
790224aee3fSIngo Weinhold 	TRACE(("close_port(id = %ld)\n", id));
791224aee3fSIngo Weinhold 
792224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
793224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
794224aee3fSIngo Weinhold 
795e8885f20SAxel Dörfler 	int32 slot = id % sMaxPorts;
796224aee3fSIngo Weinhold 
797224aee3fSIngo Weinhold 	// walk through the sem list, trying to match name
798e8885f20SAxel Dörfler 	MutexLocker locker(sPorts[slot].lock);
799224aee3fSIngo Weinhold 
800224aee3fSIngo Weinhold 	if (sPorts[slot].id != id) {
801224aee3fSIngo Weinhold 		TRACE(("close_port: invalid port_id %ld\n", id));
802224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
803224aee3fSIngo Weinhold 	}
804224aee3fSIngo Weinhold 
805224aee3fSIngo Weinhold 	// mark port to disable writing - deleting the semaphores will
806224aee3fSIngo Weinhold 	// wake up waiting read/writes
807224aee3fSIngo Weinhold 	sPorts[slot].capacity = 0;
808224aee3fSIngo Weinhold 
809224aee3fSIngo Weinhold 	notify_port_select_events(slot, B_EVENT_INVALID);
810224aee3fSIngo Weinhold 	sPorts[slot].select_infos = NULL;
811224aee3fSIngo Weinhold 
812e8885f20SAxel Dörfler 	sPorts[slot].read_condition.NotifyAll(false, B_BAD_PORT_ID);
813e8885f20SAxel Dörfler 	sPorts[slot].write_condition.NotifyAll(false, B_BAD_PORT_ID);
814224aee3fSIngo Weinhold 
815e8885f20SAxel Dörfler 	return B_OK;
816224aee3fSIngo Weinhold }
817224aee3fSIngo Weinhold 
818224aee3fSIngo Weinhold 
819224aee3fSIngo Weinhold status_t
820224aee3fSIngo Weinhold delete_port(port_id id)
821224aee3fSIngo Weinhold {
822224aee3fSIngo Weinhold 	TRACE(("delete_port(id = %ld)\n", id));
823224aee3fSIngo Weinhold 
824224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
825224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
826224aee3fSIngo Weinhold 
827e8885f20SAxel Dörfler 	int32 slot = id % sMaxPorts;
828224aee3fSIngo Weinhold 
829e8885f20SAxel Dörfler 	MutexLocker locker(sPorts[slot].lock);
830224aee3fSIngo Weinhold 
831224aee3fSIngo Weinhold 	if (sPorts[slot].id != id) {
832224aee3fSIngo Weinhold 		TRACE(("delete_port: invalid port_id %ld\n", id));
833224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
834224aee3fSIngo Weinhold 	}
835224aee3fSIngo Weinhold 
836f28dd36bSAxel Dörfler 	T(Delete(sPorts[slot]));
837f28dd36bSAxel Dörfler 
83886a999adSAxel Dörfler 	{
83986a999adSAxel Dörfler 		InterruptsSpinLocker teamLocker(gTeamSpinlock);
84086a999adSAxel Dörfler 		list_remove_link(&sPorts[slot].team_link);
841e8885f20SAxel Dörfler 	}
842224aee3fSIngo Weinhold 
84386a999adSAxel Dörfler 	uninit_port_locked(sPorts[slot]);
844224aee3fSIngo Weinhold 
845e8885f20SAxel Dörfler 	locker.Unlock();
846e8885f20SAxel Dörfler 
847e8885f20SAxel Dörfler 	MutexLocker _(sPortsLock);
848e8885f20SAxel Dörfler 
849e8885f20SAxel Dörfler 	// update the first free slot hint in the array
850e8885f20SAxel Dörfler 	if (slot < sFirstFreeSlot)
851e8885f20SAxel Dörfler 		sFirstFreeSlot = slot;
852e8885f20SAxel Dörfler 
853e8885f20SAxel Dörfler 	sUsedPorts--;
854224aee3fSIngo Weinhold 	return B_OK;
855224aee3fSIngo Weinhold }
856224aee3fSIngo Weinhold 
857224aee3fSIngo Weinhold 
858224aee3fSIngo Weinhold status_t
859224aee3fSIngo Weinhold select_port(int32 id, struct select_info* info, bool kernel)
860224aee3fSIngo Weinhold {
861224aee3fSIngo Weinhold 	if (id < 0)
862224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
863224aee3fSIngo Weinhold 
864e8885f20SAxel Dörfler 	int32 slot = id % sMaxPorts;
865224aee3fSIngo Weinhold 
866e8885f20SAxel Dörfler 	MutexLocker locker(sPorts[slot].lock);
867224aee3fSIngo Weinhold 
868e8885f20SAxel Dörfler 	if (sPorts[slot].id != id || is_port_closed(slot))
869e8885f20SAxel Dörfler 		return B_BAD_PORT_ID;
870e8885f20SAxel Dörfler 	if (!kernel && sPorts[slot].owner == team_get_kernel_team_id()) {
871224aee3fSIngo Weinhold 		// kernel port, but call from userland
872e8885f20SAxel Dörfler 		return B_NOT_ALLOWED;
873e8885f20SAxel Dörfler 	}
874e8885f20SAxel Dörfler 
875224aee3fSIngo Weinhold 	info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID;
876224aee3fSIngo Weinhold 
877224aee3fSIngo Weinhold 	if (info->selected_events != 0) {
878224aee3fSIngo Weinhold 		uint16 events = 0;
879224aee3fSIngo Weinhold 
880224aee3fSIngo Weinhold 		info->next = sPorts[slot].select_infos;
881224aee3fSIngo Weinhold 		sPorts[slot].select_infos = info;
882224aee3fSIngo Weinhold 
883224aee3fSIngo Weinhold 		// check for events
884224aee3fSIngo Weinhold 		if ((info->selected_events & B_EVENT_READ) != 0
885e8885f20SAxel Dörfler 			&& !sPorts[slot].messages.IsEmpty()) {
886224aee3fSIngo Weinhold 			events |= B_EVENT_READ;
887224aee3fSIngo Weinhold 		}
888224aee3fSIngo Weinhold 
889e8885f20SAxel Dörfler 		if (sPorts[slot].write_count > 0)
890224aee3fSIngo Weinhold 			events |= B_EVENT_WRITE;
891224aee3fSIngo Weinhold 
892224aee3fSIngo Weinhold 		if (events != 0)
893224aee3fSIngo Weinhold 			notify_select_events(info, events);
894224aee3fSIngo Weinhold 	}
895224aee3fSIngo Weinhold 
896e8885f20SAxel Dörfler 	return B_OK;
897224aee3fSIngo Weinhold }
898224aee3fSIngo Weinhold 
899224aee3fSIngo Weinhold 
900224aee3fSIngo Weinhold status_t
901224aee3fSIngo Weinhold deselect_port(int32 id, struct select_info* info, bool kernel)
902224aee3fSIngo Weinhold {
903224aee3fSIngo Weinhold 	if (id < 0)
904224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
905224aee3fSIngo Weinhold 	if (info->selected_events == 0)
906224aee3fSIngo Weinhold 		return B_OK;
907224aee3fSIngo Weinhold 
908e8885f20SAxel Dörfler 	int32 slot = id % sMaxPorts;
909224aee3fSIngo Weinhold 
910e8885f20SAxel Dörfler 	MutexLocker locker(sPorts[slot].lock);
911224aee3fSIngo Weinhold 
912224aee3fSIngo Weinhold 	if (sPorts[slot].id == id) {
913224aee3fSIngo Weinhold 		select_info** infoLocation = &sPorts[slot].select_infos;
914224aee3fSIngo Weinhold 		while (*infoLocation != NULL && *infoLocation != info)
915224aee3fSIngo Weinhold 			infoLocation = &(*infoLocation)->next;
916224aee3fSIngo Weinhold 
917224aee3fSIngo Weinhold 		if (*infoLocation == info)
918224aee3fSIngo Weinhold 			*infoLocation = info->next;
919224aee3fSIngo Weinhold 	}
920224aee3fSIngo Weinhold 
921224aee3fSIngo Weinhold 	return B_OK;
922224aee3fSIngo Weinhold }
923224aee3fSIngo Weinhold 
924224aee3fSIngo Weinhold 
925224aee3fSIngo Weinhold port_id
926224aee3fSIngo Weinhold find_port(const char* name)
927224aee3fSIngo Weinhold {
928224aee3fSIngo Weinhold 	TRACE(("find_port(name = \"%s\")\n", name));
929224aee3fSIngo Weinhold 
930e8885f20SAxel Dörfler 	if (!sPortsActive) {
931e8885f20SAxel Dörfler 		panic("ports used too early!\n");
932224aee3fSIngo Weinhold 		return B_NAME_NOT_FOUND;
933e8885f20SAxel Dörfler 	}
934224aee3fSIngo Weinhold 	if (name == NULL)
935224aee3fSIngo Weinhold 		return B_BAD_VALUE;
936224aee3fSIngo Weinhold 
937224aee3fSIngo Weinhold 	// Since we have to check every single port, and we don't
938224aee3fSIngo Weinhold 	// care if it goes away at any point, we're only grabbing
939224aee3fSIngo Weinhold 	// the port lock in question, not the port list lock
940224aee3fSIngo Weinhold 
941224aee3fSIngo Weinhold 	// loop over list
942e8885f20SAxel Dörfler 	for (int32 i = 0; i < sMaxPorts; i++) {
943224aee3fSIngo Weinhold 		// lock every individual port before comparing
944e8885f20SAxel Dörfler 		MutexLocker _(sPorts[i].lock);
945224aee3fSIngo Weinhold 
946e8885f20SAxel Dörfler 		if (sPorts[i].id >= 0 && !strcmp(name, sPorts[i].lock.name))
947e8885f20SAxel Dörfler 			return sPorts[i].id;
948224aee3fSIngo Weinhold 	}
949224aee3fSIngo Weinhold 
950e8885f20SAxel Dörfler 	return B_NAME_NOT_FOUND;
951224aee3fSIngo Weinhold }
952224aee3fSIngo Weinhold 
953224aee3fSIngo Weinhold 
954224aee3fSIngo Weinhold status_t
955224aee3fSIngo Weinhold _get_port_info(port_id id, port_info* info, size_t size)
956224aee3fSIngo Weinhold {
957224aee3fSIngo Weinhold 	TRACE(("get_port_info(id = %ld)\n", id));
958224aee3fSIngo Weinhold 
959224aee3fSIngo Weinhold 	if (info == NULL || size != sizeof(port_info))
960224aee3fSIngo Weinhold 		return B_BAD_VALUE;
961224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
962224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
963224aee3fSIngo Weinhold 
964e8885f20SAxel Dörfler 	int32 slot = id % sMaxPorts;
965224aee3fSIngo Weinhold 
966e8885f20SAxel Dörfler 	MutexLocker locker(sPorts[slot].lock);
967224aee3fSIngo Weinhold 
968224aee3fSIngo Weinhold 	if (sPorts[slot].id != id || sPorts[slot].capacity == 0) {
969224aee3fSIngo Weinhold 		TRACE(("get_port_info: invalid port_id %ld\n", id));
970224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
971224aee3fSIngo Weinhold 	}
972224aee3fSIngo Weinhold 
973224aee3fSIngo Weinhold 	// fill a port_info struct with info
974224aee3fSIngo Weinhold 	fill_port_info(&sPorts[slot], info, size);
975224aee3fSIngo Weinhold 	return B_OK;
976224aee3fSIngo Weinhold }
977224aee3fSIngo Weinhold 
978224aee3fSIngo Weinhold 
979224aee3fSIngo Weinhold status_t
980e8885f20SAxel Dörfler _get_next_port_info(team_id team, int32* _cookie, struct port_info* info,
981e8885f20SAxel Dörfler 	size_t size)
982224aee3fSIngo Weinhold {
983224aee3fSIngo Weinhold 	TRACE(("get_next_port_info(team = %ld)\n", team));
984224aee3fSIngo Weinhold 
985e8885f20SAxel Dörfler 	if (info == NULL || size != sizeof(port_info) || _cookie == NULL
986e8885f20SAxel Dörfler 		|| team < B_OK)
987224aee3fSIngo Weinhold 		return B_BAD_VALUE;
988224aee3fSIngo Weinhold 	if (!sPortsActive)
989224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
990224aee3fSIngo Weinhold 
991e8885f20SAxel Dörfler 	int32 slot = *_cookie;
992224aee3fSIngo Weinhold 	if (slot >= sMaxPorts)
993224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
994224aee3fSIngo Weinhold 
995224aee3fSIngo Weinhold 	if (team == B_CURRENT_TEAM)
996224aee3fSIngo Weinhold 		team = team_get_current_team_id();
997224aee3fSIngo Weinhold 
998224aee3fSIngo Weinhold 	info->port = -1; // used as found flag
999224aee3fSIngo Weinhold 
1000224aee3fSIngo Weinhold 	while (slot < sMaxPorts) {
1001e8885f20SAxel Dörfler 		MutexLocker locker(sPorts[slot].lock);
1002e8885f20SAxel Dörfler 
1003e8885f20SAxel Dörfler 		if (sPorts[slot].id != -1 && !is_port_closed(slot)
1004e8885f20SAxel Dörfler 			&& sPorts[slot].owner == team) {
1005224aee3fSIngo Weinhold 			// found one!
1006224aee3fSIngo Weinhold 			fill_port_info(&sPorts[slot], info, size);
1007224aee3fSIngo Weinhold 			slot++;
1008224aee3fSIngo Weinhold 			break;
1009224aee3fSIngo Weinhold 		}
1010e8885f20SAxel Dörfler 
1011224aee3fSIngo Weinhold 		slot++;
1012224aee3fSIngo Weinhold 	}
1013224aee3fSIngo Weinhold 
1014224aee3fSIngo Weinhold 	if (info->port == -1)
1015224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1016224aee3fSIngo Weinhold 
1017224aee3fSIngo Weinhold 	*_cookie = slot;
1018e8885f20SAxel Dörfler 	return B_OK;
1019224aee3fSIngo Weinhold }
1020224aee3fSIngo Weinhold 
1021224aee3fSIngo Weinhold 
1022224aee3fSIngo Weinhold ssize_t
1023224aee3fSIngo Weinhold port_buffer_size(port_id id)
1024224aee3fSIngo Weinhold {
1025224aee3fSIngo Weinhold 	return port_buffer_size_etc(id, 0, 0);
1026224aee3fSIngo Weinhold }
1027224aee3fSIngo Weinhold 
1028224aee3fSIngo Weinhold 
1029224aee3fSIngo Weinhold ssize_t
1030224aee3fSIngo Weinhold port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
1031224aee3fSIngo Weinhold {
10327727e08eSIngo Weinhold 	port_message_info info;
10337727e08eSIngo Weinhold 	status_t error = get_port_message_info_etc(id, &info, flags, timeout);
10347727e08eSIngo Weinhold 	return error != B_OK ? error : info.size;
10357727e08eSIngo Weinhold }
10367727e08eSIngo Weinhold 
1037e8885f20SAxel Dörfler 
10387727e08eSIngo Weinhold status_t
10397727e08eSIngo Weinhold _get_port_message_info_etc(port_id id, port_message_info* info,
10407727e08eSIngo Weinhold 	size_t infoSize, uint32 flags, bigtime_t timeout)
10417727e08eSIngo Weinhold {
10427727e08eSIngo Weinhold 	if (info == NULL || infoSize != sizeof(port_message_info))
10437727e08eSIngo Weinhold 		return B_BAD_VALUE;
1044224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1045224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1046224aee3fSIngo Weinhold 
1047f28dd36bSAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1048f28dd36bSAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1049e8885f20SAxel Dörfler 	int32 slot = id % sMaxPorts;
1050224aee3fSIngo Weinhold 
1051e8885f20SAxel Dörfler 	MutexLocker locker(sPorts[slot].lock);
1052224aee3fSIngo Weinhold 
1053224aee3fSIngo Weinhold 	if (sPorts[slot].id != id
1054e8885f20SAxel Dörfler 		|| (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) {
1055f28dd36bSAxel Dörfler 		T(Info(sPorts[slot], 0, B_BAD_PORT_ID));
10567d592ec4SAxel Dörfler 		TRACE(("_get_port_message_info_etc(): %s port %ld\n",
1057224aee3fSIngo Weinhold 			sPorts[slot].id == id ? "closed" : "invalid", id));
1058224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1059224aee3fSIngo Weinhold 	}
1060224aee3fSIngo Weinhold 
10617d592ec4SAxel Dörfler 	while (sPorts[slot].read_count == 0) {
1062e8885f20SAxel Dörfler 		// We need to wait for a message to appear
1063f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1064f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1065f28dd36bSAxel Dörfler 
1066e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
1067e8885f20SAxel Dörfler 		sPorts[slot].read_condition.Add(&entry);
1068224aee3fSIngo Weinhold 
1069e8885f20SAxel Dörfler 		locker.Unlock();
1070224aee3fSIngo Weinhold 
1071224aee3fSIngo Weinhold 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1072e8885f20SAxel Dörfler 		status_t status = entry.Wait(flags, timeout);
1073f28dd36bSAxel Dörfler 
1074f28dd36bSAxel Dörfler 		if (status != B_OK) {
1075f28dd36bSAxel Dörfler 			T(Info(sPorts[slot], 0, status));
1076224aee3fSIngo Weinhold 			return status;
1077f28dd36bSAxel Dörfler 		}
1078224aee3fSIngo Weinhold 
1079e8885f20SAxel Dörfler 		locker.Lock();
1080e8885f20SAxel Dörfler 	}
1081224aee3fSIngo Weinhold 
1082224aee3fSIngo Weinhold 	if (sPorts[slot].id != id) {
1083224aee3fSIngo Weinhold 		// the port is no longer there
1084224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1085224aee3fSIngo Weinhold 	}
1086224aee3fSIngo Weinhold 
1087224aee3fSIngo Weinhold 	// determine tail & get the length of the message
1088e8885f20SAxel Dörfler 	port_message* message = sPorts[slot].messages.Head();
1089e8885f20SAxel Dörfler 	if (message == NULL) {
1090224aee3fSIngo Weinhold 		panic("port %ld: no messages found\n", sPorts[slot].id);
1091e8885f20SAxel Dörfler 		return B_ERROR;
10927727e08eSIngo Weinhold 	}
1093224aee3fSIngo Weinhold 
1094e8885f20SAxel Dörfler 	info->size = message->size;
1095e8885f20SAxel Dörfler 	info->sender = message->sender;
1096e8885f20SAxel Dörfler 	info->sender_group = message->sender_group;
1097e8885f20SAxel Dörfler 	info->sender_team = message->sender_team;
1098224aee3fSIngo Weinhold 
1099f28dd36bSAxel Dörfler 	T(Info(sPorts[slot], message->code, B_OK));
1100f28dd36bSAxel Dörfler 
1101e8885f20SAxel Dörfler 	// notify next one, as we haven't read from the port
1102e8885f20SAxel Dörfler 	sPorts[slot].read_condition.NotifyOne();
1103224aee3fSIngo Weinhold 
1104e8885f20SAxel Dörfler 	return B_OK;
1105224aee3fSIngo Weinhold }
1106224aee3fSIngo Weinhold 
1107224aee3fSIngo Weinhold 
1108224aee3fSIngo Weinhold ssize_t
1109224aee3fSIngo Weinhold port_count(port_id id)
1110224aee3fSIngo Weinhold {
1111224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1112224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1113224aee3fSIngo Weinhold 
1114e8885f20SAxel Dörfler 	int32 slot = id % sMaxPorts;
1115224aee3fSIngo Weinhold 
1116e8885f20SAxel Dörfler 	MutexLocker locker(sPorts[slot].lock);
1117224aee3fSIngo Weinhold 
1118224aee3fSIngo Weinhold 	if (sPorts[slot].id != id) {
1119224aee3fSIngo Weinhold 		TRACE(("port_count: invalid port_id %ld\n", id));
1120224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1121224aee3fSIngo Weinhold 	}
1122224aee3fSIngo Weinhold 
1123224aee3fSIngo Weinhold 	// return count of messages
11247d592ec4SAxel Dörfler 	return sPorts[slot].read_count;
1125224aee3fSIngo Weinhold }
1126224aee3fSIngo Weinhold 
1127224aee3fSIngo Weinhold 
1128224aee3fSIngo Weinhold ssize_t
1129e8885f20SAxel Dörfler read_port(port_id port, int32* msgCode, void* buffer, size_t bufferSize)
1130224aee3fSIngo Weinhold {
1131e8885f20SAxel Dörfler 	return read_port_etc(port, msgCode, buffer, bufferSize, 0, 0);
1132224aee3fSIngo Weinhold }
1133224aee3fSIngo Weinhold 
1134224aee3fSIngo Weinhold 
1135224aee3fSIngo Weinhold ssize_t
1136e8885f20SAxel Dörfler read_port_etc(port_id id, int32* _code, void* buffer, size_t bufferSize,
1137224aee3fSIngo Weinhold 	uint32 flags, bigtime_t timeout)
1138224aee3fSIngo Weinhold {
1139224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1140224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1141e8885f20SAxel Dörfler 	if ((buffer == NULL && bufferSize > 0) || timeout < 0)
1142224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1143224aee3fSIngo Weinhold 
1144e8885f20SAxel Dörfler 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0;
1145e8885f20SAxel Dörfler 	bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0;
1146e8885f20SAxel Dörfler 		// TODO: we could allow peeking for user apps now
1147224aee3fSIngo Weinhold 
1148e8885f20SAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1149e8885f20SAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1150e8885f20SAxel Dörfler 
1151e8885f20SAxel Dörfler 	int32 slot = id % sMaxPorts;
1152e8885f20SAxel Dörfler 
1153e8885f20SAxel Dörfler 	MutexLocker locker(sPorts[slot].lock);
1154224aee3fSIngo Weinhold 
1155224aee3fSIngo Weinhold 	if (sPorts[slot].id != id
1156e8885f20SAxel Dörfler 		|| (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) {
1157f28dd36bSAxel Dörfler 		T(Read(sPorts[slot], 0, B_BAD_PORT_ID));
1158224aee3fSIngo Weinhold 		TRACE(("read_port_etc(): %s port %ld\n",
1159224aee3fSIngo Weinhold 			sPorts[slot].id == id ? "closed" : "invalid", id));
1160224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1161224aee3fSIngo Weinhold 	}
1162224aee3fSIngo Weinhold 
11637d592ec4SAxel Dörfler 	while (sPorts[slot].read_count == 0) {
1164f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1165f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1166f28dd36bSAxel Dörfler 
1167e8885f20SAxel Dörfler 		// We need to wait for a message to appear
1168e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
1169e8885f20SAxel Dörfler 		sPorts[slot].read_condition.Add(&entry);
1170224aee3fSIngo Weinhold 
1171e8885f20SAxel Dörfler 		locker.Unlock();
1172224aee3fSIngo Weinhold 
1173e8885f20SAxel Dörfler 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1174e8885f20SAxel Dörfler 		status_t status = entry.Wait(flags, timeout);
1175224aee3fSIngo Weinhold 
1176e8885f20SAxel Dörfler 		locker.Lock();
1177224aee3fSIngo Weinhold 
1178e8885f20SAxel Dörfler 		if (sPorts[slot].id != id) {
1179e8885f20SAxel Dörfler 			// the port is no longer there
1180f28dd36bSAxel Dörfler 			T(Read(sPorts[slot], 0, B_BAD_PORT_ID));
1181224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1182224aee3fSIngo Weinhold 		}
1183224aee3fSIngo Weinhold 
1184*c3bc71d6SIngo Weinhold 		if (status != B_OK) {
1185*c3bc71d6SIngo Weinhold 			T(Read(sPorts[slot], 0, status));
1186e8885f20SAxel Dörfler 			sPorts[slot].read_count++;
1187*c3bc71d6SIngo Weinhold 			return status;
1188e8885f20SAxel Dörfler 		}
11897d592ec4SAxel Dörfler 	}
1190224aee3fSIngo Weinhold 
1191e8885f20SAxel Dörfler 	// determine tail & get the length of the message
1192e8885f20SAxel Dörfler 	port_message* message = sPorts[slot].messages.Head();
1193e8885f20SAxel Dörfler 	if (message == NULL) {
1194e8885f20SAxel Dörfler 		panic("port %ld: no messages found\n", sPorts[slot].id);
1195e8885f20SAxel Dörfler 		return B_ERROR;
1196224aee3fSIngo Weinhold 	}
1197224aee3fSIngo Weinhold 
1198b4ec7b8eSIngo Weinhold 	if (peekOnly) {
1199e8885f20SAxel Dörfler 		size_t size = copy_port_message(message, _code, buffer, bufferSize,
1200e8885f20SAxel Dörfler 			userCopy);
1201e8885f20SAxel Dörfler 
1202f28dd36bSAxel Dörfler 		T(Read(sPorts[slot], message->code, size));
1203f28dd36bSAxel Dörfler 
1204e8885f20SAxel Dörfler 		sPorts[slot].read_condition.NotifyOne();
1205b4ec7b8eSIngo Weinhold 			// we only peeked, but didn't grab the message
1206b4ec7b8eSIngo Weinhold 		return size;
1207b4ec7b8eSIngo Weinhold 	}
1208b4ec7b8eSIngo Weinhold 
1209e8885f20SAxel Dörfler 	sPorts[slot].messages.RemoveHead();
1210224aee3fSIngo Weinhold 	sPorts[slot].total_count++;
1211e8885f20SAxel Dörfler 	sPorts[slot].write_count++;
12127d592ec4SAxel Dörfler 	sPorts[slot].read_count--;
1213224aee3fSIngo Weinhold 
1214224aee3fSIngo Weinhold 	notify_port_select_events(slot, B_EVENT_WRITE);
1215e8885f20SAxel Dörfler 	sPorts[slot].write_condition.NotifyOne();
1216224aee3fSIngo Weinhold 		// make one spot in queue available again for write
1217224aee3fSIngo Weinhold 
1218e8885f20SAxel Dörfler 	locker.Unlock();
1219e8885f20SAxel Dörfler 
1220e8885f20SAxel Dörfler 	size_t size = copy_port_message(message, _code, buffer, bufferSize,
1221e8885f20SAxel Dörfler 		userCopy);
1222f28dd36bSAxel Dörfler 	T(Read(sPorts[slot], message->code, size));
1223e8885f20SAxel Dörfler 
1224e8885f20SAxel Dörfler 	put_port_message(message);
1225224aee3fSIngo Weinhold 	return size;
1226224aee3fSIngo Weinhold }
1227224aee3fSIngo Weinhold 
1228224aee3fSIngo Weinhold 
1229224aee3fSIngo Weinhold status_t
1230e8885f20SAxel Dörfler write_port(port_id id, int32 msgCode, const void* buffer, size_t bufferSize)
1231224aee3fSIngo Weinhold {
1232e8885f20SAxel Dörfler 	iovec vec = { (void*)buffer, bufferSize };
1233224aee3fSIngo Weinhold 
1234224aee3fSIngo Weinhold 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0);
1235224aee3fSIngo Weinhold }
1236224aee3fSIngo Weinhold 
1237224aee3fSIngo Weinhold 
1238224aee3fSIngo Weinhold status_t
1239e8885f20SAxel Dörfler write_port_etc(port_id id, int32 msgCode, const void* buffer,
1240224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1241224aee3fSIngo Weinhold {
1242e8885f20SAxel Dörfler 	iovec vec = { (void*)buffer, bufferSize };
1243224aee3fSIngo Weinhold 
1244224aee3fSIngo Weinhold 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout);
1245224aee3fSIngo Weinhold }
1246224aee3fSIngo Weinhold 
1247224aee3fSIngo Weinhold 
1248224aee3fSIngo Weinhold status_t
1249224aee3fSIngo Weinhold writev_port_etc(port_id id, int32 msgCode, const iovec* msgVecs,
1250e8885f20SAxel Dörfler 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1251224aee3fSIngo Weinhold {
1252224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1253224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1254224aee3fSIngo Weinhold 	if (bufferSize > PORT_MAX_MESSAGE_SIZE)
1255224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1256224aee3fSIngo Weinhold 
1257e8885f20SAxel Dörfler 	// mask irrelevant flags (for acquire_sem() usage)
1258e8885f20SAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1259e8885f20SAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1260f28dd36bSAxel Dörfler 	if ((flags & B_RELATIVE_TIMEOUT) != 0
1261f28dd36bSAxel Dörfler 		&& timeout != B_INFINITE_TIMEOUT && timeout > 0) {
1262f28dd36bSAxel Dörfler 		// Make the timeout absolute, since we have more than one step where
1263f28dd36bSAxel Dörfler 		// we might have to wait
1264f28dd36bSAxel Dörfler 		flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT;
1265f28dd36bSAxel Dörfler 		timeout += system_time();
1266f28dd36bSAxel Dörfler 	}
1267f28dd36bSAxel Dörfler 
1268e8885f20SAxel Dörfler 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0;
1269e8885f20SAxel Dörfler 
1270e8885f20SAxel Dörfler 	int32 slot = id % sMaxPorts;
1271f28dd36bSAxel Dörfler 	status_t status;
12721c61ec1aSIngo Weinhold 	port_message* message = NULL;
1273e8885f20SAxel Dörfler 
1274e8885f20SAxel Dörfler 	MutexLocker locker(sPorts[slot].lock);
1275224aee3fSIngo Weinhold 
1276224aee3fSIngo Weinhold 	if (sPorts[slot].id != id) {
1277224aee3fSIngo Weinhold 		TRACE(("write_port_etc: invalid port_id %ld\n", id));
1278224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1279224aee3fSIngo Weinhold 	}
1280224aee3fSIngo Weinhold 	if (is_port_closed(slot)) {
1281224aee3fSIngo Weinhold 		TRACE(("write_port_etc: port %ld closed\n", id));
1282224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1283224aee3fSIngo Weinhold 	}
1284224aee3fSIngo Weinhold 
1285f28dd36bSAxel Dörfler 	if (sPorts[slot].write_count <= 0) {
1286f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1287f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1288f28dd36bSAxel Dörfler 
1289f28dd36bSAxel Dörfler 		sPorts[slot].write_count--;
1290f28dd36bSAxel Dörfler 
1291e8885f20SAxel Dörfler 		// We need to block in order to wait for a free message slot
1292e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
1293e8885f20SAxel Dörfler 		sPorts[slot].write_condition.Add(&entry);
1294224aee3fSIngo Weinhold 
1295e8885f20SAxel Dörfler 		locker.Unlock();
1296224aee3fSIngo Weinhold 
1297f28dd36bSAxel Dörfler 		status = entry.Wait(flags, timeout);
1298224aee3fSIngo Weinhold 
1299e8885f20SAxel Dörfler 		locker.Lock();
1300e8885f20SAxel Dörfler 
13013ffeff07SIngo Weinhold 		if (sPorts[slot].id != id || is_port_closed(slot)) {
1302e8885f20SAxel Dörfler 			// the port is no longer there
1303f28dd36bSAxel Dörfler 			T(Write(sPorts[slot], 0, 0, B_BAD_PORT_ID));
1304224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1305224aee3fSIngo Weinhold 		}
1306224aee3fSIngo Weinhold 
1307*c3bc71d6SIngo Weinhold 		if (status != B_OK)
1308f28dd36bSAxel Dörfler 			goto error;
1309f28dd36bSAxel Dörfler 	} else
1310f28dd36bSAxel Dörfler 		sPorts[slot].write_count--;
1311e8885f20SAxel Dörfler 
1312f28dd36bSAxel Dörfler 	status = get_port_message(msgCode, bufferSize, flags, timeout,
1313f28dd36bSAxel Dörfler 		&message);
1314f28dd36bSAxel Dörfler 	if (status != B_OK)
1315f28dd36bSAxel Dörfler 		goto error;
1316224aee3fSIngo Weinhold 
13177727e08eSIngo Weinhold 	// sender credentials
1318e8885f20SAxel Dörfler 	message->sender = geteuid();
1319e8885f20SAxel Dörfler 	message->sender_group = getegid();
1320e8885f20SAxel Dörfler 	message->sender_team = team_get_current_team_id();
13217727e08eSIngo Weinhold 
1322224aee3fSIngo Weinhold 	if (bufferSize > 0) {
1323224aee3fSIngo Weinhold 		uint32 i;
1324224aee3fSIngo Weinhold 		if (userCopy) {
1325224aee3fSIngo Weinhold 			// copy from user memory
1326224aee3fSIngo Weinhold 			for (i = 0; i < vecCount; i++) {
1327224aee3fSIngo Weinhold 				size_t bytes = msgVecs[i].iov_len;
1328224aee3fSIngo Weinhold 				if (bytes > bufferSize)
1329224aee3fSIngo Weinhold 					bytes = bufferSize;
1330224aee3fSIngo Weinhold 
1331e8885f20SAxel Dörfler 				status_t status = user_memcpy(message->buffer,
1332e8885f20SAxel Dörfler 					msgVecs[i].iov_base, bytes);
1333e8885f20SAxel Dörfler 				if (status != B_OK) {
1334e8885f20SAxel Dörfler 					put_port_message(message);
1335f28dd36bSAxel Dörfler 					goto error;
133661de73e2SIngo Weinhold 				}
1337224aee3fSIngo Weinhold 
1338224aee3fSIngo Weinhold 				bufferSize -= bytes;
1339224aee3fSIngo Weinhold 				if (bufferSize == 0)
1340224aee3fSIngo Weinhold 					break;
1341224aee3fSIngo Weinhold 			}
1342224aee3fSIngo Weinhold 		} else {
1343224aee3fSIngo Weinhold 			// copy from kernel memory
1344224aee3fSIngo Weinhold 			for (i = 0; i < vecCount; i++) {
1345224aee3fSIngo Weinhold 				size_t bytes = msgVecs[i].iov_len;
1346224aee3fSIngo Weinhold 				if (bytes > bufferSize)
1347224aee3fSIngo Weinhold 					bytes = bufferSize;
1348224aee3fSIngo Weinhold 
1349e8885f20SAxel Dörfler 				memcpy(message->buffer, msgVecs[i].iov_base, bytes);
1350224aee3fSIngo Weinhold 
1351224aee3fSIngo Weinhold 				bufferSize -= bytes;
1352224aee3fSIngo Weinhold 				if (bufferSize == 0)
1353224aee3fSIngo Weinhold 					break;
1354224aee3fSIngo Weinhold 			}
1355224aee3fSIngo Weinhold 		}
1356224aee3fSIngo Weinhold 	}
1357224aee3fSIngo Weinhold 
1358e8885f20SAxel Dörfler 	sPorts[slot].messages.Add(message);
1359e8885f20SAxel Dörfler 	sPorts[slot].read_count++;
1360224aee3fSIngo Weinhold 
1361f28dd36bSAxel Dörfler 	T(Write(sPorts[slot], message->code, message->size, B_OK));
1362f28dd36bSAxel Dörfler 
1363224aee3fSIngo Weinhold 	notify_port_select_events(slot, B_EVENT_READ);
1364e8885f20SAxel Dörfler 	sPorts[slot].read_condition.NotifyOne();
1365e8885f20SAxel Dörfler 	return B_OK;
1366f28dd36bSAxel Dörfler 
1367f28dd36bSAxel Dörfler error:
1368f28dd36bSAxel Dörfler 	// Give up our slot in the queue again, and let someone else
1369f28dd36bSAxel Dörfler 	// try and fail
1370f28dd36bSAxel Dörfler 	T(Write(sPorts[slot], 0, 0, status));
1371f28dd36bSAxel Dörfler 	sPorts[slot].write_count++;
1372f28dd36bSAxel Dörfler 	notify_port_select_events(slot, B_EVENT_WRITE);
1373f28dd36bSAxel Dörfler 	sPorts[slot].write_condition.NotifyOne();
1374f28dd36bSAxel Dörfler 
1375f28dd36bSAxel Dörfler 	return status;
1376224aee3fSIngo Weinhold }
1377224aee3fSIngo Weinhold 
1378224aee3fSIngo Weinhold 
1379224aee3fSIngo Weinhold status_t
138025028839SAxel Dörfler set_port_owner(port_id id, team_id newTeamID)
1381224aee3fSIngo Weinhold {
138225028839SAxel Dörfler 	TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, newTeamID));
1383224aee3fSIngo Weinhold 
1384e8885f20SAxel Dörfler 	if (id < 0)
1385224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1386224aee3fSIngo Weinhold 
1387e8885f20SAxel Dörfler 	int32 slot = id % sMaxPorts;
1388224aee3fSIngo Weinhold 
1389e8885f20SAxel Dörfler 	MutexLocker locker(sPorts[slot].lock);
1390224aee3fSIngo Weinhold 
1391224aee3fSIngo Weinhold 	if (sPorts[slot].id != id) {
1392224aee3fSIngo Weinhold 		TRACE(("set_port_owner: invalid port_id %ld\n", id));
1393224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1394224aee3fSIngo Weinhold 	}
139525028839SAxel Dörfler 
139625028839SAxel Dörfler 	InterruptsSpinLocker teamLocker(gTeamSpinlock);
139725028839SAxel Dörfler 
139825028839SAxel Dörfler 	struct team* team = team_get_team_struct_locked(newTeamID);
139925028839SAxel Dörfler 	if (team == NULL) {
140025028839SAxel Dörfler 		T(OwnerChange(sPorts[slot], newTeamID, B_BAD_TEAM_ID));
1401e8885f20SAxel Dörfler 		return B_BAD_TEAM_ID;
1402f28dd36bSAxel Dörfler 	}
1403f28dd36bSAxel Dörfler 
1404224aee3fSIngo Weinhold 	// transfer ownership to other team
140525028839SAxel Dörfler 	list_remove_link(&sPorts[slot].team_link);
140625028839SAxel Dörfler 	list_add_item(&team->port_list, &sPorts[slot].team_link);
140725028839SAxel Dörfler 	sPorts[slot].owner = newTeamID;
1408224aee3fSIngo Weinhold 
140925028839SAxel Dörfler 	T(OwnerChange(sPorts[slot], newTeamID, B_OK));
1410e8885f20SAxel Dörfler 	return B_OK;
1411224aee3fSIngo Weinhold }
1412224aee3fSIngo Weinhold 
1413224aee3fSIngo Weinhold 
1414224aee3fSIngo Weinhold //	#pragma mark - syscalls
1415224aee3fSIngo Weinhold 
1416224aee3fSIngo Weinhold 
1417224aee3fSIngo Weinhold port_id
1418224aee3fSIngo Weinhold _user_create_port(int32 queueLength, const char *userName)
1419224aee3fSIngo Weinhold {
1420224aee3fSIngo Weinhold 	char name[B_OS_NAME_LENGTH];
1421224aee3fSIngo Weinhold 
1422224aee3fSIngo Weinhold 	if (userName == NULL)
1423224aee3fSIngo Weinhold 		return create_port(queueLength, NULL);
1424224aee3fSIngo Weinhold 
1425224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userName)
1426224aee3fSIngo Weinhold 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1427224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1428224aee3fSIngo Weinhold 
1429224aee3fSIngo Weinhold 	return create_port(queueLength, name);
1430224aee3fSIngo Weinhold }
1431224aee3fSIngo Weinhold 
1432224aee3fSIngo Weinhold 
1433224aee3fSIngo Weinhold status_t
1434224aee3fSIngo Weinhold _user_close_port(port_id id)
1435224aee3fSIngo Weinhold {
1436224aee3fSIngo Weinhold 	return close_port(id);
1437224aee3fSIngo Weinhold }
1438224aee3fSIngo Weinhold 
1439224aee3fSIngo Weinhold 
1440224aee3fSIngo Weinhold status_t
1441224aee3fSIngo Weinhold _user_delete_port(port_id id)
1442224aee3fSIngo Weinhold {
1443224aee3fSIngo Weinhold 	return delete_port(id);
1444224aee3fSIngo Weinhold }
1445224aee3fSIngo Weinhold 
1446224aee3fSIngo Weinhold 
1447224aee3fSIngo Weinhold port_id
1448224aee3fSIngo Weinhold _user_find_port(const char *userName)
1449224aee3fSIngo Weinhold {
1450224aee3fSIngo Weinhold 	char name[B_OS_NAME_LENGTH];
1451224aee3fSIngo Weinhold 
1452224aee3fSIngo Weinhold 	if (userName == NULL)
1453224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1454224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userName)
1455224aee3fSIngo Weinhold 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1456224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1457224aee3fSIngo Weinhold 
1458224aee3fSIngo Weinhold 	return find_port(name);
1459224aee3fSIngo Weinhold }
1460224aee3fSIngo Weinhold 
1461224aee3fSIngo Weinhold 
1462224aee3fSIngo Weinhold status_t
1463224aee3fSIngo Weinhold _user_get_port_info(port_id id, struct port_info *userInfo)
1464224aee3fSIngo Weinhold {
1465224aee3fSIngo Weinhold 	struct port_info info;
1466224aee3fSIngo Weinhold 	status_t status;
1467224aee3fSIngo Weinhold 
1468224aee3fSIngo Weinhold 	if (userInfo == NULL)
1469224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1470224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userInfo))
1471224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1472224aee3fSIngo Weinhold 
1473224aee3fSIngo Weinhold 	status = get_port_info(id, &info);
1474224aee3fSIngo Weinhold 
1475224aee3fSIngo Weinhold 	// copy back to user space
14764048494cSIngo Weinhold 	if (status == B_OK
14774048494cSIngo Weinhold 		&& user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK)
1478224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1479224aee3fSIngo Weinhold 
1480224aee3fSIngo Weinhold 	return status;
1481224aee3fSIngo Weinhold }
1482224aee3fSIngo Weinhold 
1483224aee3fSIngo Weinhold 
1484224aee3fSIngo Weinhold status_t
14854048494cSIngo Weinhold _user_get_next_port_info(team_id team, int32 *userCookie,
14864048494cSIngo Weinhold 	struct port_info *userInfo)
1487224aee3fSIngo Weinhold {
1488224aee3fSIngo Weinhold 	struct port_info info;
1489224aee3fSIngo Weinhold 	status_t status;
1490224aee3fSIngo Weinhold 	int32 cookie;
1491224aee3fSIngo Weinhold 
1492224aee3fSIngo Weinhold 	if (userCookie == NULL || userInfo == NULL)
1493224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1494224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo)
1495224aee3fSIngo Weinhold 		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
1496224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1497224aee3fSIngo Weinhold 
1498224aee3fSIngo Weinhold 	status = get_next_port_info(team, &cookie, &info);
1499224aee3fSIngo Weinhold 
1500224aee3fSIngo Weinhold 	// copy back to user space
1501224aee3fSIngo Weinhold 	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
15024048494cSIngo Weinhold 		|| (status == B_OK && user_memcpy(userInfo, &info,
15034048494cSIngo Weinhold 				sizeof(struct port_info)) < B_OK))
1504224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1505224aee3fSIngo Weinhold 
1506224aee3fSIngo Weinhold 	return status;
1507224aee3fSIngo Weinhold }
1508224aee3fSIngo Weinhold 
1509224aee3fSIngo Weinhold 
1510224aee3fSIngo Weinhold ssize_t
1511224aee3fSIngo Weinhold _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout)
1512224aee3fSIngo Weinhold {
15134048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
15144048494cSIngo Weinhold 
15154048494cSIngo Weinhold 	status_t status = port_buffer_size_etc(port, flags | B_CAN_INTERRUPT,
15164048494cSIngo Weinhold 		timeout);
15174048494cSIngo Weinhold 
15184048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1519224aee3fSIngo Weinhold }
1520224aee3fSIngo Weinhold 
1521224aee3fSIngo Weinhold 
1522224aee3fSIngo Weinhold ssize_t
1523224aee3fSIngo Weinhold _user_port_count(port_id port)
1524224aee3fSIngo Weinhold {
1525224aee3fSIngo Weinhold 	return port_count(port);
1526224aee3fSIngo Weinhold }
1527224aee3fSIngo Weinhold 
1528224aee3fSIngo Weinhold 
1529224aee3fSIngo Weinhold status_t
1530224aee3fSIngo Weinhold _user_set_port_owner(port_id port, team_id team)
1531224aee3fSIngo Weinhold {
1532224aee3fSIngo Weinhold 	return set_port_owner(port, team);
1533224aee3fSIngo Weinhold }
1534224aee3fSIngo Weinhold 
1535224aee3fSIngo Weinhold 
1536224aee3fSIngo Weinhold ssize_t
1537224aee3fSIngo Weinhold _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer,
1538224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1539224aee3fSIngo Weinhold {
1540224aee3fSIngo Weinhold 	int32 messageCode;
1541224aee3fSIngo Weinhold 	ssize_t	bytesRead;
1542224aee3fSIngo Weinhold 
15434048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
15444048494cSIngo Weinhold 
1545224aee3fSIngo Weinhold 	if (userBuffer == NULL && bufferSize != 0)
1546224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1547224aee3fSIngo Weinhold 	if ((userCode != NULL && !IS_USER_ADDRESS(userCode))
1548224aee3fSIngo Weinhold 		|| (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)))
1549224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1550224aee3fSIngo Weinhold 
1551224aee3fSIngo Weinhold 	bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize,
1552224aee3fSIngo Weinhold 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1553224aee3fSIngo Weinhold 
1554224aee3fSIngo Weinhold 	if (bytesRead >= 0 && userCode != NULL
1555224aee3fSIngo Weinhold 		&& user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK)
1556224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1557224aee3fSIngo Weinhold 
15584048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(bytesRead, timeout);
1559224aee3fSIngo Weinhold }
1560224aee3fSIngo Weinhold 
1561224aee3fSIngo Weinhold 
1562224aee3fSIngo Weinhold status_t
1563224aee3fSIngo Weinhold _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer,
1564224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1565224aee3fSIngo Weinhold {
1566224aee3fSIngo Weinhold 	iovec vec = { (void *)userBuffer, bufferSize };
1567224aee3fSIngo Weinhold 
15684048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
15694048494cSIngo Weinhold 
1570224aee3fSIngo Weinhold 	if (userBuffer == NULL && bufferSize != 0)
1571224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1572224aee3fSIngo Weinhold 	if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))
1573224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1574224aee3fSIngo Weinhold 
15754048494cSIngo Weinhold 	status_t status = writev_port_etc(port, messageCode, &vec, 1, bufferSize,
1576224aee3fSIngo Weinhold 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
15774048494cSIngo Weinhold 
15784048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1579224aee3fSIngo Weinhold }
1580224aee3fSIngo Weinhold 
1581224aee3fSIngo Weinhold 
1582224aee3fSIngo Weinhold status_t
1583224aee3fSIngo Weinhold _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs,
1584224aee3fSIngo Weinhold 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1585224aee3fSIngo Weinhold {
15864048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
1587224aee3fSIngo Weinhold 
1588224aee3fSIngo Weinhold 	if (userVecs == NULL && bufferSize != 0)
1589224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1590224aee3fSIngo Weinhold 	if (userVecs != NULL && !IS_USER_ADDRESS(userVecs))
1591224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1592224aee3fSIngo Weinhold 
15934048494cSIngo Weinhold 	iovec *vecs = NULL;
1594224aee3fSIngo Weinhold 	if (userVecs && vecCount != 0) {
1595224aee3fSIngo Weinhold 		vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
1596224aee3fSIngo Weinhold 		if (vecs == NULL)
1597224aee3fSIngo Weinhold 			return B_NO_MEMORY;
1598224aee3fSIngo Weinhold 
1599224aee3fSIngo Weinhold 		if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) {
1600224aee3fSIngo Weinhold 			free(vecs);
1601224aee3fSIngo Weinhold 			return B_BAD_ADDRESS;
1602224aee3fSIngo Weinhold 		}
1603224aee3fSIngo Weinhold 	}
16044048494cSIngo Weinhold 
16054048494cSIngo Weinhold 	status_t status = writev_port_etc(port, messageCode, vecs, vecCount,
16064048494cSIngo Weinhold 		bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT,
16074048494cSIngo Weinhold 		timeout);
1608224aee3fSIngo Weinhold 
1609224aee3fSIngo Weinhold 	free(vecs);
16104048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1611224aee3fSIngo Weinhold }
16127727e08eSIngo Weinhold 
16137727e08eSIngo Weinhold 
16147727e08eSIngo Weinhold status_t
16157727e08eSIngo Weinhold _user_get_port_message_info_etc(port_id port, port_message_info *userInfo,
16167727e08eSIngo Weinhold 	size_t infoSize, uint32 flags, bigtime_t timeout)
16177727e08eSIngo Weinhold {
16187727e08eSIngo Weinhold 	if (userInfo == NULL || infoSize != sizeof(port_message_info))
16197727e08eSIngo Weinhold 		return B_BAD_VALUE;
16207727e08eSIngo Weinhold 
16217727e08eSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
16227727e08eSIngo Weinhold 
16237727e08eSIngo Weinhold 	port_message_info info;
16247727e08eSIngo Weinhold 	status_t error = _get_port_message_info_etc(port, &info, sizeof(info),
16257727e08eSIngo Weinhold 		flags | B_CAN_INTERRUPT, timeout);
16267727e08eSIngo Weinhold 
16277727e08eSIngo Weinhold 	// copy info to userland
16287727e08eSIngo Weinhold 	if (error == B_OK && (!IS_USER_ADDRESS(userInfo)
16297727e08eSIngo Weinhold 			|| user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) {
16307727e08eSIngo Weinhold 		error = B_BAD_ADDRESS;
16317727e08eSIngo Weinhold 	}
16327727e08eSIngo Weinhold 
16337727e08eSIngo Weinhold 	return syscall_restart_handle_timeout_post(error, timeout);
16347727e08eSIngo Weinhold }
1635