xref: /haiku/src/system/kernel/port.cpp (revision fae2ce1945fb1f791d4ccbab8422bcc7d7de8a3f)
1224aee3fSIngo Weinhold /*
224df6592SIngo Weinhold  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
37198f765SAxel Dörfler  * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de.
4224aee3fSIngo Weinhold  * Distributed under the terms of the MIT License.
5224aee3fSIngo Weinhold  *
6224aee3fSIngo Weinhold  * Copyright 2001, Mark-Jan Bastian. All rights reserved.
7224aee3fSIngo Weinhold  * Distributed under the terms of the NewOS License.
8224aee3fSIngo Weinhold  */
9224aee3fSIngo Weinhold 
10f28dd36bSAxel Dörfler 
11224aee3fSIngo Weinhold /*!	Ports for IPC */
12224aee3fSIngo Weinhold 
13f28dd36bSAxel Dörfler 
144048494cSIngo Weinhold #include <port.h>
154048494cSIngo Weinhold 
164048494cSIngo Weinhold #include <ctype.h>
174048494cSIngo Weinhold #include <iovec.h>
184048494cSIngo Weinhold #include <stdlib.h>
194048494cSIngo Weinhold #include <string.h>
20224aee3fSIngo Weinhold 
21224aee3fSIngo Weinhold #include <OS.h>
22224aee3fSIngo Weinhold 
2324df6592SIngo Weinhold #include <AutoDeleter.h>
2424df6592SIngo Weinhold 
25224aee3fSIngo Weinhold #include <arch/int.h>
26e8885f20SAxel Dörfler #include <heap.h>
274048494cSIngo Weinhold #include <kernel.h>
2851755cf8SAxel Dörfler #include <Notifications.h>
294048494cSIngo Weinhold #include <sem.h>
304048494cSIngo Weinhold #include <syscall_restart.h>
314048494cSIngo Weinhold #include <team.h>
32f28dd36bSAxel Dörfler #include <tracing.h>
33b4ec7b8eSIngo Weinhold #include <util/AutoLock.h>
344048494cSIngo Weinhold #include <util/list.h>
357198f765SAxel Dörfler #include <vm/vm.h>
36224aee3fSIngo Weinhold #include <wait_for_objects.h>
37224aee3fSIngo Weinhold 
38224aee3fSIngo Weinhold 
39224aee3fSIngo Weinhold //#define TRACE_PORTS
40224aee3fSIngo Weinhold #ifdef TRACE_PORTS
41224aee3fSIngo Weinhold #	define TRACE(x) dprintf x
42224aee3fSIngo Weinhold #else
43224aee3fSIngo Weinhold #	define TRACE(x)
44224aee3fSIngo Weinhold #endif
45224aee3fSIngo Weinhold 
46224aee3fSIngo Weinhold 
4724df6592SIngo Weinhold // Locking:
4824df6592SIngo Weinhold // * sPortsLock: Protects the sPorts hash table, Team::port_list, and
4924df6592SIngo Weinhold //   Port::owner.
5024df6592SIngo Weinhold // * Port::lock: Protects all Port members save team_link, hash_link, and lock.
5124df6592SIngo Weinhold //   id is immutable.
52cd3e02caSMichael Lotz // * sPortQuotaLock: Protects sTotalSpaceInUse, sAreaChangeCounter,
53cd3e02caSMichael Lotz //   sWaitingForSpace and the critical section of creating/adding areas for the
54cd3e02caSMichael Lotz //   port heap in the grow case. It also has to be held when reading
55cd3e02caSMichael Lotz //   sWaitingForSpace to determine whether or not to notify the
56cd3e02caSMichael Lotz //   sNoSpaceCondition condition variable.
5724df6592SIngo Weinhold //
5824df6592SIngo Weinhold // The locking order is sPortsLock -> Port::lock. A port must be looked up
5924df6592SIngo Weinhold // in sPorts and locked with sPortsLock held. Afterwards sPortsLock can be
6024df6592SIngo Weinhold // dropped, unless any field guarded by sPortsLock is accessed.
6124df6592SIngo Weinhold 
6224df6592SIngo Weinhold 
6324df6592SIngo Weinhold struct port_message;
6424df6592SIngo Weinhold 
6524df6592SIngo Weinhold 
6624df6592SIngo Weinhold static void put_port_message(port_message* message);
6724df6592SIngo Weinhold 
6824df6592SIngo Weinhold 
69e8885f20SAxel Dörfler struct port_message : DoublyLinkedListLinkImpl<port_message> {
70224aee3fSIngo Weinhold 	int32				code;
71224aee3fSIngo Weinhold 	size_t				size;
727727e08eSIngo Weinhold 	uid_t				sender;
737727e08eSIngo Weinhold 	gid_t				sender_group;
747727e08eSIngo Weinhold 	team_id				sender_team;
75e8885f20SAxel Dörfler 	char				buffer[0];
76e8885f20SAxel Dörfler };
77e8885f20SAxel Dörfler 
78e8885f20SAxel Dörfler typedef DoublyLinkedList<port_message> MessageList;
79224aee3fSIngo Weinhold 
8024df6592SIngo Weinhold 
8124df6592SIngo Weinhold struct Port {
8286a999adSAxel Dörfler 	struct list_link	team_link;
8324df6592SIngo Weinhold 	Port*				hash_link;
84224aee3fSIngo Weinhold 	port_id				id;
85224aee3fSIngo Weinhold 	team_id				owner;
86224aee3fSIngo Weinhold 	int32		 		capacity;
87e8885f20SAxel Dörfler 	mutex				lock;
887d592ec4SAxel Dörfler 	uint32				read_count;
89e8885f20SAxel Dörfler 	int32				write_count;
90e8885f20SAxel Dörfler 	ConditionVariable	read_condition;
91e8885f20SAxel Dörfler 	ConditionVariable	write_condition;
92e8885f20SAxel Dörfler 	int32				total_count;
93e8885f20SAxel Dörfler 		// messages read from port since creation
94224aee3fSIngo Weinhold 	select_info*		select_infos;
95e8885f20SAxel Dörfler 	MessageList			messages;
9624df6592SIngo Weinhold 
9724df6592SIngo Weinhold 	Port(team_id owner, int32 queueLength, char* name)
9824df6592SIngo Weinhold 		:
9924df6592SIngo Weinhold 		owner(owner),
10024df6592SIngo Weinhold 		capacity(queueLength),
10124df6592SIngo Weinhold 		read_count(0),
10224df6592SIngo Weinhold 		write_count(queueLength),
10324df6592SIngo Weinhold 		total_count(0),
10424df6592SIngo Weinhold 		select_infos(NULL)
10524df6592SIngo Weinhold 	{
10624df6592SIngo Weinhold 		// id is initialized when the caller adds the port to the hash table
10724df6592SIngo Weinhold 
10824df6592SIngo Weinhold 		mutex_init(&lock, name);
10924df6592SIngo Weinhold 		read_condition.Init(this, "port read");
11024df6592SIngo Weinhold 		write_condition.Init(this, "port write");
11124df6592SIngo Weinhold 	}
11224df6592SIngo Weinhold 
11324df6592SIngo Weinhold 	~Port()
11424df6592SIngo Weinhold 	{
11524df6592SIngo Weinhold 		while (port_message* message = messages.RemoveHead())
11624df6592SIngo Weinhold 			put_port_message(message);
11724df6592SIngo Weinhold 
11824df6592SIngo Weinhold 		free((char*)lock.name);
11924df6592SIngo Weinhold 		lock.name = NULL;
12024df6592SIngo Weinhold 	}
121224aee3fSIngo Weinhold };
122224aee3fSIngo Weinhold 
12324df6592SIngo Weinhold 
12424df6592SIngo Weinhold struct PortHashDefinition {
12524df6592SIngo Weinhold 	typedef port_id		KeyType;
12624df6592SIngo Weinhold 	typedef	Port		ValueType;
12724df6592SIngo Weinhold 
12824df6592SIngo Weinhold 	size_t HashKey(port_id key) const
12924df6592SIngo Weinhold 	{
13024df6592SIngo Weinhold 		return key;
13124df6592SIngo Weinhold 	}
13224df6592SIngo Weinhold 
13324df6592SIngo Weinhold 	size_t Hash(Port* value) const
13424df6592SIngo Weinhold 	{
13524df6592SIngo Weinhold 		return HashKey(value->id);
13624df6592SIngo Weinhold 	}
13724df6592SIngo Weinhold 
13824df6592SIngo Weinhold 	bool Compare(port_id key, Port* value) const
13924df6592SIngo Weinhold 	{
14024df6592SIngo Weinhold 		return value->id == key;
14124df6592SIngo Weinhold 	}
14224df6592SIngo Weinhold 
14324df6592SIngo Weinhold 	Port*& GetLink(Port* value) const
14424df6592SIngo Weinhold 	{
14524df6592SIngo Weinhold 		return value->hash_link;
14624df6592SIngo Weinhold 	}
14724df6592SIngo Weinhold };
14824df6592SIngo Weinhold 
14924df6592SIngo Weinhold typedef BOpenHashTable<PortHashDefinition> PortHashTable;
15024df6592SIngo Weinhold 
15124df6592SIngo Weinhold 
15251755cf8SAxel Dörfler class PortNotificationService : public DefaultNotificationService {
15351755cf8SAxel Dörfler public:
15451755cf8SAxel Dörfler 							PortNotificationService();
15551755cf8SAxel Dörfler 
15651755cf8SAxel Dörfler 			void			Notify(uint32 opcode, port_id team);
15751755cf8SAxel Dörfler };
158224aee3fSIngo Weinhold 
159f28dd36bSAxel Dörfler 
160f28dd36bSAxel Dörfler #if PORT_TRACING
161f28dd36bSAxel Dörfler namespace PortTracing {
162f28dd36bSAxel Dörfler 
163f28dd36bSAxel Dörfler class Create : public AbstractTraceEntry {
164f28dd36bSAxel Dörfler public:
16524df6592SIngo Weinhold 	Create(Port* port)
166f28dd36bSAxel Dörfler 		:
16724df6592SIngo Weinhold 		fID(port->id),
16824df6592SIngo Weinhold 		fOwner(port->owner),
16924df6592SIngo Weinhold 		fCapacity(port->capacity)
170f28dd36bSAxel Dörfler 	{
17124df6592SIngo Weinhold 		fName = alloc_tracing_buffer_strcpy(port->lock.name, B_OS_NAME_LENGTH,
172f28dd36bSAxel Dörfler 			false);
173f28dd36bSAxel Dörfler 
174f28dd36bSAxel Dörfler 		Initialized();
175f28dd36bSAxel Dörfler 	}
176f28dd36bSAxel Dörfler 
177f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
178f28dd36bSAxel Dörfler 	{
179f28dd36bSAxel Dörfler 		out.Print("port %ld created, name \"%s\", owner %ld, capacity %ld",
180f28dd36bSAxel Dörfler 			fID, fName, fOwner, fCapacity);
181f28dd36bSAxel Dörfler 	}
182f28dd36bSAxel Dörfler 
183f28dd36bSAxel Dörfler private:
184f28dd36bSAxel Dörfler 	port_id				fID;
185f28dd36bSAxel Dörfler 	char*				fName;
186f28dd36bSAxel Dörfler 	team_id				fOwner;
187f28dd36bSAxel Dörfler 	int32		 		fCapacity;
188f28dd36bSAxel Dörfler };
189f28dd36bSAxel Dörfler 
190f28dd36bSAxel Dörfler 
191f28dd36bSAxel Dörfler class Delete : public AbstractTraceEntry {
192f28dd36bSAxel Dörfler public:
19324df6592SIngo Weinhold 	Delete(Port* port)
194f28dd36bSAxel Dörfler 		:
19524df6592SIngo Weinhold 		fID(port->id)
196f28dd36bSAxel Dörfler 	{
197f28dd36bSAxel Dörfler 		Initialized();
198f28dd36bSAxel Dörfler 	}
199f28dd36bSAxel Dörfler 
200f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
201f28dd36bSAxel Dörfler 	{
202f28dd36bSAxel Dörfler 		out.Print("port %ld deleted", fID);
203f28dd36bSAxel Dörfler 	}
204f28dd36bSAxel Dörfler 
205f28dd36bSAxel Dörfler private:
206f28dd36bSAxel Dörfler 	port_id				fID;
207f28dd36bSAxel Dörfler };
208f28dd36bSAxel Dörfler 
209f28dd36bSAxel Dörfler 
210f28dd36bSAxel Dörfler class Read : public AbstractTraceEntry {
211f28dd36bSAxel Dörfler public:
21224df6592SIngo Weinhold 	Read(port_id id, int32 readCount, int32 writeCount, int32 code,
21324df6592SIngo Weinhold 		ssize_t result)
214f28dd36bSAxel Dörfler 		:
21524df6592SIngo Weinhold 		fID(id),
21624df6592SIngo Weinhold 		fReadCount(readCount),
21724df6592SIngo Weinhold 		fWriteCount(writeCount),
218f28dd36bSAxel Dörfler 		fCode(code),
219f28dd36bSAxel Dörfler 		fResult(result)
220f28dd36bSAxel Dörfler 	{
221f28dd36bSAxel Dörfler 		Initialized();
222f28dd36bSAxel Dörfler 	}
223f28dd36bSAxel Dörfler 
224f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
225f28dd36bSAxel Dörfler 	{
226f28dd36bSAxel Dörfler 		out.Print("port %ld read, read %ld, write %ld, code %lx: %ld",
227f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fResult);
228f28dd36bSAxel Dörfler 	}
229f28dd36bSAxel Dörfler 
230f28dd36bSAxel Dörfler private:
231f28dd36bSAxel Dörfler 	port_id				fID;
232f28dd36bSAxel Dörfler 	int32				fReadCount;
233f28dd36bSAxel Dörfler 	int32				fWriteCount;
234f28dd36bSAxel Dörfler 	int32				fCode;
235f28dd36bSAxel Dörfler 	ssize_t				fResult;
236f28dd36bSAxel Dörfler };
237f28dd36bSAxel Dörfler 
238f28dd36bSAxel Dörfler 
239f28dd36bSAxel Dörfler class Write : public AbstractTraceEntry {
240f28dd36bSAxel Dörfler public:
24124df6592SIngo Weinhold 	Write(port_id id, int32 readCount, int32 writeCount, int32 code,
24224df6592SIngo Weinhold 		size_t bufferSize, ssize_t result)
243f28dd36bSAxel Dörfler 		:
24424df6592SIngo Weinhold 		fID(id),
24524df6592SIngo Weinhold 		fReadCount(readCount),
24624df6592SIngo Weinhold 		fWriteCount(writeCount),
247f28dd36bSAxel Dörfler 		fCode(code),
248f28dd36bSAxel Dörfler 		fBufferSize(bufferSize),
249f28dd36bSAxel Dörfler 		fResult(result)
250f28dd36bSAxel Dörfler 	{
251f28dd36bSAxel Dörfler 		Initialized();
252f28dd36bSAxel Dörfler 	}
253f28dd36bSAxel Dörfler 
254f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
255f28dd36bSAxel Dörfler 	{
256f28dd36bSAxel Dörfler 		out.Print("port %ld write, read %ld, write %ld, code %lx, size %ld: %ld",
257f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fBufferSize, fResult);
258f28dd36bSAxel Dörfler 	}
259f28dd36bSAxel Dörfler 
260f28dd36bSAxel Dörfler private:
261f28dd36bSAxel Dörfler 	port_id				fID;
262f28dd36bSAxel Dörfler 	int32				fReadCount;
263f28dd36bSAxel Dörfler 	int32				fWriteCount;
264f28dd36bSAxel Dörfler 	int32				fCode;
265f28dd36bSAxel Dörfler 	size_t				fBufferSize;
266f28dd36bSAxel Dörfler 	ssize_t				fResult;
267f28dd36bSAxel Dörfler };
268f28dd36bSAxel Dörfler 
269f28dd36bSAxel Dörfler 
270f28dd36bSAxel Dörfler class Info : public AbstractTraceEntry {
271f28dd36bSAxel Dörfler public:
27224df6592SIngo Weinhold 	Info(port_id id, int32 readCount, int32 writeCount, int32 code,
27324df6592SIngo Weinhold 		ssize_t result)
274f28dd36bSAxel Dörfler 		:
27524df6592SIngo Weinhold 		fID(id),
27624df6592SIngo Weinhold 		fReadCount(readCount),
27724df6592SIngo Weinhold 		fWriteCount(writeCount),
278f28dd36bSAxel Dörfler 		fCode(code),
279f28dd36bSAxel Dörfler 		fResult(result)
280f28dd36bSAxel Dörfler 	{
281f28dd36bSAxel Dörfler 		Initialized();
282f28dd36bSAxel Dörfler 	}
283f28dd36bSAxel Dörfler 
284f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
285f28dd36bSAxel Dörfler 	{
286f28dd36bSAxel Dörfler 		out.Print("port %ld info, read %ld, write %ld, code %lx: %ld",
287f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fResult);
288f28dd36bSAxel Dörfler 	}
289f28dd36bSAxel Dörfler 
290f28dd36bSAxel Dörfler private:
291f28dd36bSAxel Dörfler 	port_id				fID;
292f28dd36bSAxel Dörfler 	int32				fReadCount;
293f28dd36bSAxel Dörfler 	int32				fWriteCount;
294f28dd36bSAxel Dörfler 	int32				fCode;
295f28dd36bSAxel Dörfler 	ssize_t				fResult;
296f28dd36bSAxel Dörfler };
297f28dd36bSAxel Dörfler 
298f28dd36bSAxel Dörfler 
299f28dd36bSAxel Dörfler class OwnerChange : public AbstractTraceEntry {
300f28dd36bSAxel Dörfler public:
30124df6592SIngo Weinhold 	OwnerChange(Port* port, team_id newOwner, status_t status)
302f28dd36bSAxel Dörfler 		:
30324df6592SIngo Weinhold 		fID(port->id),
30424df6592SIngo Weinhold 		fOldOwner(port->owner),
305f28dd36bSAxel Dörfler 		fNewOwner(newOwner),
306f28dd36bSAxel Dörfler 		fStatus(status)
307f28dd36bSAxel Dörfler 	{
308f28dd36bSAxel Dörfler 		Initialized();
309f28dd36bSAxel Dörfler 	}
310f28dd36bSAxel Dörfler 
311f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
312f28dd36bSAxel Dörfler 	{
313f28dd36bSAxel Dörfler 		out.Print("port %ld owner change from %ld to %ld: %s", fID, fOldOwner,
314f28dd36bSAxel Dörfler 			fNewOwner, strerror(fStatus));
315f28dd36bSAxel Dörfler 	}
316f28dd36bSAxel Dörfler 
317f28dd36bSAxel Dörfler private:
318f28dd36bSAxel Dörfler 	port_id				fID;
319f28dd36bSAxel Dörfler 	team_id				fOldOwner;
320f28dd36bSAxel Dörfler 	team_id				fNewOwner;
321f28dd36bSAxel Dörfler 	status_t	 		fStatus;
322f28dd36bSAxel Dörfler };
323f28dd36bSAxel Dörfler 
324f28dd36bSAxel Dörfler }	// namespace PortTracing
325f28dd36bSAxel Dörfler 
326f28dd36bSAxel Dörfler #	define T(x) new(std::nothrow) PortTracing::x;
327f28dd36bSAxel Dörfler #else
328f28dd36bSAxel Dörfler #	define T(x) ;
329f28dd36bSAxel Dörfler #endif
330f28dd36bSAxel Dörfler 
331f28dd36bSAxel Dörfler 
332e8885f20SAxel Dörfler static const size_t kInitialPortBufferSize = 4 * 1024 * 1024;
333f28dd36bSAxel Dörfler static const size_t kTotalSpaceLimit = 64 * 1024 * 1024;
334f28dd36bSAxel Dörfler static const size_t kTeamSpaceLimit = 8 * 1024 * 1024;
335f28dd36bSAxel Dörfler static const size_t kBufferGrowRate = kInitialPortBufferSize;
336f28dd36bSAxel Dörfler 
337224aee3fSIngo Weinhold #define MAX_QUEUE_LENGTH 4096
3385f87692cSIngo Weinhold #define PORT_MAX_MESSAGE_SIZE (256 * 1024)
339224aee3fSIngo Weinhold 
340224aee3fSIngo Weinhold static int32 sMaxPorts = 4096;
341224aee3fSIngo Weinhold static int32 sUsedPorts = 0;
342224aee3fSIngo Weinhold 
34324df6592SIngo Weinhold static PortHashTable sPorts;
344e8885f20SAxel Dörfler static heap_allocator* sPortAllocator;
345f28dd36bSAxel Dörfler static ConditionVariable sNoSpaceCondition;
346cd3e02caSMichael Lotz static int32 sTotalSpaceInUse;
347cd3e02caSMichael Lotz static int32 sAreaChangeCounter;
348cd3e02caSMichael Lotz static int32 sWaitingForSpace;
34924df6592SIngo Weinhold static port_id sNextPortID = 1;
350224aee3fSIngo Weinhold static bool sPortsActive = false;
351e8885f20SAxel Dörfler static mutex sPortsLock = MUTEX_INITIALIZER("ports list");
352cd3e02caSMichael Lotz static mutex sPortQuotaLock = MUTEX_INITIALIZER("port quota");
353224aee3fSIngo Weinhold 
35451755cf8SAxel Dörfler static PortNotificationService sNotificationService;
35551755cf8SAxel Dörfler 
356224aee3fSIngo Weinhold 
35751755cf8SAxel Dörfler //	#pragma mark - TeamNotificationService
35851755cf8SAxel Dörfler 
35951755cf8SAxel Dörfler 
36051755cf8SAxel Dörfler PortNotificationService::PortNotificationService()
361e8885f20SAxel Dörfler 	:
362e8885f20SAxel Dörfler 	DefaultNotificationService("ports")
36351755cf8SAxel Dörfler {
36451755cf8SAxel Dörfler }
36551755cf8SAxel Dörfler 
36651755cf8SAxel Dörfler 
36751755cf8SAxel Dörfler void
36851755cf8SAxel Dörfler PortNotificationService::Notify(uint32 opcode, port_id port)
36951755cf8SAxel Dörfler {
370*fae2ce19SIngo Weinhold 	char eventBuffer[128];
37151755cf8SAxel Dörfler 	KMessage event;
37251755cf8SAxel Dörfler 	event.SetTo(eventBuffer, sizeof(eventBuffer), PORT_MONITOR);
373efd536ffSIngo Weinhold 	event.AddInt32("event", opcode);
37451755cf8SAxel Dörfler 	event.AddInt32("port", port);
37551755cf8SAxel Dörfler 
376efd536ffSIngo Weinhold 	DefaultNotificationService::Notify(event, opcode);
37751755cf8SAxel Dörfler }
37851755cf8SAxel Dörfler 
37951755cf8SAxel Dörfler 
38051755cf8SAxel Dörfler //	#pragma mark -
38151755cf8SAxel Dörfler 
38251755cf8SAxel Dörfler 
383224aee3fSIngo Weinhold static int
384224aee3fSIngo Weinhold dump_port_list(int argc, char** argv)
385224aee3fSIngo Weinhold {
386224aee3fSIngo Weinhold 	const char* name = NULL;
387224aee3fSIngo Weinhold 	team_id owner = -1;
388224aee3fSIngo Weinhold 
389224aee3fSIngo Weinhold 	if (argc > 2) {
390224aee3fSIngo Weinhold 		if (!strcmp(argv[1], "team") || !strcmp(argv[1], "owner"))
391224aee3fSIngo Weinhold 			owner = strtoul(argv[2], NULL, 0);
392224aee3fSIngo Weinhold 		else if (!strcmp(argv[1], "name"))
393224aee3fSIngo Weinhold 			name = argv[2];
394224aee3fSIngo Weinhold 	} else if (argc > 1)
395224aee3fSIngo Weinhold 		owner = strtoul(argv[1], NULL, 0);
396224aee3fSIngo Weinhold 
397e8885f20SAxel Dörfler 	kprintf("port             id  cap  read-cnt  write-cnt   total   team  "
398e8885f20SAxel Dörfler 		"name\n");
399224aee3fSIngo Weinhold 
40024df6592SIngo Weinhold 	for (PortHashTable::Iterator it = sPorts.GetIterator();
40124df6592SIngo Weinhold 		Port* port = it.Next();) {
40224df6592SIngo Weinhold 		if ((owner != -1 && port->owner != owner)
403e8885f20SAxel Dörfler 			|| (name != NULL && strstr(port->lock.name, name) == NULL))
404224aee3fSIngo Weinhold 			continue;
405224aee3fSIngo Weinhold 
406e8885f20SAxel Dörfler 		kprintf("%p %8ld %4ld %9ld %9ld %8ld %6ld  %s\n", port,
407e8885f20SAxel Dörfler 			port->id, port->capacity, port->read_count, port->write_count,
408e8885f20SAxel Dörfler 			port->total_count, port->owner, port->lock.name);
409224aee3fSIngo Weinhold 	}
410e8885f20SAxel Dörfler 
411224aee3fSIngo Weinhold 	return 0;
412224aee3fSIngo Weinhold }
413224aee3fSIngo Weinhold 
414224aee3fSIngo Weinhold 
415224aee3fSIngo Weinhold static void
41624df6592SIngo Weinhold _dump_port_info(Port* port)
417224aee3fSIngo Weinhold {
418224aee3fSIngo Weinhold 	kprintf("PORT: %p\n", port);
4193cad4daeSMarcus Overhagen 	kprintf(" id:              %ld\n", port->id);
420e8885f20SAxel Dörfler 	kprintf(" name:            \"%s\"\n", port->lock.name);
4213cad4daeSMarcus Overhagen 	kprintf(" owner:           %ld\n", port->owner);
422224aee3fSIngo Weinhold 	kprintf(" capacity:        %ld\n", port->capacity);
423e8885f20SAxel Dörfler 	kprintf(" read_count:      %ld\n", port->read_count);
424e8885f20SAxel Dörfler 	kprintf(" write_count:     %ld\n", port->write_count);
425224aee3fSIngo Weinhold 	kprintf(" total count:     %ld\n", port->total_count);
4265aee691eSIngo Weinhold 
427f28dd36bSAxel Dörfler 	if (!port->messages.IsEmpty()) {
428f28dd36bSAxel Dörfler 		kprintf("messages:\n");
429f28dd36bSAxel Dörfler 
430f28dd36bSAxel Dörfler 		MessageList::Iterator iterator = port->messages.GetIterator();
431f28dd36bSAxel Dörfler 		while (port_message* message = iterator.Next()) {
432f28dd36bSAxel Dörfler 			kprintf(" %p  %08lx  %ld\n", message, message->code, message->size);
433f28dd36bSAxel Dörfler 		}
434f28dd36bSAxel Dörfler 	}
435f28dd36bSAxel Dörfler 
4365aee691eSIngo Weinhold 	set_debug_variable("_port", (addr_t)port);
4375aee691eSIngo Weinhold 	set_debug_variable("_portID", port->id);
4385aee691eSIngo Weinhold 	set_debug_variable("_owner", port->owner);
439224aee3fSIngo Weinhold }
440224aee3fSIngo Weinhold 
441224aee3fSIngo Weinhold 
442224aee3fSIngo Weinhold static int
443224aee3fSIngo Weinhold dump_port_info(int argc, char** argv)
444224aee3fSIngo Weinhold {
445e8885f20SAxel Dörfler 	ConditionVariable* condition = NULL;
446f28dd36bSAxel Dörfler 	const char* name = NULL;
447224aee3fSIngo Weinhold 
448224aee3fSIngo Weinhold 	if (argc < 2) {
449ce637fdaSIngo Weinhold 		print_debugger_command_usage(argv[0]);
450224aee3fSIngo Weinhold 		return 0;
451224aee3fSIngo Weinhold 	}
452224aee3fSIngo Weinhold 
453224aee3fSIngo Weinhold 	if (argc > 2) {
454224aee3fSIngo Weinhold 		if (!strcmp(argv[1], "address")) {
45524df6592SIngo Weinhold 			_dump_port_info((Port*)parse_expression(argv[2]));
456224aee3fSIngo Weinhold 			return 0;
457e8885f20SAxel Dörfler 		} else if (!strcmp(argv[1], "condition"))
458f28dd36bSAxel Dörfler 			condition = (ConditionVariable*)parse_expression(argv[2]);
459224aee3fSIngo Weinhold 		else if (!strcmp(argv[1], "name"))
460224aee3fSIngo Weinhold 			name = argv[2];
461f28dd36bSAxel Dörfler 	} else if (parse_expression(argv[1]) > 0) {
462224aee3fSIngo Weinhold 		// if the argument looks like a number, treat it as such
463f28dd36bSAxel Dörfler 		int32 num = parse_expression(argv[1]);
46424df6592SIngo Weinhold 		Port* port = sPorts.Lookup(num);
46524df6592SIngo Weinhold 		if (port == NULL) {
466224aee3fSIngo Weinhold 			kprintf("port %ld (%#lx) doesn't exist!\n", num, num);
467224aee3fSIngo Weinhold 			return 0;
468224aee3fSIngo Weinhold 		}
46924df6592SIngo Weinhold 		_dump_port_info(port);
470224aee3fSIngo Weinhold 		return 0;
471224aee3fSIngo Weinhold 	} else
472224aee3fSIngo Weinhold 		name = argv[1];
473224aee3fSIngo Weinhold 
474224aee3fSIngo Weinhold 	// walk through the ports list, trying to match name
47524df6592SIngo Weinhold 	for (PortHashTable::Iterator it = sPorts.GetIterator();
47624df6592SIngo Weinhold 		Port* port = it.Next();) {
47724df6592SIngo Weinhold 		if ((name != NULL && port->lock.name != NULL
47824df6592SIngo Weinhold 				&& !strcmp(name, port->lock.name))
47924df6592SIngo Weinhold 			|| (condition != NULL && (&port->read_condition == condition
48024df6592SIngo Weinhold 				|| &port->write_condition == condition))) {
48124df6592SIngo Weinhold 			_dump_port_info(port);
482224aee3fSIngo Weinhold 			return 0;
483224aee3fSIngo Weinhold 		}
484224aee3fSIngo Weinhold 	}
485224aee3fSIngo Weinhold 
486224aee3fSIngo Weinhold 	return 0;
487224aee3fSIngo Weinhold }
488224aee3fSIngo Weinhold 
489224aee3fSIngo Weinhold 
49024df6592SIngo Weinhold /*!	Notifies the port's select events.
49124df6592SIngo Weinhold 	The port must be locked.
49224df6592SIngo Weinhold */
493224aee3fSIngo Weinhold static void
49424df6592SIngo Weinhold notify_port_select_events(Port* port, uint16 events)
495224aee3fSIngo Weinhold {
49624df6592SIngo Weinhold 	if (port->select_infos)
49724df6592SIngo Weinhold 		notify_select_events_list(port->select_infos, events);
498224aee3fSIngo Weinhold }
499224aee3fSIngo Weinhold 
500224aee3fSIngo Weinhold 
501cd3e02caSMichael Lotz static Port*
502cd3e02caSMichael Lotz get_locked_port(port_id id)
503cd3e02caSMichael Lotz {
504cd3e02caSMichael Lotz 	MutexLocker portsLocker(sPortsLock);
505cd3e02caSMichael Lotz 
506cd3e02caSMichael Lotz 	Port* port = sPorts.Lookup(id);
507cd3e02caSMichael Lotz 	if (port != NULL)
508cd3e02caSMichael Lotz 		mutex_lock(&port->lock);
509cd3e02caSMichael Lotz 	return port;
510cd3e02caSMichael Lotz }
511cd3e02caSMichael Lotz 
512cd3e02caSMichael Lotz 
513cd3e02caSMichael Lotz /*!	You need to own the port's lock when calling this function */
514cd3e02caSMichael Lotz static inline bool
515cd3e02caSMichael Lotz is_port_closed(Port* port)
516cd3e02caSMichael Lotz {
517cd3e02caSMichael Lotz 	return port->capacity == 0;
518cd3e02caSMichael Lotz }
519cd3e02caSMichael Lotz 
520cd3e02caSMichael Lotz 
521224aee3fSIngo Weinhold static void
522e8885f20SAxel Dörfler put_port_message(port_message* message)
523224aee3fSIngo Weinhold {
524f28dd36bSAxel Dörfler 	size_t size = sizeof(port_message) + message->size;
525e8885f20SAxel Dörfler 	heap_free(sPortAllocator, message);
526f28dd36bSAxel Dörfler 
527cd3e02caSMichael Lotz 	MutexLocker quotaLocker(sPortQuotaLock);
528cd3e02caSMichael Lotz 	sTotalSpaceInUse -= size;
529cd3e02caSMichael Lotz 	if (sWaitingForSpace > 0)
530f28dd36bSAxel Dörfler 		sNoSpaceCondition.NotifyAll();
531224aee3fSIngo Weinhold }
532224aee3fSIngo Weinhold 
533224aee3fSIngo Weinhold 
534f28dd36bSAxel Dörfler static status_t
535f28dd36bSAxel Dörfler get_port_message(int32 code, size_t bufferSize, uint32 flags, bigtime_t timeout,
536cd3e02caSMichael Lotz 	port_message** _message, Port& port)
537224aee3fSIngo Weinhold {
538f28dd36bSAxel Dörfler 	size_t size = sizeof(port_message) + bufferSize;
539cd3e02caSMichael Lotz 	bool needToWait = false;
540cd3e02caSMichael Lotz 
541cd3e02caSMichael Lotz 	MutexLocker quotaLocker(sPortQuotaLock);
542f28dd36bSAxel Dörfler 
543f28dd36bSAxel Dörfler 	while (true) {
544cd3e02caSMichael Lotz 		while (sTotalSpaceInUse + size > kTotalSpaceLimit || needToWait) {
545f28dd36bSAxel Dörfler 			// TODO: add per team limit
546f28dd36bSAxel Dörfler 			// We are not allowed to create another heap area, as our
547f28dd36bSAxel Dörfler 			// space limit has been reached - just wait until we get
548f28dd36bSAxel Dörfler 			// some free space again.
549f28dd36bSAxel Dörfler 
550f28dd36bSAxel Dörfler 			// TODO: we don't want to wait - but does that also mean we
551f28dd36bSAxel Dörfler 			// shouldn't wait for the area creation?
552cd3e02caSMichael Lotz 			if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
553f28dd36bSAxel Dörfler 				return B_WOULD_BLOCK;
554f28dd36bSAxel Dörfler 
555f28dd36bSAxel Dörfler 			ConditionVariableEntry entry;
556f28dd36bSAxel Dörfler 			sNoSpaceCondition.Add(&entry);
557f28dd36bSAxel Dörfler 
558cd3e02caSMichael Lotz 			sWaitingForSpace++;
559cd3e02caSMichael Lotz 			quotaLocker.Unlock();
560cd3e02caSMichael Lotz 
561cd3e02caSMichael Lotz 			port_id portID = port.id;
562cd3e02caSMichael Lotz 			mutex_unlock(&port.lock);
563f28dd36bSAxel Dörfler 
564f28dd36bSAxel Dörfler 			status_t status = entry.Wait(flags, timeout);
565cd3e02caSMichael Lotz 
566cd3e02caSMichael Lotz 			// re-lock the port and the quota
567cd3e02caSMichael Lotz 			Port* newPort = get_locked_port(portID);
568cd3e02caSMichael Lotz 			quotaLocker.Lock();
569cd3e02caSMichael Lotz 			sWaitingForSpace--;
570cd3e02caSMichael Lotz 
571cd3e02caSMichael Lotz 			if (newPort != &port || is_port_closed(&port)) {
572cd3e02caSMichael Lotz 				// the port is no longer usable
573cd3e02caSMichael Lotz 				return B_BAD_PORT_ID;
574cd3e02caSMichael Lotz 			}
575cd3e02caSMichael Lotz 
576f28dd36bSAxel Dörfler 			if (status == B_TIMED_OUT)
577f28dd36bSAxel Dörfler 				return B_TIMED_OUT;
578f28dd36bSAxel Dörfler 
579cd3e02caSMichael Lotz 			needToWait = false;
580f28dd36bSAxel Dörfler 			continue;
581224aee3fSIngo Weinhold 		}
582224aee3fSIngo Weinhold 
583cd3e02caSMichael Lotz 		int32 areaChangeCounter = sAreaChangeCounter;
584cd3e02caSMichael Lotz 		sTotalSpaceInUse += size;
585cd3e02caSMichael Lotz 		quotaLocker.Unlock();
586f28dd36bSAxel Dörfler 
587f28dd36bSAxel Dörfler 		// Quota is fulfilled, try to allocate the buffer
588f28dd36bSAxel Dörfler 
589f28dd36bSAxel Dörfler 		port_message* message
590f28dd36bSAxel Dörfler 			= (port_message*)heap_memalign(sPortAllocator, 0, size);
591f28dd36bSAxel Dörfler 		if (message != NULL) {
592e8885f20SAxel Dörfler 			message->code = code;
593e8885f20SAxel Dörfler 			message->size = bufferSize;
594e8885f20SAxel Dörfler 
595f28dd36bSAxel Dörfler 			*_message = message;
596f28dd36bSAxel Dörfler 			return B_OK;
597f28dd36bSAxel Dörfler 		}
598f28dd36bSAxel Dörfler 
599cd3e02caSMichael Lotz 		quotaLocker.Lock();
600f28dd36bSAxel Dörfler 
601cd3e02caSMichael Lotz 		// We weren't able to allocate and we'll start over, including
602cd3e02caSMichael Lotz 		// re-acquireing the quota, so we remove our size from the in-use
603cd3e02caSMichael Lotz 		// counter again.
604cd3e02caSMichael Lotz 		sTotalSpaceInUse -= size;
605cd3e02caSMichael Lotz 
606cd3e02caSMichael Lotz 		if (areaChangeCounter != sAreaChangeCounter) {
607cd3e02caSMichael Lotz 			// There was already an area added since we tried allocating,
608cd3e02caSMichael Lotz 			// start over.
609f28dd36bSAxel Dörfler 			continue;
610f28dd36bSAxel Dörfler 		}
611f28dd36bSAxel Dörfler 
612f28dd36bSAxel Dörfler 		// Create a new area for the heap to use
613f28dd36bSAxel Dörfler 
614f28dd36bSAxel Dörfler 		addr_t base;
615f28dd36bSAxel Dörfler 		area_id area = create_area("port grown buffer", (void**)&base,
616f28dd36bSAxel Dörfler 			B_ANY_KERNEL_ADDRESS, kBufferGrowRate, B_NO_LOCK,
617f28dd36bSAxel Dörfler 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
618f28dd36bSAxel Dörfler 		if (area < 0) {
619cd3e02caSMichael Lotz 			// We'll have to get by with what we have, so wait for someone
620cd3e02caSMichael Lotz 			// to free a message instead. We enforce waiting so that we don't
621cd3e02caSMichael Lotz 			// try to create a new area over and over.
622cd3e02caSMichael Lotz 			needToWait = true;
623cd3e02caSMichael Lotz 			continue;
624f28dd36bSAxel Dörfler 		}
625f28dd36bSAxel Dörfler 
626f28dd36bSAxel Dörfler 		heap_add_area(sPortAllocator, area, base, kBufferGrowRate);
627f28dd36bSAxel Dörfler 
628cd3e02caSMichael Lotz 		sAreaChangeCounter++;
629cd3e02caSMichael Lotz 		if (sWaitingForSpace > 0)
630f28dd36bSAxel Dörfler 			sNoSpaceCondition.NotifyAll();
631f28dd36bSAxel Dörfler 	}
632224aee3fSIngo Weinhold }
633224aee3fSIngo Weinhold 
634224aee3fSIngo Weinhold 
635224aee3fSIngo Weinhold /*!	Fills the port_info structure with information from the specified
636224aee3fSIngo Weinhold 	port.
63724df6592SIngo Weinhold 	The port's lock must be held when called.
638224aee3fSIngo Weinhold */
639224aee3fSIngo Weinhold static void
64024df6592SIngo Weinhold fill_port_info(Port* port, port_info* info, size_t size)
641224aee3fSIngo Weinhold {
642224aee3fSIngo Weinhold 	info->port = port->id;
643224aee3fSIngo Weinhold 	info->team = port->owner;
644224aee3fSIngo Weinhold 	info->capacity = port->capacity;
645224aee3fSIngo Weinhold 
6467d592ec4SAxel Dörfler 	info->queue_count = port->read_count;
647224aee3fSIngo Weinhold 	info->total_count = port->total_count;
648224aee3fSIngo Weinhold 
649e8885f20SAxel Dörfler 	strlcpy(info->name, port->lock.name, B_OS_NAME_LENGTH);
650e8885f20SAxel Dörfler }
651e8885f20SAxel Dörfler 
652e8885f20SAxel Dörfler 
653e8885f20SAxel Dörfler static ssize_t
654e8885f20SAxel Dörfler copy_port_message(port_message* message, int32* _code, void* buffer,
655e8885f20SAxel Dörfler 	size_t bufferSize, bool userCopy)
656e8885f20SAxel Dörfler {
657e8885f20SAxel Dörfler 	// check output buffer size
658e8885f20SAxel Dörfler 	size_t size = min_c(bufferSize, message->size);
659e8885f20SAxel Dörfler 
660e8885f20SAxel Dörfler 	// copy message
661e8885f20SAxel Dörfler 	if (_code != NULL)
662e8885f20SAxel Dörfler 		*_code = message->code;
663e8885f20SAxel Dörfler 
664e8885f20SAxel Dörfler 	if (size > 0) {
665e8885f20SAxel Dörfler 		if (userCopy) {
666e8885f20SAxel Dörfler 			status_t status = user_memcpy(buffer, message->buffer, size);
667e8885f20SAxel Dörfler 			if (status != B_OK)
668e8885f20SAxel Dörfler 				return status;
669e8885f20SAxel Dörfler 		} else
670e8885f20SAxel Dörfler 			memcpy(buffer, message->buffer, size);
671e8885f20SAxel Dörfler 	}
672e8885f20SAxel Dörfler 
673e8885f20SAxel Dörfler 	return size;
674224aee3fSIngo Weinhold }
675224aee3fSIngo Weinhold 
676224aee3fSIngo Weinhold 
67786a999adSAxel Dörfler static void
67824df6592SIngo Weinhold uninit_port_locked(Port* port)
67986a999adSAxel Dörfler {
68024df6592SIngo Weinhold 	notify_port_select_events(port, B_EVENT_INVALID);
68124df6592SIngo Weinhold 	port->select_infos = NULL;
68286a999adSAxel Dörfler 
68386a999adSAxel Dörfler 	// Release the threads that were blocking on this port.
68486a999adSAxel Dörfler 	// read_port() will see the B_BAD_PORT_ID return value, and act accordingly
68524df6592SIngo Weinhold 	port->read_condition.NotifyAll(false, B_BAD_PORT_ID);
68624df6592SIngo Weinhold 	port->write_condition.NotifyAll(false, B_BAD_PORT_ID);
68724df6592SIngo Weinhold 	sNotificationService.Notify(PORT_REMOVED, port->id);
68824df6592SIngo Weinhold }
68924df6592SIngo Weinhold 
69024df6592SIngo Weinhold 
691224aee3fSIngo Weinhold //	#pragma mark - private kernel API
692224aee3fSIngo Weinhold 
693224aee3fSIngo Weinhold 
69424df6592SIngo Weinhold /*! This function deletes all the ports that are owned by the passed team.
695224aee3fSIngo Weinhold */
69686a999adSAxel Dörfler void
6974535495dSIngo Weinhold delete_owned_ports(Team* team)
698224aee3fSIngo Weinhold {
69986a999adSAxel Dörfler 	TRACE(("delete_owned_ports(owner = %ld)\n", team->id));
700224aee3fSIngo Weinhold 
70124df6592SIngo Weinhold 	MutexLocker portsLocker(sPortsLock);
70224df6592SIngo Weinhold 
70324df6592SIngo Weinhold 	// move the ports from the team's port list to a local list
70486a999adSAxel Dörfler 	struct list queue;
70586a999adSAxel Dörfler 	list_move_to_list(&team->port_list, &queue);
706224aee3fSIngo Weinhold 
70724df6592SIngo Weinhold 	// iterate through the list or ports, remove them from the hash table and
70824df6592SIngo Weinhold 	// uninitialize them
70924df6592SIngo Weinhold 	Port* port = (Port*)list_get_first_item(&queue);
71024df6592SIngo Weinhold 	while (port != NULL) {
71186a999adSAxel Dörfler 		MutexLocker locker(port->lock);
71224df6592SIngo Weinhold 		sPorts.Remove(port);
71324df6592SIngo Weinhold 		uninit_port_locked(port);
71424df6592SIngo Weinhold 		sUsedPorts--;
71524df6592SIngo Weinhold 
71624df6592SIngo Weinhold 		port = (Port*)list_get_next_item(&queue, port);
71786a999adSAxel Dörfler 	}
7188cd9a524SAxel Dörfler 
71924df6592SIngo Weinhold 	portsLocker.Unlock();
7208cd9a524SAxel Dörfler 
72124df6592SIngo Weinhold 	// delete the ports
72224df6592SIngo Weinhold 	while (Port* port = (Port*)list_remove_head_item(&queue))
72324df6592SIngo Weinhold 		delete port;
724224aee3fSIngo Weinhold }
725224aee3fSIngo Weinhold 
726224aee3fSIngo Weinhold 
727224aee3fSIngo Weinhold int32
728224aee3fSIngo Weinhold port_max_ports(void)
729224aee3fSIngo Weinhold {
730224aee3fSIngo Weinhold 	return sMaxPorts;
731224aee3fSIngo Weinhold }
732224aee3fSIngo Weinhold 
733224aee3fSIngo Weinhold 
734224aee3fSIngo Weinhold int32
735224aee3fSIngo Weinhold port_used_ports(void)
736224aee3fSIngo Weinhold {
737224aee3fSIngo Weinhold 	return sUsedPorts;
738224aee3fSIngo Weinhold }
739224aee3fSIngo Weinhold 
740224aee3fSIngo Weinhold 
741224aee3fSIngo Weinhold status_t
742224aee3fSIngo Weinhold port_init(kernel_args *args)
743224aee3fSIngo Weinhold {
74424df6592SIngo Weinhold 	// initialize ports table
74524df6592SIngo Weinhold 	new(&sPorts) PortHashTable;
74624df6592SIngo Weinhold 	if (sPorts.Init() != B_OK) {
74724df6592SIngo Weinhold 		panic("Failed to init port hash table!");
74824df6592SIngo Weinhold 		return B_NO_MEMORY;
749e8885f20SAxel Dörfler 	}
750e8885f20SAxel Dörfler 
751e8885f20SAxel Dörfler 	addr_t base;
752e8885f20SAxel Dörfler 	if (create_area("port heap", (void**)&base, B_ANY_KERNEL_ADDRESS,
753e8885f20SAxel Dörfler 			kInitialPortBufferSize, B_NO_LOCK,
754e8885f20SAxel Dörfler 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA) < 0) {
755bf96cfdcSIngo Weinhold 			// TODO: Since port_init() is invoked before the boot partition is
756bf96cfdcSIngo Weinhold 			// mounted, the underlying VMAnonymousCache cannot commit swap space
757bf96cfdcSIngo Weinhold 			// upon creation and thus the pages aren't swappable after all. This
758bf96cfdcSIngo Weinhold 			// makes the area essentially B_LAZY_LOCK with additional overhead.
759e8885f20SAxel Dörfler 		panic("unable to allocate port area!\n");
760e8885f20SAxel Dörfler 		return B_ERROR;
761e8885f20SAxel Dörfler 	}
762e8885f20SAxel Dörfler 
763961a96a9SMichael Lotz 	static const heap_class kBufferHeapClass = { "port heap", 100,
764e8885f20SAxel Dörfler 		PORT_MAX_MESSAGE_SIZE + sizeof(port_message), 2 * 1024,
765961a96a9SMichael Lotz 		sizeof(port_message), 4, 2, 24 };
766e8885f20SAxel Dörfler 	sPortAllocator = heap_create_allocator("port buffer", base,
767e8885f20SAxel Dörfler 		kInitialPortBufferSize, &kBufferHeapClass, true);
768f28dd36bSAxel Dörfler 	if (sPortAllocator == NULL) {
769f28dd36bSAxel Dörfler 		panic("unable to create port heap");
770f28dd36bSAxel Dörfler 		return B_NO_MEMORY;
771f28dd36bSAxel Dörfler 	}
772f28dd36bSAxel Dörfler 
77324df6592SIngo Weinhold 	sNoSpaceCondition.Init(&sPorts, "port space");
774224aee3fSIngo Weinhold 
775224aee3fSIngo Weinhold 	// add debugger commands
776ce637fdaSIngo Weinhold 	add_debugger_command_etc("ports", &dump_port_list,
777ce637fdaSIngo Weinhold 		"Dump a list of all active ports (for team, with name, etc.)",
778ce637fdaSIngo Weinhold 		"[ ([ \"team\" | \"owner\" ] <team>) | (\"name\" <name>) ]\n"
779ce637fdaSIngo Weinhold 		"Prints a list of all active ports meeting the given\n"
780ce637fdaSIngo Weinhold 		"requirement. If no argument is given, all ports are listed.\n"
781ce637fdaSIngo Weinhold 		"  <team>             - The team owning the ports.\n"
782ce637fdaSIngo Weinhold 		"  <name>             - Part of the name of the ports.\n", 0);
783ce637fdaSIngo Weinhold 	add_debugger_command_etc("port", &dump_port_info,
784ce637fdaSIngo Weinhold 		"Dump info about a particular port",
785f28dd36bSAxel Dörfler 		"(<id> | [ \"address\" ] <address>) | ([ \"name\" ] <name>) "
786f28dd36bSAxel Dörfler 			"| (\"condition\" <address>)\n"
787ce637fdaSIngo Weinhold 		"Prints info about the specified port.\n"
788ce637fdaSIngo Weinhold 		"  <address>   - Pointer to the port structure.\n"
789ce637fdaSIngo Weinhold 		"  <name>      - Name of the port.\n"
790f28dd36bSAxel Dörfler 		"  <condition> - address of the port's read or write condition.\n", 0);
791224aee3fSIngo Weinhold 
79251755cf8SAxel Dörfler 	new(&sNotificationService) PortNotificationService();
793224aee3fSIngo Weinhold 	sPortsActive = true;
794224aee3fSIngo Weinhold 	return B_OK;
795224aee3fSIngo Weinhold }
796224aee3fSIngo Weinhold 
797224aee3fSIngo Weinhold 
798224aee3fSIngo Weinhold //	#pragma mark - public kernel API
799224aee3fSIngo Weinhold 
800224aee3fSIngo Weinhold 
801224aee3fSIngo Weinhold port_id
802224aee3fSIngo Weinhold create_port(int32 queueLength, const char* name)
803224aee3fSIngo Weinhold {
80451755cf8SAxel Dörfler 	TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength,
80551755cf8SAxel Dörfler 		name));
806224aee3fSIngo Weinhold 
807e8885f20SAxel Dörfler 	if (!sPortsActive) {
808e8885f20SAxel Dörfler 		panic("ports used too early!\n");
809224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
810e8885f20SAxel Dörfler 	}
811e8885f20SAxel Dörfler 	if (queueLength < 1 || queueLength > MAX_QUEUE_LENGTH)
812224aee3fSIngo Weinhold 		return B_BAD_VALUE;
813224aee3fSIngo Weinhold 
8144535495dSIngo Weinhold 	Team* team = thread_get_current_thread()->team;
81586a999adSAxel Dörfler 	if (team == NULL)
81686a999adSAxel Dörfler 		return B_BAD_TEAM_ID;
81786a999adSAxel Dörfler 
818224aee3fSIngo Weinhold 	// check & dup name
819e8885f20SAxel Dörfler 	char* nameBuffer = strdup(name != NULL ? name : "unnamed port");
820e8885f20SAxel Dörfler 	if (nameBuffer == NULL)
821e8885f20SAxel Dörfler 		return B_NO_MEMORY;
822224aee3fSIngo Weinhold 
82324df6592SIngo Weinhold 	// create a port
82424df6592SIngo Weinhold 	Port* port = new(std::nothrow) Port(team_get_current_team_id(), queueLength,
82524df6592SIngo Weinhold 		nameBuffer);
82624df6592SIngo Weinhold 	if (port == NULL) {
82724df6592SIngo Weinhold 		free(nameBuffer);
82824df6592SIngo Weinhold 		return B_NO_MEMORY;
82924df6592SIngo Weinhold 	}
83024df6592SIngo Weinhold 	ObjectDeleter<Port> portDeleter(port);
83124df6592SIngo Weinhold 
83224df6592SIngo Weinhold 	MutexLocker locker(sPortsLock);
83324df6592SIngo Weinhold 
83424df6592SIngo Weinhold 	// check the ports limit
83524df6592SIngo Weinhold 	if (sUsedPorts >= sMaxPorts)
83624df6592SIngo Weinhold 		return B_NO_MORE_PORTS;
83724df6592SIngo Weinhold 
838e8885f20SAxel Dörfler 	sUsedPorts++;
839224aee3fSIngo Weinhold 
84024df6592SIngo Weinhold 	// allocate a port ID
84124df6592SIngo Weinhold 	do {
84224df6592SIngo Weinhold 		port->id = sNextPortID++;
843224aee3fSIngo Weinhold 
84424df6592SIngo Weinhold 		// handle integer overflow
84524df6592SIngo Weinhold 		if (sNextPortID < 0)
84624df6592SIngo Weinhold 			sNextPortID = 1;
84724df6592SIngo Weinhold 	} while (sPorts.Lookup(port->id) != NULL);
848224aee3fSIngo Weinhold 
84924df6592SIngo Weinhold 	// insert port in table and team list
85024df6592SIngo Weinhold 	sPorts.Insert(port);
85124df6592SIngo Weinhold 	list_add_item(&team->port_list, &port->team_link);
85224df6592SIngo Weinhold 	portDeleter.Detach();
85324df6592SIngo Weinhold 
85424df6592SIngo Weinhold 	// tracing, notifications, etc.
85524df6592SIngo Weinhold 	T(Create(port));
85624df6592SIngo Weinhold 
85724df6592SIngo Weinhold 	port_id id = port->id;
85824df6592SIngo Weinhold 
859e8885f20SAxel Dörfler 	locker.Unlock();
860224aee3fSIngo Weinhold 
861224aee3fSIngo Weinhold 	TRACE(("create_port() done: port created %ld\n", id));
862224aee3fSIngo Weinhold 
86351755cf8SAxel Dörfler 	sNotificationService.Notify(PORT_ADDED, id);
864224aee3fSIngo Weinhold 	return id;
865224aee3fSIngo Weinhold }
866224aee3fSIngo Weinhold 
867224aee3fSIngo Weinhold 
868224aee3fSIngo Weinhold status_t
869224aee3fSIngo Weinhold close_port(port_id id)
870224aee3fSIngo Weinhold {
871224aee3fSIngo Weinhold 	TRACE(("close_port(id = %ld)\n", id));
872224aee3fSIngo Weinhold 
873224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
874224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
875224aee3fSIngo Weinhold 
87624df6592SIngo Weinhold 	// get the port
87724df6592SIngo Weinhold 	Port* port = get_locked_port(id);
87824df6592SIngo Weinhold 	if (port == NULL) {
879224aee3fSIngo Weinhold 		TRACE(("close_port: invalid port_id %ld\n", id));
880224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
881224aee3fSIngo Weinhold 	}
88224df6592SIngo Weinhold 	MutexLocker lock(&port->lock, true);
883224aee3fSIngo Weinhold 
884224aee3fSIngo Weinhold 	// mark port to disable writing - deleting the semaphores will
885224aee3fSIngo Weinhold 	// wake up waiting read/writes
88624df6592SIngo Weinhold 	port->capacity = 0;
887224aee3fSIngo Weinhold 
88824df6592SIngo Weinhold 	notify_port_select_events(port, B_EVENT_INVALID);
88924df6592SIngo Weinhold 	port->select_infos = NULL;
890224aee3fSIngo Weinhold 
89124df6592SIngo Weinhold 	port->read_condition.NotifyAll(false, B_BAD_PORT_ID);
89224df6592SIngo Weinhold 	port->write_condition.NotifyAll(false, B_BAD_PORT_ID);
893224aee3fSIngo Weinhold 
894e8885f20SAxel Dörfler 	return B_OK;
895224aee3fSIngo Weinhold }
896224aee3fSIngo Weinhold 
897224aee3fSIngo Weinhold 
898224aee3fSIngo Weinhold status_t
899224aee3fSIngo Weinhold delete_port(port_id id)
900224aee3fSIngo Weinhold {
901224aee3fSIngo Weinhold 	TRACE(("delete_port(id = %ld)\n", id));
902224aee3fSIngo Weinhold 
903224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
904224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
905224aee3fSIngo Weinhold 
90624df6592SIngo Weinhold 	// get the port and remove it from the hash table and the team
90724df6592SIngo Weinhold 	Port* port;
90824df6592SIngo Weinhold 	MutexLocker locker;
90924df6592SIngo Weinhold 	{
91024df6592SIngo Weinhold 		MutexLocker portsLocker(sPortsLock);
911224aee3fSIngo Weinhold 
91224df6592SIngo Weinhold 		port = sPorts.Lookup(id);
91324df6592SIngo Weinhold 		if (port == NULL) {
914224aee3fSIngo Weinhold 			TRACE(("delete_port: invalid port_id %ld\n", id));
915224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
916224aee3fSIngo Weinhold 		}
917224aee3fSIngo Weinhold 
91824df6592SIngo Weinhold 		sPorts.Remove(port);
91924df6592SIngo Weinhold 		list_remove_link(&port->team_link);
920f28dd36bSAxel Dörfler 
92124df6592SIngo Weinhold 		sUsedPorts--;
92224df6592SIngo Weinhold 
92324df6592SIngo Weinhold 		locker.SetTo(port->lock, false);
92424df6592SIngo Weinhold 
92524df6592SIngo Weinhold 		uninit_port_locked(port);
926e8885f20SAxel Dörfler 	}
927224aee3fSIngo Weinhold 
92824df6592SIngo Weinhold 	T(Delete(port));
929224aee3fSIngo Weinhold 
930e8885f20SAxel Dörfler 	locker.Unlock();
931e8885f20SAxel Dörfler 
93224df6592SIngo Weinhold 	delete port;
933e8885f20SAxel Dörfler 
934224aee3fSIngo Weinhold 	return B_OK;
935224aee3fSIngo Weinhold }
936224aee3fSIngo Weinhold 
937224aee3fSIngo Weinhold 
938224aee3fSIngo Weinhold status_t
939224aee3fSIngo Weinhold select_port(int32 id, struct select_info* info, bool kernel)
940224aee3fSIngo Weinhold {
941224aee3fSIngo Weinhold 	if (id < 0)
942224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
943224aee3fSIngo Weinhold 
94424df6592SIngo Weinhold 	// get the port
94524df6592SIngo Weinhold 	Port* port = get_locked_port(id);
94624df6592SIngo Weinhold 	if (port == NULL)
947e8885f20SAxel Dörfler 		return B_BAD_PORT_ID;
94824df6592SIngo Weinhold 	MutexLocker locker(port->lock, true);
94924df6592SIngo Weinhold 
95024df6592SIngo Weinhold 	// port must not yet be closed
95124df6592SIngo Weinhold 	if (is_port_closed(port))
95224df6592SIngo Weinhold 		return B_BAD_PORT_ID;
95324df6592SIngo Weinhold 
95424df6592SIngo Weinhold 	if (!kernel && port->owner == team_get_kernel_team_id()) {
955224aee3fSIngo Weinhold 		// kernel port, but call from userland
956e8885f20SAxel Dörfler 		return B_NOT_ALLOWED;
957e8885f20SAxel Dörfler 	}
958e8885f20SAxel Dörfler 
959224aee3fSIngo Weinhold 	info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID;
960224aee3fSIngo Weinhold 
961224aee3fSIngo Weinhold 	if (info->selected_events != 0) {
962224aee3fSIngo Weinhold 		uint16 events = 0;
963224aee3fSIngo Weinhold 
96424df6592SIngo Weinhold 		info->next = port->select_infos;
96524df6592SIngo Weinhold 		port->select_infos = info;
966224aee3fSIngo Weinhold 
967224aee3fSIngo Weinhold 		// check for events
968224aee3fSIngo Weinhold 		if ((info->selected_events & B_EVENT_READ) != 0
96924df6592SIngo Weinhold 			&& !port->messages.IsEmpty()) {
970224aee3fSIngo Weinhold 			events |= B_EVENT_READ;
971224aee3fSIngo Weinhold 		}
972224aee3fSIngo Weinhold 
97324df6592SIngo Weinhold 		if (port->write_count > 0)
974224aee3fSIngo Weinhold 			events |= B_EVENT_WRITE;
975224aee3fSIngo Weinhold 
976224aee3fSIngo Weinhold 		if (events != 0)
977224aee3fSIngo Weinhold 			notify_select_events(info, events);
978224aee3fSIngo Weinhold 	}
979224aee3fSIngo Weinhold 
980e8885f20SAxel Dörfler 	return B_OK;
981224aee3fSIngo Weinhold }
982224aee3fSIngo Weinhold 
983224aee3fSIngo Weinhold 
984224aee3fSIngo Weinhold status_t
985224aee3fSIngo Weinhold deselect_port(int32 id, struct select_info* info, bool kernel)
986224aee3fSIngo Weinhold {
987224aee3fSIngo Weinhold 	if (id < 0)
988224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
989224aee3fSIngo Weinhold 	if (info->selected_events == 0)
990224aee3fSIngo Weinhold 		return B_OK;
991224aee3fSIngo Weinhold 
99224df6592SIngo Weinhold 	// get the port
99324df6592SIngo Weinhold 	Port* port = get_locked_port(id);
99424df6592SIngo Weinhold 	if (port == NULL)
99524df6592SIngo Weinhold 		return B_BAD_PORT_ID;
99624df6592SIngo Weinhold 	MutexLocker locker(port->lock, true);
997224aee3fSIngo Weinhold 
99824df6592SIngo Weinhold 	// find and remove the infos
99924df6592SIngo Weinhold 	select_info** infoLocation = &port->select_infos;
1000224aee3fSIngo Weinhold 	while (*infoLocation != NULL && *infoLocation != info)
1001224aee3fSIngo Weinhold 		infoLocation = &(*infoLocation)->next;
1002224aee3fSIngo Weinhold 
1003224aee3fSIngo Weinhold 	if (*infoLocation == info)
1004224aee3fSIngo Weinhold 		*infoLocation = info->next;
1005224aee3fSIngo Weinhold 
1006224aee3fSIngo Weinhold 	return B_OK;
1007224aee3fSIngo Weinhold }
1008224aee3fSIngo Weinhold 
1009224aee3fSIngo Weinhold 
1010224aee3fSIngo Weinhold port_id
1011224aee3fSIngo Weinhold find_port(const char* name)
1012224aee3fSIngo Weinhold {
1013224aee3fSIngo Weinhold 	TRACE(("find_port(name = \"%s\")\n", name));
1014224aee3fSIngo Weinhold 
1015e8885f20SAxel Dörfler 	if (!sPortsActive) {
1016e8885f20SAxel Dörfler 		panic("ports used too early!\n");
1017224aee3fSIngo Weinhold 		return B_NAME_NOT_FOUND;
1018e8885f20SAxel Dörfler 	}
1019224aee3fSIngo Weinhold 	if (name == NULL)
1020224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1021224aee3fSIngo Weinhold 
102224df6592SIngo Weinhold 	MutexLocker portsLocker(sPortsLock);
1023224aee3fSIngo Weinhold 
102424df6592SIngo Weinhold 	for (PortHashTable::Iterator it = sPorts.GetIterator();
102524df6592SIngo Weinhold 		Port* port = it.Next();) {
102624df6592SIngo Weinhold 		if (!strcmp(name, port->lock.name))
102724df6592SIngo Weinhold 			return port->id;
1028224aee3fSIngo Weinhold 	}
1029224aee3fSIngo Weinhold 
1030e8885f20SAxel Dörfler 	return B_NAME_NOT_FOUND;
1031224aee3fSIngo Weinhold }
1032224aee3fSIngo Weinhold 
1033224aee3fSIngo Weinhold 
1034224aee3fSIngo Weinhold status_t
1035224aee3fSIngo Weinhold _get_port_info(port_id id, port_info* info, size_t size)
1036224aee3fSIngo Weinhold {
1037224aee3fSIngo Weinhold 	TRACE(("get_port_info(id = %ld)\n", id));
1038224aee3fSIngo Weinhold 
1039224aee3fSIngo Weinhold 	if (info == NULL || size != sizeof(port_info))
1040224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1041224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1042224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1043224aee3fSIngo Weinhold 
104424df6592SIngo Weinhold 	// get the port
104524df6592SIngo Weinhold 	Port* port = get_locked_port(id);
104624df6592SIngo Weinhold 	if (port == NULL) {
1047224aee3fSIngo Weinhold 		TRACE(("get_port_info: invalid port_id %ld\n", id));
1048224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1049224aee3fSIngo Weinhold 	}
105024df6592SIngo Weinhold 	MutexLocker locker(port->lock, true);
1051224aee3fSIngo Weinhold 
1052224aee3fSIngo Weinhold 	// fill a port_info struct with info
105324df6592SIngo Weinhold 	fill_port_info(port, info, size);
1054224aee3fSIngo Weinhold 	return B_OK;
1055224aee3fSIngo Weinhold }
1056224aee3fSIngo Weinhold 
1057224aee3fSIngo Weinhold 
1058224aee3fSIngo Weinhold status_t
105924df6592SIngo Weinhold _get_next_port_info(team_id teamID, int32* _cookie, struct port_info* info,
1060e8885f20SAxel Dörfler 	size_t size)
1061224aee3fSIngo Weinhold {
106224df6592SIngo Weinhold 	TRACE(("get_next_port_info(team = %ld)\n", teamID));
1063224aee3fSIngo Weinhold 
1064e8885f20SAxel Dörfler 	if (info == NULL || size != sizeof(port_info) || _cookie == NULL
106524df6592SIngo Weinhold 		|| teamID < 0) {
1066224aee3fSIngo Weinhold 		return B_BAD_VALUE;
106724df6592SIngo Weinhold 	}
1068224aee3fSIngo Weinhold 	if (!sPortsActive)
1069224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1070224aee3fSIngo Weinhold 
107124df6592SIngo Weinhold 	Team* team = Team::Get(teamID);
107224df6592SIngo Weinhold 	if (team == NULL)
107324df6592SIngo Weinhold 		return B_BAD_TEAM_ID;
107424df6592SIngo Weinhold 	BReference<Team> teamReference(team, true);
1075224aee3fSIngo Weinhold 
107624df6592SIngo Weinhold 	// iterate through the team's port list
107724df6592SIngo Weinhold 	MutexLocker portsLocker(sPortsLock);
1078224aee3fSIngo Weinhold 
107924df6592SIngo Weinhold 	int32 stopIndex = *_cookie;
108024df6592SIngo Weinhold 	int32 index = 0;
1081224aee3fSIngo Weinhold 
108224df6592SIngo Weinhold 	Port* port = (Port*)list_get_first_item(&team->port_list);
108324df6592SIngo Weinhold 	while (port != NULL) {
108424df6592SIngo Weinhold 		if (!is_port_closed(port)) {
108524df6592SIngo Weinhold 			if (index == stopIndex)
1086224aee3fSIngo Weinhold 				break;
108724df6592SIngo Weinhold 			index++;
1088224aee3fSIngo Weinhold 		}
1089e8885f20SAxel Dörfler 
109024df6592SIngo Weinhold 		port = (Port*)list_get_next_item(&team->port_list, port);
1091224aee3fSIngo Weinhold 	}
1092224aee3fSIngo Weinhold 
109324df6592SIngo Weinhold 	if (port == NULL)
1094224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1095224aee3fSIngo Weinhold 
109624df6592SIngo Weinhold 	// fill in the port info
109724df6592SIngo Weinhold 	MutexLocker locker(port->lock);
109824df6592SIngo Weinhold 	portsLocker.Unlock();
109924df6592SIngo Weinhold 	fill_port_info(port, info, size);
110024df6592SIngo Weinhold 
110124df6592SIngo Weinhold 	*_cookie = stopIndex + 1;
1102e8885f20SAxel Dörfler 	return B_OK;
1103224aee3fSIngo Weinhold }
1104224aee3fSIngo Weinhold 
1105224aee3fSIngo Weinhold 
1106224aee3fSIngo Weinhold ssize_t
1107224aee3fSIngo Weinhold port_buffer_size(port_id id)
1108224aee3fSIngo Weinhold {
1109224aee3fSIngo Weinhold 	return port_buffer_size_etc(id, 0, 0);
1110224aee3fSIngo Weinhold }
1111224aee3fSIngo Weinhold 
1112224aee3fSIngo Weinhold 
1113224aee3fSIngo Weinhold ssize_t
1114224aee3fSIngo Weinhold port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
1115224aee3fSIngo Weinhold {
11167727e08eSIngo Weinhold 	port_message_info info;
11177727e08eSIngo Weinhold 	status_t error = get_port_message_info_etc(id, &info, flags, timeout);
11187727e08eSIngo Weinhold 	return error != B_OK ? error : info.size;
11197727e08eSIngo Weinhold }
11207727e08eSIngo Weinhold 
1121e8885f20SAxel Dörfler 
11227727e08eSIngo Weinhold status_t
11237727e08eSIngo Weinhold _get_port_message_info_etc(port_id id, port_message_info* info,
11247727e08eSIngo Weinhold 	size_t infoSize, uint32 flags, bigtime_t timeout)
11257727e08eSIngo Weinhold {
11267727e08eSIngo Weinhold 	if (info == NULL || infoSize != sizeof(port_message_info))
11277727e08eSIngo Weinhold 		return B_BAD_VALUE;
1128224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1129224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1130224aee3fSIngo Weinhold 
1131f28dd36bSAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1132f28dd36bSAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1133224aee3fSIngo Weinhold 
113424df6592SIngo Weinhold 	// get the port
113524df6592SIngo Weinhold 	Port* port = get_locked_port(id);
113624df6592SIngo Weinhold 	if (port == NULL)
113724df6592SIngo Weinhold 		return B_BAD_PORT_ID;
113824df6592SIngo Weinhold 	MutexLocker locker(port->lock, true);
1139224aee3fSIngo Weinhold 
114024df6592SIngo Weinhold 	if (is_port_closed(port) && port->messages.IsEmpty()) {
114124df6592SIngo Weinhold 		T(Info(port, 0, B_BAD_PORT_ID));
114224df6592SIngo Weinhold 		TRACE(("_get_port_message_info_etc(): closed port %ld\n", id));
1143224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1144224aee3fSIngo Weinhold 	}
1145224aee3fSIngo Weinhold 
114624df6592SIngo Weinhold 	while (port->read_count == 0) {
1147e8885f20SAxel Dörfler 		// We need to wait for a message to appear
1148f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1149f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1150f28dd36bSAxel Dörfler 
1151e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
115224df6592SIngo Weinhold 		port->read_condition.Add(&entry);
1153224aee3fSIngo Weinhold 
1154e8885f20SAxel Dörfler 		locker.Unlock();
1155224aee3fSIngo Weinhold 
1156224aee3fSIngo Weinhold 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1157e8885f20SAxel Dörfler 		status_t status = entry.Wait(flags, timeout);
1158f28dd36bSAxel Dörfler 
1159f28dd36bSAxel Dörfler 		if (status != B_OK) {
116024df6592SIngo Weinhold 			T(Info(port, 0, status));
1161224aee3fSIngo Weinhold 			return status;
1162f28dd36bSAxel Dörfler 		}
1163224aee3fSIngo Weinhold 
116424df6592SIngo Weinhold 		// re-lock
116524df6592SIngo Weinhold 		Port* newPort = get_locked_port(id);
116624df6592SIngo Weinhold 		if (newPort == NULL) {
116724df6592SIngo Weinhold 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
116824df6592SIngo Weinhold 			return B_BAD_PORT_ID;
116924df6592SIngo Weinhold 		}
117024df6592SIngo Weinhold 		locker.SetTo(newPort->lock, true);
1171224aee3fSIngo Weinhold 
117224df6592SIngo Weinhold 		if (newPort != port
117324df6592SIngo Weinhold 			|| (is_port_closed(port) && port->messages.IsEmpty())) {
1174224aee3fSIngo Weinhold 			// the port is no longer there
117524df6592SIngo Weinhold 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
1176224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1177224aee3fSIngo Weinhold 		}
1178a73382f7SIngo Weinhold 	}
1179224aee3fSIngo Weinhold 
1180224aee3fSIngo Weinhold 	// determine tail & get the length of the message
118124df6592SIngo Weinhold 	port_message* message = port->messages.Head();
1182e8885f20SAxel Dörfler 	if (message == NULL) {
118324df6592SIngo Weinhold 		panic("port %ld: no messages found\n", port->id);
1184e8885f20SAxel Dörfler 		return B_ERROR;
11857727e08eSIngo Weinhold 	}
1186224aee3fSIngo Weinhold 
1187e8885f20SAxel Dörfler 	info->size = message->size;
1188e8885f20SAxel Dörfler 	info->sender = message->sender;
1189e8885f20SAxel Dörfler 	info->sender_group = message->sender_group;
1190e8885f20SAxel Dörfler 	info->sender_team = message->sender_team;
1191224aee3fSIngo Weinhold 
119224df6592SIngo Weinhold 	T(Info(id, id->read_count, id->write_count, message->code, B_OK));
1193f28dd36bSAxel Dörfler 
1194e8885f20SAxel Dörfler 	// notify next one, as we haven't read from the port
119524df6592SIngo Weinhold 	port->read_condition.NotifyOne();
1196224aee3fSIngo Weinhold 
1197e8885f20SAxel Dörfler 	return B_OK;
1198224aee3fSIngo Weinhold }
1199224aee3fSIngo Weinhold 
1200224aee3fSIngo Weinhold 
1201224aee3fSIngo Weinhold ssize_t
1202224aee3fSIngo Weinhold port_count(port_id id)
1203224aee3fSIngo Weinhold {
1204224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1205224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1206224aee3fSIngo Weinhold 
120724df6592SIngo Weinhold 	// get the port
120824df6592SIngo Weinhold 	Port* port = get_locked_port(id);
120924df6592SIngo Weinhold 	if (port == NULL) {
1210224aee3fSIngo Weinhold 		TRACE(("port_count: invalid port_id %ld\n", id));
1211224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1212224aee3fSIngo Weinhold 	}
121324df6592SIngo Weinhold 	MutexLocker locker(port->lock, true);
1214224aee3fSIngo Weinhold 
1215224aee3fSIngo Weinhold 	// return count of messages
121624df6592SIngo Weinhold 	return port->read_count;
1217224aee3fSIngo Weinhold }
1218224aee3fSIngo Weinhold 
1219224aee3fSIngo Weinhold 
1220224aee3fSIngo Weinhold ssize_t
1221e8885f20SAxel Dörfler read_port(port_id port, int32* msgCode, void* buffer, size_t bufferSize)
1222224aee3fSIngo Weinhold {
1223e8885f20SAxel Dörfler 	return read_port_etc(port, msgCode, buffer, bufferSize, 0, 0);
1224224aee3fSIngo Weinhold }
1225224aee3fSIngo Weinhold 
1226224aee3fSIngo Weinhold 
1227224aee3fSIngo Weinhold ssize_t
1228e8885f20SAxel Dörfler read_port_etc(port_id id, int32* _code, void* buffer, size_t bufferSize,
1229224aee3fSIngo Weinhold 	uint32 flags, bigtime_t timeout)
1230224aee3fSIngo Weinhold {
1231224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1232224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1233e8885f20SAxel Dörfler 	if ((buffer == NULL && bufferSize > 0) || timeout < 0)
1234224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1235224aee3fSIngo Weinhold 
1236e8885f20SAxel Dörfler 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0;
1237e8885f20SAxel Dörfler 	bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0;
1238e8885f20SAxel Dörfler 		// TODO: we could allow peeking for user apps now
1239224aee3fSIngo Weinhold 
1240e8885f20SAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1241e8885f20SAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1242e8885f20SAxel Dörfler 
124324df6592SIngo Weinhold 	// get the port
124424df6592SIngo Weinhold 	Port* port = get_locked_port(id);
124524df6592SIngo Weinhold 	if (port == NULL)
124624df6592SIngo Weinhold 		return B_BAD_PORT_ID;
124724df6592SIngo Weinhold 	MutexLocker locker(port->lock, true);
1248e8885f20SAxel Dörfler 
124924df6592SIngo Weinhold 	if (is_port_closed(port) && port->messages.IsEmpty()) {
125024df6592SIngo Weinhold 		T(Read(port, 0, B_BAD_PORT_ID));
125124df6592SIngo Weinhold 		TRACE(("read_port_etc(): closed port %ld\n", id));
1252224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1253224aee3fSIngo Weinhold 	}
1254224aee3fSIngo Weinhold 
125524df6592SIngo Weinhold 	while (port->read_count == 0) {
1256f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1257f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1258f28dd36bSAxel Dörfler 
1259e8885f20SAxel Dörfler 		// We need to wait for a message to appear
1260e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
126124df6592SIngo Weinhold 		port->read_condition.Add(&entry);
1262224aee3fSIngo Weinhold 
1263e8885f20SAxel Dörfler 		locker.Unlock();
1264224aee3fSIngo Weinhold 
1265e8885f20SAxel Dörfler 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1266e8885f20SAxel Dörfler 		status_t status = entry.Wait(flags, timeout);
1267224aee3fSIngo Weinhold 
126824df6592SIngo Weinhold 		// re-lock
126924df6592SIngo Weinhold 		Port* newPort = get_locked_port(id);
127024df6592SIngo Weinhold 		if (newPort == NULL) {
127124df6592SIngo Weinhold 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
127224df6592SIngo Weinhold 			return B_BAD_PORT_ID;
127324df6592SIngo Weinhold 		}
127424df6592SIngo Weinhold 		locker.SetTo(newPort->lock, true);
1275224aee3fSIngo Weinhold 
127624df6592SIngo Weinhold 		if (newPort != port
127724df6592SIngo Weinhold 			|| (is_port_closed(port) && port->messages.IsEmpty())) {
1278e8885f20SAxel Dörfler 			// the port is no longer there
127924df6592SIngo Weinhold 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
1280224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1281224aee3fSIngo Weinhold 		}
1282224aee3fSIngo Weinhold 
1283c3bc71d6SIngo Weinhold 		if (status != B_OK) {
128424df6592SIngo Weinhold 			T(Read(port, 0, status));
1285c3bc71d6SIngo Weinhold 			return status;
1286e8885f20SAxel Dörfler 		}
12877d592ec4SAxel Dörfler 	}
1288224aee3fSIngo Weinhold 
1289e8885f20SAxel Dörfler 	// determine tail & get the length of the message
129024df6592SIngo Weinhold 	port_message* message = port->messages.Head();
1291e8885f20SAxel Dörfler 	if (message == NULL) {
129224df6592SIngo Weinhold 		panic("port %ld: no messages found\n", port->id);
1293e8885f20SAxel Dörfler 		return B_ERROR;
1294224aee3fSIngo Weinhold 	}
1295224aee3fSIngo Weinhold 
1296b4ec7b8eSIngo Weinhold 	if (peekOnly) {
1297e8885f20SAxel Dörfler 		size_t size = copy_port_message(message, _code, buffer, bufferSize,
1298e8885f20SAxel Dörfler 			userCopy);
1299e8885f20SAxel Dörfler 
130024df6592SIngo Weinhold 		T(Read(port, message->code, size));
1301f28dd36bSAxel Dörfler 
130224df6592SIngo Weinhold 		port->read_condition.NotifyOne();
1303b4ec7b8eSIngo Weinhold 			// we only peeked, but didn't grab the message
1304b4ec7b8eSIngo Weinhold 		return size;
1305b4ec7b8eSIngo Weinhold 	}
1306b4ec7b8eSIngo Weinhold 
130724df6592SIngo Weinhold 	port->messages.RemoveHead();
130824df6592SIngo Weinhold 	port->total_count++;
130924df6592SIngo Weinhold 	port->write_count++;
131024df6592SIngo Weinhold 	port->read_count--;
1311224aee3fSIngo Weinhold 
131224df6592SIngo Weinhold 	notify_port_select_events(port, B_EVENT_WRITE);
131324df6592SIngo Weinhold 	port->write_condition.NotifyOne();
1314224aee3fSIngo Weinhold 		// make one spot in queue available again for write
1315224aee3fSIngo Weinhold 
131624df6592SIngo Weinhold 	T(Read(id, port->read_count, port->write_count, message->code,
131724df6592SIngo Weinhold 		min_c(bufferSize, message->size)));
131824df6592SIngo Weinhold 
1319e8885f20SAxel Dörfler 	locker.Unlock();
1320e8885f20SAxel Dörfler 
1321e8885f20SAxel Dörfler 	size_t size = copy_port_message(message, _code, buffer, bufferSize,
1322e8885f20SAxel Dörfler 		userCopy);
1323e8885f20SAxel Dörfler 
1324e8885f20SAxel Dörfler 	put_port_message(message);
1325224aee3fSIngo Weinhold 	return size;
1326224aee3fSIngo Weinhold }
1327224aee3fSIngo Weinhold 
1328224aee3fSIngo Weinhold 
1329224aee3fSIngo Weinhold status_t
1330e8885f20SAxel Dörfler write_port(port_id id, int32 msgCode, const void* buffer, size_t bufferSize)
1331224aee3fSIngo Weinhold {
1332e8885f20SAxel Dörfler 	iovec vec = { (void*)buffer, bufferSize };
1333224aee3fSIngo Weinhold 
1334224aee3fSIngo Weinhold 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0);
1335224aee3fSIngo Weinhold }
1336224aee3fSIngo Weinhold 
1337224aee3fSIngo Weinhold 
1338224aee3fSIngo Weinhold status_t
1339e8885f20SAxel Dörfler write_port_etc(port_id id, int32 msgCode, const void* buffer,
1340224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1341224aee3fSIngo Weinhold {
1342e8885f20SAxel Dörfler 	iovec vec = { (void*)buffer, bufferSize };
1343224aee3fSIngo Weinhold 
1344224aee3fSIngo Weinhold 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout);
1345224aee3fSIngo Weinhold }
1346224aee3fSIngo Weinhold 
1347224aee3fSIngo Weinhold 
1348224aee3fSIngo Weinhold status_t
1349224aee3fSIngo Weinhold writev_port_etc(port_id id, int32 msgCode, const iovec* msgVecs,
1350e8885f20SAxel Dörfler 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1351224aee3fSIngo Weinhold {
1352224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1353224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1354224aee3fSIngo Weinhold 	if (bufferSize > PORT_MAX_MESSAGE_SIZE)
1355224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1356224aee3fSIngo Weinhold 
1357e8885f20SAxel Dörfler 	// mask irrelevant flags (for acquire_sem() usage)
1358e8885f20SAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1359e8885f20SAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1360f28dd36bSAxel Dörfler 	if ((flags & B_RELATIVE_TIMEOUT) != 0
1361f28dd36bSAxel Dörfler 		&& timeout != B_INFINITE_TIMEOUT && timeout > 0) {
1362f28dd36bSAxel Dörfler 		// Make the timeout absolute, since we have more than one step where
1363f28dd36bSAxel Dörfler 		// we might have to wait
1364f28dd36bSAxel Dörfler 		flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT;
1365f28dd36bSAxel Dörfler 		timeout += system_time();
1366f28dd36bSAxel Dörfler 	}
1367f28dd36bSAxel Dörfler 
1368e8885f20SAxel Dörfler 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0;
1369e8885f20SAxel Dörfler 
1370f28dd36bSAxel Dörfler 	status_t status;
13711c61ec1aSIngo Weinhold 	port_message* message = NULL;
1372e8885f20SAxel Dörfler 
137324df6592SIngo Weinhold 	// get the port
137424df6592SIngo Weinhold 	Port* port = get_locked_port(id);
137524df6592SIngo Weinhold 	if (port == NULL) {
1376224aee3fSIngo Weinhold 		TRACE(("write_port_etc: invalid port_id %ld\n", id));
1377224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1378224aee3fSIngo Weinhold 	}
137924df6592SIngo Weinhold 	MutexLocker locker(port->lock, true);
138024df6592SIngo Weinhold 
138124df6592SIngo Weinhold 	if (is_port_closed(port)) {
1382224aee3fSIngo Weinhold 		TRACE(("write_port_etc: port %ld closed\n", id));
1383224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1384224aee3fSIngo Weinhold 	}
1385224aee3fSIngo Weinhold 
138624df6592SIngo Weinhold 	if (port->write_count <= 0) {
1387f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1388f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1389f28dd36bSAxel Dörfler 
139024df6592SIngo Weinhold 		port->write_count--;
1391f28dd36bSAxel Dörfler 
1392e8885f20SAxel Dörfler 		// We need to block in order to wait for a free message slot
1393e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
139424df6592SIngo Weinhold 		port->write_condition.Add(&entry);
1395224aee3fSIngo Weinhold 
1396e8885f20SAxel Dörfler 		locker.Unlock();
1397224aee3fSIngo Weinhold 
1398f28dd36bSAxel Dörfler 		status = entry.Wait(flags, timeout);
1399224aee3fSIngo Weinhold 
140024df6592SIngo Weinhold 		// re-lock
140124df6592SIngo Weinhold 		Port* newPort = get_locked_port(id);
140224df6592SIngo Weinhold 		if (newPort == NULL) {
140324df6592SIngo Weinhold 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
140424df6592SIngo Weinhold 			return B_BAD_PORT_ID;
140524df6592SIngo Weinhold 		}
140624df6592SIngo Weinhold 		locker.SetTo(newPort->lock, true);
1407e8885f20SAxel Dörfler 
140824df6592SIngo Weinhold 		if (newPort != port || is_port_closed(port)) {
1409e8885f20SAxel Dörfler 			// the port is no longer there
141024df6592SIngo Weinhold 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1411224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1412224aee3fSIngo Weinhold 		}
1413224aee3fSIngo Weinhold 
1414c3bc71d6SIngo Weinhold 		if (status != B_OK)
1415f28dd36bSAxel Dörfler 			goto error;
1416f28dd36bSAxel Dörfler 	} else
141724df6592SIngo Weinhold 		port->write_count--;
1418e8885f20SAxel Dörfler 
1419f28dd36bSAxel Dörfler 	status = get_port_message(msgCode, bufferSize, flags, timeout,
1420cd3e02caSMichael Lotz 		&message, *port);
1421cd3e02caSMichael Lotz 	if (status != B_OK) {
1422cd3e02caSMichael Lotz 		if (status == B_BAD_PORT_ID) {
1423cd3e02caSMichael Lotz 			// the port had to be unlocked and is now no longer there
1424cd3e02caSMichael Lotz 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1425cd3e02caSMichael Lotz 			return B_BAD_PORT_ID;
1426cd3e02caSMichael Lotz 		}
1427cd3e02caSMichael Lotz 
1428f28dd36bSAxel Dörfler 		goto error;
1429cd3e02caSMichael Lotz 	}
1430224aee3fSIngo Weinhold 
14317727e08eSIngo Weinhold 	// sender credentials
1432e8885f20SAxel Dörfler 	message->sender = geteuid();
1433e8885f20SAxel Dörfler 	message->sender_group = getegid();
1434e8885f20SAxel Dörfler 	message->sender_team = team_get_current_team_id();
14357727e08eSIngo Weinhold 
1436224aee3fSIngo Weinhold 	if (bufferSize > 0) {
14372b861349SMichael Lotz 		size_t offset = 0;
14382b861349SMichael Lotz 		for (uint32 i = 0; i < vecCount; i++) {
1439224aee3fSIngo Weinhold 			size_t bytes = msgVecs[i].iov_len;
1440224aee3fSIngo Weinhold 			if (bytes > bufferSize)
1441224aee3fSIngo Weinhold 				bytes = bufferSize;
1442224aee3fSIngo Weinhold 
14432b861349SMichael Lotz 			if (userCopy) {
14442b861349SMichael Lotz 				status_t status = user_memcpy(message->buffer + offset,
1445e8885f20SAxel Dörfler 					msgVecs[i].iov_base, bytes);
1446e8885f20SAxel Dörfler 				if (status != B_OK) {
1447e8885f20SAxel Dörfler 					put_port_message(message);
1448f28dd36bSAxel Dörfler 					goto error;
144961de73e2SIngo Weinhold 				}
14502b861349SMichael Lotz 			} else
14512b861349SMichael Lotz 				memcpy(message->buffer + offset, msgVecs[i].iov_base, bytes);
1452224aee3fSIngo Weinhold 
1453224aee3fSIngo Weinhold 			bufferSize -= bytes;
1454224aee3fSIngo Weinhold 			if (bufferSize == 0)
1455224aee3fSIngo Weinhold 				break;
1456224aee3fSIngo Weinhold 
14572b861349SMichael Lotz 			offset += bytes;
1458224aee3fSIngo Weinhold 		}
1459224aee3fSIngo Weinhold 	}
1460224aee3fSIngo Weinhold 
146124df6592SIngo Weinhold 	port->messages.Add(message);
146224df6592SIngo Weinhold 	port->read_count++;
1463224aee3fSIngo Weinhold 
146424df6592SIngo Weinhold 	T(Write(id, port->read_count, port->write_count, message->code,
146524df6592SIngo Weinhold 		message->size, B_OK));
1466f28dd36bSAxel Dörfler 
146724df6592SIngo Weinhold 	notify_port_select_events(port, B_EVENT_READ);
146824df6592SIngo Weinhold 	port->read_condition.NotifyOne();
1469e8885f20SAxel Dörfler 	return B_OK;
1470f28dd36bSAxel Dörfler 
1471f28dd36bSAxel Dörfler error:
1472f28dd36bSAxel Dörfler 	// Give up our slot in the queue again, and let someone else
1473f28dd36bSAxel Dörfler 	// try and fail
147424df6592SIngo Weinhold 	T(Write(id, port->read_count, port->write_count, 0, 0, status));
147524df6592SIngo Weinhold 	port->write_count++;
147624df6592SIngo Weinhold 	notify_port_select_events(port, B_EVENT_WRITE);
147724df6592SIngo Weinhold 	port->write_condition.NotifyOne();
1478f28dd36bSAxel Dörfler 
1479f28dd36bSAxel Dörfler 	return status;
1480224aee3fSIngo Weinhold }
1481224aee3fSIngo Weinhold 
1482224aee3fSIngo Weinhold 
1483224aee3fSIngo Weinhold status_t
148425028839SAxel Dörfler set_port_owner(port_id id, team_id newTeamID)
1485224aee3fSIngo Weinhold {
148625028839SAxel Dörfler 	TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, newTeamID));
1487224aee3fSIngo Weinhold 
1488e8885f20SAxel Dörfler 	if (id < 0)
1489224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1490224aee3fSIngo Weinhold 
149124df6592SIngo Weinhold 	// get the new team
149224df6592SIngo Weinhold 	Team* team = Team::Get(newTeamID);
149324df6592SIngo Weinhold 	if (team == NULL)
149424df6592SIngo Weinhold 		return B_BAD_TEAM_ID;
149524df6592SIngo Weinhold 	BReference<Team> teamReference(team, true);
1496224aee3fSIngo Weinhold 
149724df6592SIngo Weinhold 	// get the port
149824df6592SIngo Weinhold 	MutexLocker portsLocker(sPortsLock);
149924df6592SIngo Weinhold 	Port* port = sPorts.Lookup(id);
150024df6592SIngo Weinhold 	if (port == NULL) {
1501224aee3fSIngo Weinhold 		TRACE(("set_port_owner: invalid port_id %ld\n", id));
1502224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1503224aee3fSIngo Weinhold 	}
150424df6592SIngo Weinhold 	MutexLocker locker(port->lock);
1505f28dd36bSAxel Dörfler 
1506224aee3fSIngo Weinhold 	// transfer ownership to other team
150724df6592SIngo Weinhold 	if (team->id != port->owner) {
150824df6592SIngo Weinhold 		list_remove_link(&port->team_link);
150924df6592SIngo Weinhold 		list_add_item(&team->port_list, &port->team_link);
151024df6592SIngo Weinhold 		port->owner = team->id;
151124df6592SIngo Weinhold 	}
1512224aee3fSIngo Weinhold 
151324df6592SIngo Weinhold 	T(OwnerChange(port, team->id, B_OK));
1514e8885f20SAxel Dörfler 	return B_OK;
1515224aee3fSIngo Weinhold }
1516224aee3fSIngo Weinhold 
1517224aee3fSIngo Weinhold 
1518224aee3fSIngo Weinhold //	#pragma mark - syscalls
1519224aee3fSIngo Weinhold 
1520224aee3fSIngo Weinhold 
1521224aee3fSIngo Weinhold port_id
1522224aee3fSIngo Weinhold _user_create_port(int32 queueLength, const char *userName)
1523224aee3fSIngo Weinhold {
1524224aee3fSIngo Weinhold 	char name[B_OS_NAME_LENGTH];
1525224aee3fSIngo Weinhold 
1526224aee3fSIngo Weinhold 	if (userName == NULL)
1527224aee3fSIngo Weinhold 		return create_port(queueLength, NULL);
1528224aee3fSIngo Weinhold 
1529224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userName)
1530224aee3fSIngo Weinhold 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1531224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1532224aee3fSIngo Weinhold 
1533224aee3fSIngo Weinhold 	return create_port(queueLength, name);
1534224aee3fSIngo Weinhold }
1535224aee3fSIngo Weinhold 
1536224aee3fSIngo Weinhold 
1537224aee3fSIngo Weinhold status_t
1538224aee3fSIngo Weinhold _user_close_port(port_id id)
1539224aee3fSIngo Weinhold {
1540224aee3fSIngo Weinhold 	return close_port(id);
1541224aee3fSIngo Weinhold }
1542224aee3fSIngo Weinhold 
1543224aee3fSIngo Weinhold 
1544224aee3fSIngo Weinhold status_t
1545224aee3fSIngo Weinhold _user_delete_port(port_id id)
1546224aee3fSIngo Weinhold {
1547224aee3fSIngo Weinhold 	return delete_port(id);
1548224aee3fSIngo Weinhold }
1549224aee3fSIngo Weinhold 
1550224aee3fSIngo Weinhold 
1551224aee3fSIngo Weinhold port_id
1552224aee3fSIngo Weinhold _user_find_port(const char *userName)
1553224aee3fSIngo Weinhold {
1554224aee3fSIngo Weinhold 	char name[B_OS_NAME_LENGTH];
1555224aee3fSIngo Weinhold 
1556224aee3fSIngo Weinhold 	if (userName == NULL)
1557224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1558224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userName)
1559224aee3fSIngo Weinhold 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1560224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1561224aee3fSIngo Weinhold 
1562224aee3fSIngo Weinhold 	return find_port(name);
1563224aee3fSIngo Weinhold }
1564224aee3fSIngo Weinhold 
1565224aee3fSIngo Weinhold 
1566224aee3fSIngo Weinhold status_t
1567224aee3fSIngo Weinhold _user_get_port_info(port_id id, struct port_info *userInfo)
1568224aee3fSIngo Weinhold {
1569224aee3fSIngo Weinhold 	struct port_info info;
1570224aee3fSIngo Weinhold 	status_t status;
1571224aee3fSIngo Weinhold 
1572224aee3fSIngo Weinhold 	if (userInfo == NULL)
1573224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1574224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userInfo))
1575224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1576224aee3fSIngo Weinhold 
1577224aee3fSIngo Weinhold 	status = get_port_info(id, &info);
1578224aee3fSIngo Weinhold 
1579224aee3fSIngo Weinhold 	// copy back to user space
15804048494cSIngo Weinhold 	if (status == B_OK
15814048494cSIngo Weinhold 		&& user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK)
1582224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1583224aee3fSIngo Weinhold 
1584224aee3fSIngo Weinhold 	return status;
1585224aee3fSIngo Weinhold }
1586224aee3fSIngo Weinhold 
1587224aee3fSIngo Weinhold 
1588224aee3fSIngo Weinhold status_t
15894048494cSIngo Weinhold _user_get_next_port_info(team_id team, int32 *userCookie,
15904048494cSIngo Weinhold 	struct port_info *userInfo)
1591224aee3fSIngo Weinhold {
1592224aee3fSIngo Weinhold 	struct port_info info;
1593224aee3fSIngo Weinhold 	status_t status;
1594224aee3fSIngo Weinhold 	int32 cookie;
1595224aee3fSIngo Weinhold 
1596224aee3fSIngo Weinhold 	if (userCookie == NULL || userInfo == NULL)
1597224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1598224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo)
1599224aee3fSIngo Weinhold 		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
1600224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1601224aee3fSIngo Weinhold 
1602224aee3fSIngo Weinhold 	status = get_next_port_info(team, &cookie, &info);
1603224aee3fSIngo Weinhold 
1604224aee3fSIngo Weinhold 	// copy back to user space
1605224aee3fSIngo Weinhold 	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
16064048494cSIngo Weinhold 		|| (status == B_OK && user_memcpy(userInfo, &info,
16074048494cSIngo Weinhold 				sizeof(struct port_info)) < B_OK))
1608224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1609224aee3fSIngo Weinhold 
1610224aee3fSIngo Weinhold 	return status;
1611224aee3fSIngo Weinhold }
1612224aee3fSIngo Weinhold 
1613224aee3fSIngo Weinhold 
1614224aee3fSIngo Weinhold ssize_t
1615224aee3fSIngo Weinhold _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout)
1616224aee3fSIngo Weinhold {
16174048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
16184048494cSIngo Weinhold 
16194048494cSIngo Weinhold 	status_t status = port_buffer_size_etc(port, flags | B_CAN_INTERRUPT,
16204048494cSIngo Weinhold 		timeout);
16214048494cSIngo Weinhold 
16224048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1623224aee3fSIngo Weinhold }
1624224aee3fSIngo Weinhold 
1625224aee3fSIngo Weinhold 
1626224aee3fSIngo Weinhold ssize_t
1627224aee3fSIngo Weinhold _user_port_count(port_id port)
1628224aee3fSIngo Weinhold {
1629224aee3fSIngo Weinhold 	return port_count(port);
1630224aee3fSIngo Weinhold }
1631224aee3fSIngo Weinhold 
1632224aee3fSIngo Weinhold 
1633224aee3fSIngo Weinhold status_t
1634224aee3fSIngo Weinhold _user_set_port_owner(port_id port, team_id team)
1635224aee3fSIngo Weinhold {
1636224aee3fSIngo Weinhold 	return set_port_owner(port, team);
1637224aee3fSIngo Weinhold }
1638224aee3fSIngo Weinhold 
1639224aee3fSIngo Weinhold 
1640224aee3fSIngo Weinhold ssize_t
1641224aee3fSIngo Weinhold _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer,
1642224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1643224aee3fSIngo Weinhold {
1644224aee3fSIngo Weinhold 	int32 messageCode;
1645224aee3fSIngo Weinhold 	ssize_t	bytesRead;
1646224aee3fSIngo Weinhold 
16474048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
16484048494cSIngo Weinhold 
1649224aee3fSIngo Weinhold 	if (userBuffer == NULL && bufferSize != 0)
1650224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1651224aee3fSIngo Weinhold 	if ((userCode != NULL && !IS_USER_ADDRESS(userCode))
1652224aee3fSIngo Weinhold 		|| (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)))
1653224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1654224aee3fSIngo Weinhold 
1655224aee3fSIngo Weinhold 	bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize,
1656224aee3fSIngo Weinhold 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1657224aee3fSIngo Weinhold 
1658224aee3fSIngo Weinhold 	if (bytesRead >= 0 && userCode != NULL
1659224aee3fSIngo Weinhold 		&& user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK)
1660224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1661224aee3fSIngo Weinhold 
16624048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(bytesRead, timeout);
1663224aee3fSIngo Weinhold }
1664224aee3fSIngo Weinhold 
1665224aee3fSIngo Weinhold 
1666224aee3fSIngo Weinhold status_t
1667224aee3fSIngo Weinhold _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer,
1668224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1669224aee3fSIngo Weinhold {
1670224aee3fSIngo Weinhold 	iovec vec = { (void *)userBuffer, bufferSize };
1671224aee3fSIngo Weinhold 
16724048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
16734048494cSIngo Weinhold 
1674224aee3fSIngo Weinhold 	if (userBuffer == NULL && bufferSize != 0)
1675224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1676224aee3fSIngo Weinhold 	if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))
1677224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1678224aee3fSIngo Weinhold 
16794048494cSIngo Weinhold 	status_t status = writev_port_etc(port, messageCode, &vec, 1, bufferSize,
1680224aee3fSIngo Weinhold 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
16814048494cSIngo Weinhold 
16824048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1683224aee3fSIngo Weinhold }
1684224aee3fSIngo Weinhold 
1685224aee3fSIngo Weinhold 
1686224aee3fSIngo Weinhold status_t
1687224aee3fSIngo Weinhold _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs,
1688224aee3fSIngo Weinhold 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1689224aee3fSIngo Weinhold {
16904048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
1691224aee3fSIngo Weinhold 
1692224aee3fSIngo Weinhold 	if (userVecs == NULL && bufferSize != 0)
1693224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1694224aee3fSIngo Weinhold 	if (userVecs != NULL && !IS_USER_ADDRESS(userVecs))
1695224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1696224aee3fSIngo Weinhold 
16974048494cSIngo Weinhold 	iovec *vecs = NULL;
1698224aee3fSIngo Weinhold 	if (userVecs && vecCount != 0) {
1699224aee3fSIngo Weinhold 		vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
1700224aee3fSIngo Weinhold 		if (vecs == NULL)
1701224aee3fSIngo Weinhold 			return B_NO_MEMORY;
1702224aee3fSIngo Weinhold 
1703224aee3fSIngo Weinhold 		if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) {
1704224aee3fSIngo Weinhold 			free(vecs);
1705224aee3fSIngo Weinhold 			return B_BAD_ADDRESS;
1706224aee3fSIngo Weinhold 		}
1707224aee3fSIngo Weinhold 	}
17084048494cSIngo Weinhold 
17094048494cSIngo Weinhold 	status_t status = writev_port_etc(port, messageCode, vecs, vecCount,
17104048494cSIngo Weinhold 		bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT,
17114048494cSIngo Weinhold 		timeout);
1712224aee3fSIngo Weinhold 
1713224aee3fSIngo Weinhold 	free(vecs);
17144048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1715224aee3fSIngo Weinhold }
17167727e08eSIngo Weinhold 
17177727e08eSIngo Weinhold 
17187727e08eSIngo Weinhold status_t
17197727e08eSIngo Weinhold _user_get_port_message_info_etc(port_id port, port_message_info *userInfo,
17207727e08eSIngo Weinhold 	size_t infoSize, uint32 flags, bigtime_t timeout)
17217727e08eSIngo Weinhold {
17227727e08eSIngo Weinhold 	if (userInfo == NULL || infoSize != sizeof(port_message_info))
17237727e08eSIngo Weinhold 		return B_BAD_VALUE;
17247727e08eSIngo Weinhold 
17257727e08eSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
17267727e08eSIngo Weinhold 
17277727e08eSIngo Weinhold 	port_message_info info;
17287727e08eSIngo Weinhold 	status_t error = _get_port_message_info_etc(port, &info, sizeof(info),
17297727e08eSIngo Weinhold 		flags | B_CAN_INTERRUPT, timeout);
17307727e08eSIngo Weinhold 
17317727e08eSIngo Weinhold 	// copy info to userland
17327727e08eSIngo Weinhold 	if (error == B_OK && (!IS_USER_ADDRESS(userInfo)
17337727e08eSIngo Weinhold 			|| user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) {
17347727e08eSIngo Weinhold 		error = B_BAD_ADDRESS;
17357727e08eSIngo Weinhold 	}
17367727e08eSIngo Weinhold 
17377727e08eSIngo Weinhold 	return syscall_restart_handle_timeout_post(error, timeout);
17387727e08eSIngo Weinhold }
1739