xref: /haiku/src/system/kernel/port.cpp (revision 057719ef904e9c6fb0146f97b575d4a93ce23c06)
1224aee3fSIngo Weinhold /*
224df6592SIngo Weinhold  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3748c0f30SAxel Dörfler  * Copyright 2002-2015, 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 
16748c0f30SAxel Dörfler #include <algorithm>
174048494cSIngo Weinhold #include <ctype.h>
184048494cSIngo Weinhold #include <iovec.h>
194048494cSIngo Weinhold #include <stdlib.h>
204048494cSIngo Weinhold #include <string.h>
21224aee3fSIngo Weinhold 
22224aee3fSIngo Weinhold #include <OS.h>
23224aee3fSIngo Weinhold 
2424df6592SIngo Weinhold #include <AutoDeleter.h>
2524df6592SIngo Weinhold 
26224aee3fSIngo Weinhold #include <arch/int.h>
27e8885f20SAxel Dörfler #include <heap.h>
284048494cSIngo Weinhold #include <kernel.h>
2951755cf8SAxel Dörfler #include <Notifications.h>
304048494cSIngo Weinhold #include <sem.h>
314048494cSIngo Weinhold #include <syscall_restart.h>
324048494cSIngo Weinhold #include <team.h>
33f28dd36bSAxel Dörfler #include <tracing.h>
34b4ec7b8eSIngo Weinhold #include <util/AutoLock.h>
354048494cSIngo Weinhold #include <util/list.h>
367198f765SAxel Dörfler #include <vm/vm.h>
37224aee3fSIngo Weinhold #include <wait_for_objects.h>
38224aee3fSIngo Weinhold 
39224aee3fSIngo Weinhold 
40224aee3fSIngo Weinhold //#define TRACE_PORTS
41224aee3fSIngo Weinhold #ifdef TRACE_PORTS
42224aee3fSIngo Weinhold #	define TRACE(x) dprintf x
43224aee3fSIngo Weinhold #else
44224aee3fSIngo Weinhold #	define TRACE(x)
45224aee3fSIngo Weinhold #endif
46224aee3fSIngo Weinhold 
47224aee3fSIngo Weinhold 
487f64b301SJulian Harnath #if __GNUC__ >= 3
497f64b301SJulian Harnath #	define GCC_2_NRV(x)
507f64b301SJulian Harnath 	// GCC >= 3.1 doesn't need it anymore
517f64b301SJulian Harnath #else
527f64b301SJulian Harnath #	define GCC_2_NRV(x) return x;
537f64b301SJulian Harnath 	// GCC 2 named return value syntax
547f64b301SJulian Harnath 	// see http://gcc.gnu.org/onlinedocs/gcc-2.95.2/gcc_5.html#SEC106
557f64b301SJulian Harnath #endif
567f64b301SJulian Harnath 
577f64b301SJulian Harnath 
5824df6592SIngo Weinhold // Locking:
597f64b301SJulian Harnath // * sPortsLock: Protects the sPorts and sPortsByName hash tables.
607f64b301SJulian Harnath // * sTeamListLock[]: Protects Team::port_list. Lock index for given team is
617f64b301SJulian Harnath //   (Team::id % kTeamListLockCount).
627f64b301SJulian Harnath // * Port::lock: Protects all Port members save team_link, hash_link, lock and
637f64b301SJulian Harnath //   state. id is immutable.
6424df6592SIngo Weinhold //
657f64b301SJulian Harnath // Port::state ensures atomicity by providing a linearization point for adding
667f64b301SJulian Harnath // and removing ports to the hash tables and the team port list.
677f64b301SJulian Harnath // * sPortsLock and sTeamListLock[] are locked separately and not in a nested
687f64b301SJulian Harnath //   fashion, so a port can be in the hash table but not in the team port list
697f64b301SJulian Harnath //   or vice versa. => Without further provisions, insertion and removal are
707f64b301SJulian Harnath //   not linearizable and thus not concurrency-safe.
717f64b301SJulian Harnath // * To make insertion and removal linearizable, Port::state was added. It is
727f64b301SJulian Harnath //   always only accessed atomically and updates are done using
737f64b301SJulian Harnath //   atomic_test_and_set(). A port is only seen as existent when its state is
747f64b301SJulian Harnath //   Port::kActive.
757f64b301SJulian Harnath // * Deletion of ports is done in two steps: logical and physical deletion.
767f64b301SJulian Harnath //   First, logical deletion happens and sets Port::state to Port::kDeleted.
777f64b301SJulian Harnath //   This is an atomic operation and from then on, functions like
787f64b301SJulian Harnath //   get_locked_port() consider this port as deleted and ignore it. Secondly,
797f64b301SJulian Harnath //   physical deletion removes the port from hash tables and team port list.
807f64b301SJulian Harnath //   In a similar way, port creation first inserts into hashes and team list
817f64b301SJulian Harnath //   and only then sets port to Port::kActive.
827f64b301SJulian Harnath //   This creates a linearization point at the atomic update of Port::state,
837f64b301SJulian Harnath //   operations become linearizable and thus concurrency-safe. To help
847f64b301SJulian Harnath //   understanding, the linearization points are annotated with comments.
857f64b301SJulian Harnath // * Ports are reference-counted so it's not a problem when someone still
867f64b301SJulian Harnath //   has a reference to a deleted port.
8724df6592SIngo Weinhold 
8824df6592SIngo Weinhold 
89c73d1301SMichael Lotz namespace {
9024df6592SIngo Weinhold 
91e8885f20SAxel Dörfler struct port_message : DoublyLinkedListLinkImpl<port_message> {
92224aee3fSIngo Weinhold 	int32				code;
93224aee3fSIngo Weinhold 	size_t				size;
947727e08eSIngo Weinhold 	uid_t				sender;
957727e08eSIngo Weinhold 	gid_t				sender_group;
967727e08eSIngo Weinhold 	team_id				sender_team;
97e8885f20SAxel Dörfler 	char				buffer[0];
98e8885f20SAxel Dörfler };
99e8885f20SAxel Dörfler 
100e8885f20SAxel Dörfler typedef DoublyLinkedList<port_message> MessageList;
101224aee3fSIngo Weinhold 
102c73d1301SMichael Lotz } // namespace
103c73d1301SMichael Lotz 
104c73d1301SMichael Lotz 
105c73d1301SMichael Lotz static void put_port_message(port_message* message);
106c73d1301SMichael Lotz 
107c73d1301SMichael Lotz 
108c73d1301SMichael Lotz namespace {
10924df6592SIngo Weinhold 
1107f64b301SJulian Harnath struct Port : public KernelReferenceable {
1117f64b301SJulian Harnath 	enum State {
1127f64b301SJulian Harnath 		kUnused = 0,
1137f64b301SJulian Harnath 		kActive,
1147f64b301SJulian Harnath 		kDeleted
1157f64b301SJulian Harnath 	};
1167f64b301SJulian Harnath 
11786a999adSAxel Dörfler 	struct list_link	team_link;
11824df6592SIngo Weinhold 	Port*				hash_link;
119224aee3fSIngo Weinhold 	port_id				id;
120224aee3fSIngo Weinhold 	team_id				owner;
1217f64b301SJulian Harnath 	Port*				name_hash_link;
1227f64b301SJulian Harnath 	size_t				name_hash;
123224aee3fSIngo Weinhold 	int32				capacity;
124e8885f20SAxel Dörfler 	mutex				lock;
125d0f2d828SPawel Dziepak 	int32				state;
1267d592ec4SAxel Dörfler 	uint32				read_count;
127e8885f20SAxel Dörfler 	int32				write_count;
128e8885f20SAxel Dörfler 	ConditionVariable	read_condition;
129e8885f20SAxel Dörfler 	ConditionVariable	write_condition;
130e8885f20SAxel Dörfler 	int32				total_count;
131e8885f20SAxel Dörfler 		// messages read from port since creation
132224aee3fSIngo Weinhold 	select_info*		select_infos;
133e8885f20SAxel Dörfler 	MessageList			messages;
13424df6592SIngo Weinhold 
1353c47c28aSAugustin Cavalier 	Port(team_id owner, int32 queueLength, const char* name)
13624df6592SIngo Weinhold 		:
13724df6592SIngo Weinhold 		owner(owner),
1387f64b301SJulian Harnath 		name_hash(0),
13924df6592SIngo Weinhold 		capacity(queueLength),
1407f64b301SJulian Harnath 		state(kUnused),
14124df6592SIngo Weinhold 		read_count(0),
14224df6592SIngo Weinhold 		write_count(queueLength),
14324df6592SIngo Weinhold 		total_count(0),
14424df6592SIngo Weinhold 		select_infos(NULL)
14524df6592SIngo Weinhold 	{
14624df6592SIngo Weinhold 		// id is initialized when the caller adds the port to the hash table
14724df6592SIngo Weinhold 
1483c47c28aSAugustin Cavalier 		mutex_init_etc(&lock, name, MUTEX_FLAG_CLONE_NAME);
14924df6592SIngo Weinhold 		read_condition.Init(this, "port read");
15024df6592SIngo Weinhold 		write_condition.Init(this, "port write");
15124df6592SIngo Weinhold 	}
15224df6592SIngo Weinhold 
1537f64b301SJulian Harnath 	virtual ~Port()
15424df6592SIngo Weinhold 	{
15524df6592SIngo Weinhold 		while (port_message* message = messages.RemoveHead())
15624df6592SIngo Weinhold 			put_port_message(message);
15724df6592SIngo Weinhold 
1583c47c28aSAugustin Cavalier 		mutex_destroy(&lock);
15924df6592SIngo Weinhold 	}
160224aee3fSIngo Weinhold };
161224aee3fSIngo Weinhold 
16224df6592SIngo Weinhold 
16324df6592SIngo Weinhold struct PortHashDefinition {
16424df6592SIngo Weinhold 	typedef port_id		KeyType;
16524df6592SIngo Weinhold 	typedef	Port		ValueType;
16624df6592SIngo Weinhold 
16724df6592SIngo Weinhold 	size_t HashKey(port_id key) const
16824df6592SIngo Weinhold 	{
16924df6592SIngo Weinhold 		return key;
17024df6592SIngo Weinhold 	}
17124df6592SIngo Weinhold 
17224df6592SIngo Weinhold 	size_t Hash(Port* value) const
17324df6592SIngo Weinhold 	{
17424df6592SIngo Weinhold 		return HashKey(value->id);
17524df6592SIngo Weinhold 	}
17624df6592SIngo Weinhold 
17724df6592SIngo Weinhold 	bool Compare(port_id key, Port* value) const
17824df6592SIngo Weinhold 	{
17924df6592SIngo Weinhold 		return value->id == key;
18024df6592SIngo Weinhold 	}
18124df6592SIngo Weinhold 
18224df6592SIngo Weinhold 	Port*& GetLink(Port* value) const
18324df6592SIngo Weinhold 	{
18424df6592SIngo Weinhold 		return value->hash_link;
18524df6592SIngo Weinhold 	}
18624df6592SIngo Weinhold };
18724df6592SIngo Weinhold 
18824df6592SIngo Weinhold typedef BOpenHashTable<PortHashDefinition> PortHashTable;
18924df6592SIngo Weinhold 
19024df6592SIngo Weinhold 
1917f64b301SJulian Harnath struct PortNameHashDefinition {
1927f64b301SJulian Harnath 	typedef const char*	KeyType;
1937f64b301SJulian Harnath 	typedef	Port		ValueType;
1947f64b301SJulian Harnath 
1957f64b301SJulian Harnath 	size_t HashKey(const char* key) const
1967f64b301SJulian Harnath 	{
1977f64b301SJulian Harnath 		// Hash function: hash(key) =  key[0] * 31^(length - 1)
1987f64b301SJulian Harnath 		//   + key[1] * 31^(length - 2) + ... + key[length - 1]
1997f64b301SJulian Harnath 
2007f64b301SJulian Harnath 		const size_t length = strlen(key);
2017f64b301SJulian Harnath 
2027f64b301SJulian Harnath 		size_t hash = 0;
2037f64b301SJulian Harnath 		for (size_t index = 0; index < length; index++)
2047f64b301SJulian Harnath 			hash = 31 * hash + key[index];
2057f64b301SJulian Harnath 
2067f64b301SJulian Harnath 		return hash;
2077f64b301SJulian Harnath 	}
2087f64b301SJulian Harnath 
2097f64b301SJulian Harnath 	size_t Hash(Port* value) const
2107f64b301SJulian Harnath 	{
2117f64b301SJulian Harnath 		size_t& hash = value->name_hash;
2127f64b301SJulian Harnath 		if (hash == 0)
2137f64b301SJulian Harnath 			hash = HashKey(value->lock.name);
2147f64b301SJulian Harnath 		return hash;
2157f64b301SJulian Harnath 	}
2167f64b301SJulian Harnath 
2177f64b301SJulian Harnath 	bool Compare(const char* key, Port* value) const
2187f64b301SJulian Harnath 	{
2197f64b301SJulian Harnath 		return (strcmp(key, value->lock.name) == 0);
2207f64b301SJulian Harnath 	}
2217f64b301SJulian Harnath 
2227f64b301SJulian Harnath 	Port*& GetLink(Port* value) const
2237f64b301SJulian Harnath 	{
2247f64b301SJulian Harnath 		return value->name_hash_link;
2257f64b301SJulian Harnath 	}
2267f64b301SJulian Harnath };
2277f64b301SJulian Harnath 
2287f64b301SJulian Harnath typedef BOpenHashTable<PortNameHashDefinition> PortNameHashTable;
2297f64b301SJulian Harnath 
2307f64b301SJulian Harnath 
23151755cf8SAxel Dörfler class PortNotificationService : public DefaultNotificationService {
23251755cf8SAxel Dörfler public:
23351755cf8SAxel Dörfler 							PortNotificationService();
23451755cf8SAxel Dörfler 
23551755cf8SAxel Dörfler 			void			Notify(uint32 opcode, port_id team);
23651755cf8SAxel Dörfler };
237224aee3fSIngo Weinhold 
238c73d1301SMichael Lotz } // namespace
239c73d1301SMichael Lotz 
240f28dd36bSAxel Dörfler 
2417f64b301SJulian Harnath // #pragma mark - tracing
2427f64b301SJulian Harnath 
2437f64b301SJulian Harnath 
244f28dd36bSAxel Dörfler #if PORT_TRACING
245f28dd36bSAxel Dörfler namespace PortTracing {
246f28dd36bSAxel Dörfler 
247f28dd36bSAxel Dörfler class Create : public AbstractTraceEntry {
248f28dd36bSAxel Dörfler public:
24924df6592SIngo Weinhold 	Create(Port* port)
250f28dd36bSAxel Dörfler 		:
25124df6592SIngo Weinhold 		fID(port->id),
25224df6592SIngo Weinhold 		fOwner(port->owner),
25324df6592SIngo Weinhold 		fCapacity(port->capacity)
254f28dd36bSAxel Dörfler 	{
25524df6592SIngo Weinhold 		fName = alloc_tracing_buffer_strcpy(port->lock.name, B_OS_NAME_LENGTH,
256f28dd36bSAxel Dörfler 			false);
257f28dd36bSAxel Dörfler 
258f28dd36bSAxel Dörfler 		Initialized();
259f28dd36bSAxel Dörfler 	}
260f28dd36bSAxel Dörfler 
261f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
262f28dd36bSAxel Dörfler 	{
263f28dd36bSAxel Dörfler 		out.Print("port %ld created, name \"%s\", owner %ld, capacity %ld",
264f28dd36bSAxel Dörfler 			fID, fName, fOwner, fCapacity);
265f28dd36bSAxel Dörfler 	}
266f28dd36bSAxel Dörfler 
267f28dd36bSAxel Dörfler private:
268f28dd36bSAxel Dörfler 	port_id				fID;
269f28dd36bSAxel Dörfler 	char*				fName;
270f28dd36bSAxel Dörfler 	team_id				fOwner;
271f28dd36bSAxel Dörfler 	int32		 		fCapacity;
272f28dd36bSAxel Dörfler };
273f28dd36bSAxel Dörfler 
274f28dd36bSAxel Dörfler 
275f28dd36bSAxel Dörfler class Delete : public AbstractTraceEntry {
276f28dd36bSAxel Dörfler public:
27724df6592SIngo Weinhold 	Delete(Port* port)
278f28dd36bSAxel Dörfler 		:
27924df6592SIngo Weinhold 		fID(port->id)
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 deleted", fID);
287f28dd36bSAxel Dörfler 	}
288f28dd36bSAxel Dörfler 
289f28dd36bSAxel Dörfler private:
290f28dd36bSAxel Dörfler 	port_id				fID;
291f28dd36bSAxel Dörfler };
292f28dd36bSAxel Dörfler 
293f28dd36bSAxel Dörfler 
294f28dd36bSAxel Dörfler class Read : public AbstractTraceEntry {
295f28dd36bSAxel Dörfler public:
296748c0f30SAxel Dörfler 	Read(const BReference<Port>& portRef, int32 code, ssize_t result)
297748c0f30SAxel Dörfler 		:
298748c0f30SAxel Dörfler 		fID(portRef->id),
299748c0f30SAxel Dörfler 		fReadCount(portRef->read_count),
300748c0f30SAxel Dörfler 		fWriteCount(portRef->write_count),
301748c0f30SAxel Dörfler 		fCode(code),
302748c0f30SAxel Dörfler 		fResult(result)
303748c0f30SAxel Dörfler 	{
304748c0f30SAxel Dörfler 		Initialized();
305748c0f30SAxel Dörfler 	}
306748c0f30SAxel Dörfler 
30724df6592SIngo Weinhold 	Read(port_id id, int32 readCount, int32 writeCount, int32 code,
30824df6592SIngo Weinhold 		ssize_t result)
309f28dd36bSAxel Dörfler 		:
31024df6592SIngo Weinhold 		fID(id),
31124df6592SIngo Weinhold 		fReadCount(readCount),
31224df6592SIngo Weinhold 		fWriteCount(writeCount),
313f28dd36bSAxel Dörfler 		fCode(code),
314f28dd36bSAxel Dörfler 		fResult(result)
315f28dd36bSAxel Dörfler 	{
316f28dd36bSAxel Dörfler 		Initialized();
317f28dd36bSAxel Dörfler 	}
318f28dd36bSAxel Dörfler 
319f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
320f28dd36bSAxel Dörfler 	{
321f28dd36bSAxel Dörfler 		out.Print("port %ld read, read %ld, write %ld, code %lx: %ld",
322f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fResult);
323f28dd36bSAxel Dörfler 	}
324f28dd36bSAxel Dörfler 
325f28dd36bSAxel Dörfler private:
326f28dd36bSAxel Dörfler 	port_id				fID;
327f28dd36bSAxel Dörfler 	int32				fReadCount;
328f28dd36bSAxel Dörfler 	int32				fWriteCount;
329f28dd36bSAxel Dörfler 	int32				fCode;
330f28dd36bSAxel Dörfler 	ssize_t				fResult;
331f28dd36bSAxel Dörfler };
332f28dd36bSAxel Dörfler 
333f28dd36bSAxel Dörfler 
334f28dd36bSAxel Dörfler class Write : public AbstractTraceEntry {
335f28dd36bSAxel Dörfler public:
33624df6592SIngo Weinhold 	Write(port_id id, int32 readCount, int32 writeCount, int32 code,
33724df6592SIngo Weinhold 		size_t bufferSize, ssize_t result)
338f28dd36bSAxel Dörfler 		:
33924df6592SIngo Weinhold 		fID(id),
34024df6592SIngo Weinhold 		fReadCount(readCount),
34124df6592SIngo Weinhold 		fWriteCount(writeCount),
342f28dd36bSAxel Dörfler 		fCode(code),
343f28dd36bSAxel Dörfler 		fBufferSize(bufferSize),
344f28dd36bSAxel Dörfler 		fResult(result)
345f28dd36bSAxel Dörfler 	{
346f28dd36bSAxel Dörfler 		Initialized();
347f28dd36bSAxel Dörfler 	}
348f28dd36bSAxel Dörfler 
349f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
350f28dd36bSAxel Dörfler 	{
351f28dd36bSAxel Dörfler 		out.Print("port %ld write, read %ld, write %ld, code %lx, size %ld: %ld",
352f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fBufferSize, fResult);
353f28dd36bSAxel Dörfler 	}
354f28dd36bSAxel Dörfler 
355f28dd36bSAxel Dörfler private:
356f28dd36bSAxel Dörfler 	port_id				fID;
357f28dd36bSAxel Dörfler 	int32				fReadCount;
358f28dd36bSAxel Dörfler 	int32				fWriteCount;
359f28dd36bSAxel Dörfler 	int32				fCode;
360f28dd36bSAxel Dörfler 	size_t				fBufferSize;
361f28dd36bSAxel Dörfler 	ssize_t				fResult;
362f28dd36bSAxel Dörfler };
363f28dd36bSAxel Dörfler 
364f28dd36bSAxel Dörfler 
365f28dd36bSAxel Dörfler class Info : public AbstractTraceEntry {
366f28dd36bSAxel Dörfler public:
367748c0f30SAxel Dörfler 	Info(const BReference<Port>& portRef, int32 code, ssize_t result)
368748c0f30SAxel Dörfler 		:
369748c0f30SAxel Dörfler 		fID(portRef->id),
370748c0f30SAxel Dörfler 		fReadCount(portRef->read_count),
371748c0f30SAxel Dörfler 		fWriteCount(portRef->write_count),
372748c0f30SAxel Dörfler 		fCode(code),
373748c0f30SAxel Dörfler 		fResult(result)
374748c0f30SAxel Dörfler 	{
375748c0f30SAxel Dörfler 		Initialized();
376748c0f30SAxel Dörfler 	}
377748c0f30SAxel Dörfler 
37824df6592SIngo Weinhold 	Info(port_id id, int32 readCount, int32 writeCount, int32 code,
37924df6592SIngo Weinhold 		ssize_t result)
380f28dd36bSAxel Dörfler 		:
38124df6592SIngo Weinhold 		fID(id),
38224df6592SIngo Weinhold 		fReadCount(readCount),
38324df6592SIngo Weinhold 		fWriteCount(writeCount),
384f28dd36bSAxel Dörfler 		fCode(code),
385f28dd36bSAxel Dörfler 		fResult(result)
386f28dd36bSAxel Dörfler 	{
387f28dd36bSAxel Dörfler 		Initialized();
388f28dd36bSAxel Dörfler 	}
389f28dd36bSAxel Dörfler 
390f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
391f28dd36bSAxel Dörfler 	{
392f28dd36bSAxel Dörfler 		out.Print("port %ld info, read %ld, write %ld, code %lx: %ld",
393f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fResult);
394f28dd36bSAxel Dörfler 	}
395f28dd36bSAxel Dörfler 
396f28dd36bSAxel Dörfler private:
397f28dd36bSAxel Dörfler 	port_id				fID;
398f28dd36bSAxel Dörfler 	int32				fReadCount;
399f28dd36bSAxel Dörfler 	int32				fWriteCount;
400f28dd36bSAxel Dörfler 	int32				fCode;
401f28dd36bSAxel Dörfler 	ssize_t				fResult;
402f28dd36bSAxel Dörfler };
403f28dd36bSAxel Dörfler 
404f28dd36bSAxel Dörfler 
405f28dd36bSAxel Dörfler class OwnerChange : public AbstractTraceEntry {
406f28dd36bSAxel Dörfler public:
40724df6592SIngo Weinhold 	OwnerChange(Port* port, team_id newOwner, status_t status)
408f28dd36bSAxel Dörfler 		:
40924df6592SIngo Weinhold 		fID(port->id),
41024df6592SIngo Weinhold 		fOldOwner(port->owner),
411f28dd36bSAxel Dörfler 		fNewOwner(newOwner),
412f28dd36bSAxel Dörfler 		fStatus(status)
413f28dd36bSAxel Dörfler 	{
414f28dd36bSAxel Dörfler 		Initialized();
415f28dd36bSAxel Dörfler 	}
416f28dd36bSAxel Dörfler 
417f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
418f28dd36bSAxel Dörfler 	{
419f28dd36bSAxel Dörfler 		out.Print("port %ld owner change from %ld to %ld: %s", fID, fOldOwner,
420f28dd36bSAxel Dörfler 			fNewOwner, strerror(fStatus));
421f28dd36bSAxel Dörfler 	}
422f28dd36bSAxel Dörfler 
423f28dd36bSAxel Dörfler private:
424f28dd36bSAxel Dörfler 	port_id				fID;
425f28dd36bSAxel Dörfler 	team_id				fOldOwner;
426f28dd36bSAxel Dörfler 	team_id				fNewOwner;
427f28dd36bSAxel Dörfler 	status_t	 		fStatus;
428f28dd36bSAxel Dörfler };
429f28dd36bSAxel Dörfler 
430f28dd36bSAxel Dörfler }	// namespace PortTracing
431f28dd36bSAxel Dörfler 
432f28dd36bSAxel Dörfler #	define T(x) new(std::nothrow) PortTracing::x;
433f28dd36bSAxel Dörfler #else
434f28dd36bSAxel Dörfler #	define T(x) ;
435f28dd36bSAxel Dörfler #endif
436f28dd36bSAxel Dörfler 
437f28dd36bSAxel Dörfler 
438e8885f20SAxel Dörfler static const size_t kInitialPortBufferSize = 4 * 1024 * 1024;
439f28dd36bSAxel Dörfler static const size_t kTotalSpaceLimit = 64 * 1024 * 1024;
440f28dd36bSAxel Dörfler static const size_t kTeamSpaceLimit = 8 * 1024 * 1024;
441f28dd36bSAxel Dörfler static const size_t kBufferGrowRate = kInitialPortBufferSize;
442f28dd36bSAxel Dörfler 
443224aee3fSIngo Weinhold #define MAX_QUEUE_LENGTH 4096
4445f87692cSIngo Weinhold #define PORT_MAX_MESSAGE_SIZE (256 * 1024)
445224aee3fSIngo Weinhold 
446224aee3fSIngo Weinhold static int32 sMaxPorts = 4096;
447d0f2d828SPawel Dziepak static int32 sUsedPorts;
448224aee3fSIngo Weinhold 
44924df6592SIngo Weinhold static PortHashTable sPorts;
4507f64b301SJulian Harnath static PortNameHashTable sPortsByName;
451f28dd36bSAxel Dörfler static ConditionVariable sNoSpaceCondition;
452d0f2d828SPawel Dziepak static int32 sTotalSpaceCommited;
453cd3e02caSMichael Lotz static int32 sWaitingForSpace;
45424df6592SIngo Weinhold static port_id sNextPortID = 1;
455224aee3fSIngo Weinhold static bool sPortsActive = false;
4567f64b301SJulian Harnath static rw_lock sPortsLock = RW_LOCK_INITIALIZER("ports list");
4577f64b301SJulian Harnath 
4587f64b301SJulian Harnath enum {
4597f64b301SJulian Harnath 	kTeamListLockCount = 8
4607f64b301SJulian Harnath };
4617f64b301SJulian Harnath 
4627f64b301SJulian Harnath static mutex sTeamListLock[kTeamListLockCount] = {
4637f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 1"),
4647f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 2"),
4657f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 3"),
4667f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 4"),
4677f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 5"),
4687f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 6"),
4697f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 7"),
4707f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 8")
4717f64b301SJulian Harnath };
472224aee3fSIngo Weinhold 
47351755cf8SAxel Dörfler static PortNotificationService sNotificationService;
47451755cf8SAxel Dörfler 
475224aee3fSIngo Weinhold 
47651755cf8SAxel Dörfler //	#pragma mark - TeamNotificationService
47751755cf8SAxel Dörfler 
47851755cf8SAxel Dörfler 
47951755cf8SAxel Dörfler PortNotificationService::PortNotificationService()
480e8885f20SAxel Dörfler 	:
481e8885f20SAxel Dörfler 	DefaultNotificationService("ports")
48251755cf8SAxel Dörfler {
48351755cf8SAxel Dörfler }
48451755cf8SAxel Dörfler 
48551755cf8SAxel Dörfler 
48651755cf8SAxel Dörfler void
48751755cf8SAxel Dörfler PortNotificationService::Notify(uint32 opcode, port_id port)
48851755cf8SAxel Dörfler {
489fae2ce19SIngo Weinhold 	char eventBuffer[128];
49051755cf8SAxel Dörfler 	KMessage event;
49151755cf8SAxel Dörfler 	event.SetTo(eventBuffer, sizeof(eventBuffer), PORT_MONITOR);
492efd536ffSIngo Weinhold 	event.AddInt32("event", opcode);
49351755cf8SAxel Dörfler 	event.AddInt32("port", port);
49451755cf8SAxel Dörfler 
495efd536ffSIngo Weinhold 	DefaultNotificationService::Notify(event, opcode);
49651755cf8SAxel Dörfler }
49751755cf8SAxel Dörfler 
49851755cf8SAxel Dörfler 
4997f64b301SJulian Harnath //	#pragma mark - debugger commands
50051755cf8SAxel Dörfler 
50151755cf8SAxel Dörfler 
502224aee3fSIngo Weinhold static int
503224aee3fSIngo Weinhold dump_port_list(int argc, char** argv)
504224aee3fSIngo Weinhold {
505224aee3fSIngo Weinhold 	const char* name = NULL;
506224aee3fSIngo Weinhold 	team_id owner = -1;
507224aee3fSIngo Weinhold 
508224aee3fSIngo Weinhold 	if (argc > 2) {
509224aee3fSIngo Weinhold 		if (!strcmp(argv[1], "team") || !strcmp(argv[1], "owner"))
510224aee3fSIngo Weinhold 			owner = strtoul(argv[2], NULL, 0);
511224aee3fSIngo Weinhold 		else if (!strcmp(argv[1], "name"))
512224aee3fSIngo Weinhold 			name = argv[2];
513224aee3fSIngo Weinhold 	} else if (argc > 1)
514224aee3fSIngo Weinhold 		owner = strtoul(argv[1], NULL, 0);
515224aee3fSIngo Weinhold 
516e8885f20SAxel Dörfler 	kprintf("port             id  cap  read-cnt  write-cnt   total   team  "
517e8885f20SAxel Dörfler 		"name\n");
518224aee3fSIngo Weinhold 
51924df6592SIngo Weinhold 	for (PortHashTable::Iterator it = sPorts.GetIterator();
52024df6592SIngo Weinhold 		Port* port = it.Next();) {
52124df6592SIngo Weinhold 		if ((owner != -1 && port->owner != owner)
522e8885f20SAxel Dörfler 			|| (name != NULL && strstr(port->lock.name, name) == NULL))
523224aee3fSIngo Weinhold 			continue;
524224aee3fSIngo Weinhold 
5250e88a887SAlex Smith 		kprintf("%p %8" B_PRId32 " %4" B_PRId32 " %9" B_PRIu32 " %9" B_PRId32
5260e88a887SAlex Smith 			" %8" B_PRId32 " %6" B_PRId32 "  %s\n", port, port->id,
5270e88a887SAlex Smith 			port->capacity, port->read_count, port->write_count,
528e8885f20SAxel Dörfler 			port->total_count, port->owner, port->lock.name);
529224aee3fSIngo Weinhold 	}
530e8885f20SAxel Dörfler 
531224aee3fSIngo Weinhold 	return 0;
532224aee3fSIngo Weinhold }
533224aee3fSIngo Weinhold 
534224aee3fSIngo Weinhold 
535224aee3fSIngo Weinhold static void
53624df6592SIngo Weinhold _dump_port_info(Port* port)
537224aee3fSIngo Weinhold {
538224aee3fSIngo Weinhold 	kprintf("PORT: %p\n", port);
5390e88a887SAlex Smith 	kprintf(" id:              %" B_PRId32 "\n", port->id);
540e8885f20SAxel Dörfler 	kprintf(" name:            \"%s\"\n", port->lock.name);
5410e88a887SAlex Smith 	kprintf(" owner:           %" B_PRId32 "\n", port->owner);
5420e88a887SAlex Smith 	kprintf(" capacity:        %" B_PRId32 "\n", port->capacity);
5430e88a887SAlex Smith 	kprintf(" read_count:      %" B_PRIu32 "\n", port->read_count);
5440e88a887SAlex Smith 	kprintf(" write_count:     %" B_PRId32 "\n", port->write_count);
5450e88a887SAlex Smith 	kprintf(" total count:     %" B_PRId32 "\n", port->total_count);
5465aee691eSIngo Weinhold 
547f28dd36bSAxel Dörfler 	if (!port->messages.IsEmpty()) {
548f28dd36bSAxel Dörfler 		kprintf("messages:\n");
549f28dd36bSAxel Dörfler 
550f28dd36bSAxel Dörfler 		MessageList::Iterator iterator = port->messages.GetIterator();
551f28dd36bSAxel Dörfler 		while (port_message* message = iterator.Next()) {
5520e88a887SAlex Smith 			kprintf(" %p  %08" B_PRIx32 "  %ld\n", message, message->code, message->size);
553f28dd36bSAxel Dörfler 		}
554f28dd36bSAxel Dörfler 	}
555f28dd36bSAxel Dörfler 
5565aee691eSIngo Weinhold 	set_debug_variable("_port", (addr_t)port);
5575aee691eSIngo Weinhold 	set_debug_variable("_portID", port->id);
5585aee691eSIngo Weinhold 	set_debug_variable("_owner", port->owner);
559224aee3fSIngo Weinhold }
560224aee3fSIngo Weinhold 
561224aee3fSIngo Weinhold 
562224aee3fSIngo Weinhold static int
563224aee3fSIngo Weinhold dump_port_info(int argc, char** argv)
564224aee3fSIngo Weinhold {
565e8885f20SAxel Dörfler 	ConditionVariable* condition = NULL;
566f28dd36bSAxel Dörfler 	const char* name = NULL;
567224aee3fSIngo Weinhold 
568224aee3fSIngo Weinhold 	if (argc < 2) {
569ce637fdaSIngo Weinhold 		print_debugger_command_usage(argv[0]);
570224aee3fSIngo Weinhold 		return 0;
571224aee3fSIngo Weinhold 	}
572224aee3fSIngo Weinhold 
573224aee3fSIngo Weinhold 	if (argc > 2) {
574224aee3fSIngo Weinhold 		if (!strcmp(argv[1], "address")) {
57524df6592SIngo Weinhold 			_dump_port_info((Port*)parse_expression(argv[2]));
576224aee3fSIngo Weinhold 			return 0;
577e8885f20SAxel Dörfler 		} else if (!strcmp(argv[1], "condition"))
578f28dd36bSAxel Dörfler 			condition = (ConditionVariable*)parse_expression(argv[2]);
579224aee3fSIngo Weinhold 		else if (!strcmp(argv[1], "name"))
580224aee3fSIngo Weinhold 			name = argv[2];
581f28dd36bSAxel Dörfler 	} else if (parse_expression(argv[1]) > 0) {
582224aee3fSIngo Weinhold 		// if the argument looks like a number, treat it as such
583f28dd36bSAxel Dörfler 		int32 num = parse_expression(argv[1]);
58424df6592SIngo Weinhold 		Port* port = sPorts.Lookup(num);
5857f64b301SJulian Harnath 		if (port == NULL || port->state != Port::kActive) {
5860e88a887SAlex Smith 			kprintf("port %" B_PRId32 " (%#" B_PRIx32 ") doesn't exist!\n",
5870e88a887SAlex Smith 				num, num);
588224aee3fSIngo Weinhold 			return 0;
589224aee3fSIngo Weinhold 		}
59024df6592SIngo Weinhold 		_dump_port_info(port);
591224aee3fSIngo Weinhold 		return 0;
592224aee3fSIngo Weinhold 	} else
593224aee3fSIngo Weinhold 		name = argv[1];
594224aee3fSIngo Weinhold 
595224aee3fSIngo Weinhold 	// walk through the ports list, trying to match name
59624df6592SIngo Weinhold 	for (PortHashTable::Iterator it = sPorts.GetIterator();
59724df6592SIngo Weinhold 		Port* port = it.Next();) {
59824df6592SIngo Weinhold 		if ((name != NULL && port->lock.name != NULL
59924df6592SIngo Weinhold 				&& !strcmp(name, port->lock.name))
60024df6592SIngo Weinhold 			|| (condition != NULL && (&port->read_condition == condition
60124df6592SIngo Weinhold 				|| &port->write_condition == condition))) {
60224df6592SIngo Weinhold 			_dump_port_info(port);
603224aee3fSIngo Weinhold 			return 0;
604224aee3fSIngo Weinhold 		}
605224aee3fSIngo Weinhold 	}
606224aee3fSIngo Weinhold 
607224aee3fSIngo Weinhold 	return 0;
608224aee3fSIngo Weinhold }
609224aee3fSIngo Weinhold 
610224aee3fSIngo Weinhold 
6117f64b301SJulian Harnath // #pragma mark - internal helper functions
6127f64b301SJulian Harnath 
6137f64b301SJulian Harnath 
61424df6592SIngo Weinhold /*!	Notifies the port's select events.
61524df6592SIngo Weinhold 	The port must be locked.
61624df6592SIngo Weinhold */
617224aee3fSIngo Weinhold static void
61824df6592SIngo Weinhold notify_port_select_events(Port* port, uint16 events)
619224aee3fSIngo Weinhold {
62024df6592SIngo Weinhold 	if (port->select_infos)
62124df6592SIngo Weinhold 		notify_select_events_list(port->select_infos, events);
622224aee3fSIngo Weinhold }
623224aee3fSIngo Weinhold 
624224aee3fSIngo Weinhold 
6257f64b301SJulian Harnath static BReference<Port>
6267f64b301SJulian Harnath get_locked_port(port_id id) GCC_2_NRV(portRef)
627cd3e02caSMichael Lotz {
6287f64b301SJulian Harnath #if __GNUC__ >= 3
6297f64b301SJulian Harnath 	BReference<Port> portRef;
6307f64b301SJulian Harnath #endif
6317f64b301SJulian Harnath 	{
6327f64b301SJulian Harnath 		ReadLocker portsLocker(sPortsLock);
6337f64b301SJulian Harnath 		portRef.SetTo(sPorts.Lookup(id));
6347f64b301SJulian Harnath 	}
635cd3e02caSMichael Lotz 
636*057719efSAugustin Cavalier 	if (portRef != NULL && portRef->state == Port::kActive) {
637*057719efSAugustin Cavalier 		if (mutex_lock(&portRef->lock) != B_OK)
638*057719efSAugustin Cavalier 			portRef.Unset();
639*057719efSAugustin Cavalier 	} else
6407f64b301SJulian Harnath 		portRef.Unset();
6417f64b301SJulian Harnath 
6427f64b301SJulian Harnath 	return portRef;
6437f64b301SJulian Harnath }
6447f64b301SJulian Harnath 
6457f64b301SJulian Harnath 
6467f64b301SJulian Harnath static BReference<Port>
6477f64b301SJulian Harnath get_port(port_id id) GCC_2_NRV(portRef)
6487f64b301SJulian Harnath {
6497f64b301SJulian Harnath #if __GNUC__ >= 3
6507f64b301SJulian Harnath 	BReference<Port> portRef;
6517f64b301SJulian Harnath #endif
6527f64b301SJulian Harnath 	ReadLocker portsLocker(sPortsLock);
6537f64b301SJulian Harnath 	portRef.SetTo(sPorts.Lookup(id));
6547f64b301SJulian Harnath 
6557f64b301SJulian Harnath 	return portRef;
656cd3e02caSMichael Lotz }
657cd3e02caSMichael Lotz 
658cd3e02caSMichael Lotz 
659cd3e02caSMichael Lotz /*!	You need to own the port's lock when calling this function */
660cd3e02caSMichael Lotz static inline bool
661cd3e02caSMichael Lotz is_port_closed(Port* port)
662cd3e02caSMichael Lotz {
663cd3e02caSMichael Lotz 	return port->capacity == 0;
664cd3e02caSMichael Lotz }
665cd3e02caSMichael Lotz 
666cd3e02caSMichael Lotz 
667224aee3fSIngo Weinhold static void
668e8885f20SAxel Dörfler put_port_message(port_message* message)
669224aee3fSIngo Weinhold {
6707f64b301SJulian Harnath 	const size_t size = sizeof(port_message) + message->size;
6717f64b301SJulian Harnath 	free(message);
672f28dd36bSAxel Dörfler 
6737f64b301SJulian Harnath 	atomic_add(&sTotalSpaceCommited, -size);
674cd3e02caSMichael Lotz 	if (sWaitingForSpace > 0)
675f28dd36bSAxel Dörfler 		sNoSpaceCondition.NotifyAll();
676224aee3fSIngo Weinhold }
677224aee3fSIngo Weinhold 
678224aee3fSIngo Weinhold 
6797f64b301SJulian Harnath /*! Port must be locked. */
680f28dd36bSAxel Dörfler static status_t
681f28dd36bSAxel Dörfler get_port_message(int32 code, size_t bufferSize, uint32 flags, bigtime_t timeout,
682cd3e02caSMichael Lotz 	port_message** _message, Port& port)
683224aee3fSIngo Weinhold {
6847f64b301SJulian Harnath 	const size_t size = sizeof(port_message) + bufferSize;
685f28dd36bSAxel Dörfler 
686f28dd36bSAxel Dörfler 	while (true) {
6877f64b301SJulian Harnath 		int32 previouslyCommited = atomic_add(&sTotalSpaceCommited, size);
6887f64b301SJulian Harnath 
6897f64b301SJulian Harnath 		while (previouslyCommited + size > kTotalSpaceLimit) {
690f28dd36bSAxel Dörfler 			// TODO: add per team limit
6917f64b301SJulian Harnath 
6927f64b301SJulian Harnath 			// We are not allowed to allocate more memory, as our
693f28dd36bSAxel Dörfler 			// space limit has been reached - just wait until we get
694f28dd36bSAxel Dörfler 			// some free space again.
695f28dd36bSAxel Dörfler 
6967f64b301SJulian Harnath 			atomic_add(&sTotalSpaceCommited, -size);
6977f64b301SJulian Harnath 
698f28dd36bSAxel Dörfler 			// TODO: we don't want to wait - but does that also mean we
6997f64b301SJulian Harnath 			// shouldn't wait for free memory?
700cd3e02caSMichael Lotz 			if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
701f28dd36bSAxel Dörfler 				return B_WOULD_BLOCK;
702f28dd36bSAxel Dörfler 
703f28dd36bSAxel Dörfler 			ConditionVariableEntry entry;
704f28dd36bSAxel Dörfler 			sNoSpaceCondition.Add(&entry);
705f28dd36bSAxel Dörfler 
706cd3e02caSMichael Lotz 			port_id portID = port.id;
707cd3e02caSMichael Lotz 			mutex_unlock(&port.lock);
708f28dd36bSAxel Dörfler 
7097f64b301SJulian Harnath 			atomic_add(&sWaitingForSpace, 1);
7107f64b301SJulian Harnath 
7117f64b301SJulian Harnath 			// TODO: right here the condition could be notified and we'd
7127f64b301SJulian Harnath 			//       miss it.
7137f64b301SJulian Harnath 
714f28dd36bSAxel Dörfler 			status_t status = entry.Wait(flags, timeout);
715cd3e02caSMichael Lotz 
7167f64b301SJulian Harnath 			atomic_add(&sWaitingForSpace, -1);
717cd3e02caSMichael Lotz 
7187f64b301SJulian Harnath 			// re-lock the port
7197f64b301SJulian Harnath 			BReference<Port> newPortRef = get_locked_port(portID);
7207f64b301SJulian Harnath 
7217f64b301SJulian Harnath 			if (newPortRef.Get() != &port || is_port_closed(&port)) {
722cd3e02caSMichael Lotz 				// the port is no longer usable
723cd3e02caSMichael Lotz 				return B_BAD_PORT_ID;
724cd3e02caSMichael Lotz 			}
725cd3e02caSMichael Lotz 
726f28dd36bSAxel Dörfler 			if (status == B_TIMED_OUT)
727f28dd36bSAxel Dörfler 				return B_TIMED_OUT;
728f28dd36bSAxel Dörfler 
7297f64b301SJulian Harnath 			previouslyCommited = atomic_add(&sTotalSpaceCommited, size);
730f28dd36bSAxel Dörfler 			continue;
731224aee3fSIngo Weinhold 		}
732224aee3fSIngo Weinhold 
733f28dd36bSAxel Dörfler 		// Quota is fulfilled, try to allocate the buffer
7347f64b301SJulian Harnath 		port_message* message = (port_message*)malloc(size);
735f28dd36bSAxel Dörfler 		if (message != NULL) {
736e8885f20SAxel Dörfler 			message->code = code;
737e8885f20SAxel Dörfler 			message->size = bufferSize;
738e8885f20SAxel Dörfler 
739f28dd36bSAxel Dörfler 			*_message = message;
740f28dd36bSAxel Dörfler 			return B_OK;
741f28dd36bSAxel Dörfler 		}
742f28dd36bSAxel Dörfler 
7437f64b301SJulian Harnath 		// We weren't able to allocate and we'll start over,so we remove our
7447f64b301SJulian Harnath 		// size from the commited-counter again.
7457f64b301SJulian Harnath 		atomic_add(&sTotalSpaceCommited, -size);
746f28dd36bSAxel Dörfler 		continue;
747f28dd36bSAxel Dörfler 	}
748224aee3fSIngo Weinhold }
749224aee3fSIngo Weinhold 
750224aee3fSIngo Weinhold 
751224aee3fSIngo Weinhold /*!	Fills the port_info structure with information from the specified
752224aee3fSIngo Weinhold 	port.
75324df6592SIngo Weinhold 	The port's lock must be held when called.
754224aee3fSIngo Weinhold */
755224aee3fSIngo Weinhold static void
75624df6592SIngo Weinhold fill_port_info(Port* port, port_info* info, size_t size)
757224aee3fSIngo Weinhold {
758224aee3fSIngo Weinhold 	info->port = port->id;
759224aee3fSIngo Weinhold 	info->team = port->owner;
760224aee3fSIngo Weinhold 	info->capacity = port->capacity;
761224aee3fSIngo Weinhold 
7627d592ec4SAxel Dörfler 	info->queue_count = port->read_count;
763224aee3fSIngo Weinhold 	info->total_count = port->total_count;
764224aee3fSIngo Weinhold 
765e8885f20SAxel Dörfler 	strlcpy(info->name, port->lock.name, B_OS_NAME_LENGTH);
766e8885f20SAxel Dörfler }
767e8885f20SAxel Dörfler 
768e8885f20SAxel Dörfler 
769e8885f20SAxel Dörfler static ssize_t
770e8885f20SAxel Dörfler copy_port_message(port_message* message, int32* _code, void* buffer,
771e8885f20SAxel Dörfler 	size_t bufferSize, bool userCopy)
772e8885f20SAxel Dörfler {
773e8885f20SAxel Dörfler 	// check output buffer size
774748c0f30SAxel Dörfler 	size_t size = std::min(bufferSize, message->size);
775e8885f20SAxel Dörfler 
776e8885f20SAxel Dörfler 	// copy message
777e8885f20SAxel Dörfler 	if (_code != NULL)
778e8885f20SAxel Dörfler 		*_code = message->code;
779e8885f20SAxel Dörfler 
780e8885f20SAxel Dörfler 	if (size > 0) {
781e8885f20SAxel Dörfler 		if (userCopy) {
782e8885f20SAxel Dörfler 			status_t status = user_memcpy(buffer, message->buffer, size);
783e8885f20SAxel Dörfler 			if (status != B_OK)
784e8885f20SAxel Dörfler 				return status;
785e8885f20SAxel Dörfler 		} else
786e8885f20SAxel Dörfler 			memcpy(buffer, message->buffer, size);
787e8885f20SAxel Dörfler 	}
788e8885f20SAxel Dörfler 
789e8885f20SAxel Dörfler 	return size;
790224aee3fSIngo Weinhold }
791224aee3fSIngo Weinhold 
792224aee3fSIngo Weinhold 
79386a999adSAxel Dörfler static void
7947f64b301SJulian Harnath uninit_port(Port* port)
79586a999adSAxel Dörfler {
7967f64b301SJulian Harnath 	MutexLocker locker(port->lock);
7977f64b301SJulian Harnath 
79824df6592SIngo Weinhold 	notify_port_select_events(port, B_EVENT_INVALID);
79924df6592SIngo Weinhold 	port->select_infos = NULL;
80086a999adSAxel Dörfler 
80186a999adSAxel Dörfler 	// Release the threads that were blocking on this port.
80286a999adSAxel Dörfler 	// read_port() will see the B_BAD_PORT_ID return value, and act accordingly
80303fb2d88SPawel Dziepak 	port->read_condition.NotifyAll(B_BAD_PORT_ID);
80403fb2d88SPawel Dziepak 	port->write_condition.NotifyAll(B_BAD_PORT_ID);
80524df6592SIngo Weinhold 	sNotificationService.Notify(PORT_REMOVED, port->id);
80624df6592SIngo Weinhold }
80724df6592SIngo Weinhold 
80824df6592SIngo Weinhold 
8097f64b301SJulian Harnath /*! Caller must ensure there is still a reference to the port. (Either by
8107f64b301SJulian Harnath  *  holding a reference itself or by holding a lock on one of the data
8117f64b301SJulian Harnath  *  structures in which it is referenced.)
8127f64b301SJulian Harnath  */
8137f64b301SJulian Harnath static status_t
8147f64b301SJulian Harnath delete_port_logical(Port* port)
8157f64b301SJulian Harnath {
8167f64b301SJulian Harnath 	for (;;) {
8177f64b301SJulian Harnath 		// Try to logically delete
8187f64b301SJulian Harnath 		const int32 oldState = atomic_test_and_set(&port->state,
8197f64b301SJulian Harnath 			Port::kDeleted, Port::kActive);
8207f64b301SJulian Harnath 			// Linearization point for port deletion
8217f64b301SJulian Harnath 
8227f64b301SJulian Harnath 		switch (oldState) {
8237f64b301SJulian Harnath 			case Port::kActive:
8247f64b301SJulian Harnath 				// Logical deletion succesful
8257f64b301SJulian Harnath 				return B_OK;
8267f64b301SJulian Harnath 
8277f64b301SJulian Harnath 			case Port::kDeleted:
8287f64b301SJulian Harnath 				// Someone else already deleted it in the meantime
8297f64b301SJulian Harnath 				TRACE(("delete_port_logical: already deleted port_id %ld\n",
8307f64b301SJulian Harnath 						port->id));
8317f64b301SJulian Harnath 				return B_BAD_PORT_ID;
8327f64b301SJulian Harnath 
8337f64b301SJulian Harnath 			case Port::kUnused:
8347f64b301SJulian Harnath 				// Port is still being created, retry
8357f64b301SJulian Harnath 				continue;
8367f64b301SJulian Harnath 
8377f64b301SJulian Harnath 			default:
8387f64b301SJulian Harnath 				// Port state got corrupted somehow
8397f64b301SJulian Harnath 				panic("Invalid port state!\n");
8407f64b301SJulian Harnath 		}
8417f64b301SJulian Harnath 	}
8427f64b301SJulian Harnath }
8437f64b301SJulian Harnath 
8447f64b301SJulian Harnath 
845224aee3fSIngo Weinhold //	#pragma mark - private kernel API
846224aee3fSIngo Weinhold 
847224aee3fSIngo Weinhold 
84824df6592SIngo Weinhold /*! This function deletes all the ports that are owned by the passed team.
849224aee3fSIngo Weinhold */
85086a999adSAxel Dörfler void
8514535495dSIngo Weinhold delete_owned_ports(Team* team)
852224aee3fSIngo Weinhold {
85386a999adSAxel Dörfler 	TRACE(("delete_owned_ports(owner = %ld)\n", team->id));
854224aee3fSIngo Weinhold 
8557f64b301SJulian Harnath 	list deletionList;
8567f64b301SJulian Harnath 	list_init_etc(&deletionList, port_team_link_offset());
85724df6592SIngo Weinhold 
8587f64b301SJulian Harnath 	const uint8 lockIndex = team->id % kTeamListLockCount;
8597f64b301SJulian Harnath 	MutexLocker teamPortsListLocker(sTeamListLock[lockIndex]);
860224aee3fSIngo Weinhold 
8617f64b301SJulian Harnath 	// Try to logically delete all ports from the team's port list.
8627f64b301SJulian Harnath 	// On success, move the port to deletionList.
8637f64b301SJulian Harnath 	Port* port = (Port*)list_get_first_item(&team->port_list);
86424df6592SIngo Weinhold 	while (port != NULL) {
8657f64b301SJulian Harnath 		status_t status = delete_port_logical(port);
8667f64b301SJulian Harnath 			// Contains linearization point
86724df6592SIngo Weinhold 
8687f64b301SJulian Harnath 		Port* nextPort = (Port*)list_get_next_item(&team->port_list, port);
8697f64b301SJulian Harnath 
8707f64b301SJulian Harnath 		if (status == B_OK) {
8717f64b301SJulian Harnath 			list_remove_link(&port->team_link);
8727f64b301SJulian Harnath 			list_add_item(&deletionList, port);
87386a999adSAxel Dörfler 		}
8748cd9a524SAxel Dörfler 
8757f64b301SJulian Harnath 		port = nextPort;
8767f64b301SJulian Harnath 	}
8778cd9a524SAxel Dörfler 
8787f64b301SJulian Harnath 	teamPortsListLocker.Unlock();
8797f64b301SJulian Harnath 
8807f64b301SJulian Harnath 	// Remove all ports in deletionList from hashes
8817f64b301SJulian Harnath 	{
8827f64b301SJulian Harnath 		WriteLocker portsLocker(sPortsLock);
8837f64b301SJulian Harnath 
8847f64b301SJulian Harnath 		for (Port* port = (Port*)list_get_first_item(&deletionList);
8857f64b301SJulian Harnath 			 port != NULL;
8867f64b301SJulian Harnath 			 port = (Port*)list_get_next_item(&deletionList, port)) {
8877f64b301SJulian Harnath 
8887f64b301SJulian Harnath 			sPorts.Remove(port);
8897f64b301SJulian Harnath 			sPortsByName.Remove(port);
8907f64b301SJulian Harnath 			port->ReleaseReference();
8917f64b301SJulian Harnath 				// joint reference for sPorts and sPortsByName
8927f64b301SJulian Harnath 		}
8937f64b301SJulian Harnath 	}
8947f64b301SJulian Harnath 
8957f64b301SJulian Harnath 	// Uninitialize ports and release team port list references
8967f64b301SJulian Harnath 	while (Port* port = (Port*)list_remove_head_item(&deletionList)) {
8977f64b301SJulian Harnath 		atomic_add(&sUsedPorts, -1);
8987f64b301SJulian Harnath 		uninit_port(port);
8997f64b301SJulian Harnath 		port->ReleaseReference();
9007f64b301SJulian Harnath 			// Reference for team port list
9017f64b301SJulian Harnath 	}
902224aee3fSIngo Weinhold }
903224aee3fSIngo Weinhold 
904224aee3fSIngo Weinhold 
905224aee3fSIngo Weinhold int32
906224aee3fSIngo Weinhold port_max_ports(void)
907224aee3fSIngo Weinhold {
908224aee3fSIngo Weinhold 	return sMaxPorts;
909224aee3fSIngo Weinhold }
910224aee3fSIngo Weinhold 
911224aee3fSIngo Weinhold 
912224aee3fSIngo Weinhold int32
913224aee3fSIngo Weinhold port_used_ports(void)
914224aee3fSIngo Weinhold {
915224aee3fSIngo Weinhold 	return sUsedPorts;
916224aee3fSIngo Weinhold }
917224aee3fSIngo Weinhold 
918224aee3fSIngo Weinhold 
9197f64b301SJulian Harnath size_t
9207f64b301SJulian Harnath port_team_link_offset()
9217f64b301SJulian Harnath {
9227f64b301SJulian Harnath 	// Somewhat ugly workaround since we cannot use offsetof() for a class
9237f64b301SJulian Harnath 	// with vtable (GCC4 throws a warning then).
9247f64b301SJulian Harnath 	Port* port = (Port*)0;
9257f64b301SJulian Harnath 	return (size_t)&port->team_link;
9267f64b301SJulian Harnath }
9277f64b301SJulian Harnath 
9287f64b301SJulian Harnath 
929224aee3fSIngo Weinhold status_t
930224aee3fSIngo Weinhold port_init(kernel_args *args)
931224aee3fSIngo Weinhold {
9327f64b301SJulian Harnath 	// initialize ports table and by-name hash
93324df6592SIngo Weinhold 	new(&sPorts) PortHashTable;
93424df6592SIngo Weinhold 	if (sPorts.Init() != B_OK) {
93524df6592SIngo Weinhold 		panic("Failed to init port hash table!");
93624df6592SIngo Weinhold 		return B_NO_MEMORY;
937e8885f20SAxel Dörfler 	}
938e8885f20SAxel Dörfler 
9397f64b301SJulian Harnath 	new(&sPortsByName) PortNameHashTable;
9407f64b301SJulian Harnath 	if (sPortsByName.Init() != B_OK) {
9417f64b301SJulian Harnath 		panic("Failed to init port by name hash table!");
942f28dd36bSAxel Dörfler 		return B_NO_MEMORY;
943f28dd36bSAxel Dörfler 	}
944f28dd36bSAxel Dörfler 
94524df6592SIngo Weinhold 	sNoSpaceCondition.Init(&sPorts, "port space");
946224aee3fSIngo Weinhold 
947224aee3fSIngo Weinhold 	// add debugger commands
948ce637fdaSIngo Weinhold 	add_debugger_command_etc("ports", &dump_port_list,
949ce637fdaSIngo Weinhold 		"Dump a list of all active ports (for team, with name, etc.)",
950ce637fdaSIngo Weinhold 		"[ ([ \"team\" | \"owner\" ] <team>) | (\"name\" <name>) ]\n"
951ce637fdaSIngo Weinhold 		"Prints a list of all active ports meeting the given\n"
952ce637fdaSIngo Weinhold 		"requirement. If no argument is given, all ports are listed.\n"
953ce637fdaSIngo Weinhold 		"  <team>             - The team owning the ports.\n"
954ce637fdaSIngo Weinhold 		"  <name>             - Part of the name of the ports.\n", 0);
955ce637fdaSIngo Weinhold 	add_debugger_command_etc("port", &dump_port_info,
956ce637fdaSIngo Weinhold 		"Dump info about a particular port",
957f28dd36bSAxel Dörfler 		"(<id> | [ \"address\" ] <address>) | ([ \"name\" ] <name>) "
958f28dd36bSAxel Dörfler 			"| (\"condition\" <address>)\n"
959ce637fdaSIngo Weinhold 		"Prints info about the specified port.\n"
960ce637fdaSIngo Weinhold 		"  <address>   - Pointer to the port structure.\n"
961ce637fdaSIngo Weinhold 		"  <name>      - Name of the port.\n"
962f28dd36bSAxel Dörfler 		"  <condition> - address of the port's read or write condition.\n", 0);
963224aee3fSIngo Weinhold 
96451755cf8SAxel Dörfler 	new(&sNotificationService) PortNotificationService();
965c24adb29SRene Gollent 	sNotificationService.Register();
966224aee3fSIngo Weinhold 	sPortsActive = true;
967224aee3fSIngo Weinhold 	return B_OK;
968224aee3fSIngo Weinhold }
969224aee3fSIngo Weinhold 
970224aee3fSIngo Weinhold 
971224aee3fSIngo Weinhold //	#pragma mark - public kernel API
972224aee3fSIngo Weinhold 
973224aee3fSIngo Weinhold 
974224aee3fSIngo Weinhold port_id
975224aee3fSIngo Weinhold create_port(int32 queueLength, const char* name)
976224aee3fSIngo Weinhold {
97751755cf8SAxel Dörfler 	TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength,
97851755cf8SAxel Dörfler 		name));
979224aee3fSIngo Weinhold 
980e8885f20SAxel Dörfler 	if (!sPortsActive) {
981e8885f20SAxel Dörfler 		panic("ports used too early!\n");
982224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
983e8885f20SAxel Dörfler 	}
984e8885f20SAxel Dörfler 	if (queueLength < 1 || queueLength > MAX_QUEUE_LENGTH)
985224aee3fSIngo Weinhold 		return B_BAD_VALUE;
986224aee3fSIngo Weinhold 
9874535495dSIngo Weinhold 	Team* team = thread_get_current_thread()->team;
98886a999adSAxel Dörfler 	if (team == NULL)
98986a999adSAxel Dörfler 		return B_BAD_TEAM_ID;
99086a999adSAxel Dörfler 
99124df6592SIngo Weinhold 	// create a port
99224df6592SIngo Weinhold 	Port* port = new(std::nothrow) Port(team_get_current_team_id(), queueLength,
9933c47c28aSAugustin Cavalier 		name != NULL ? name : "unnamed port");
9943c47c28aSAugustin Cavalier 	if (port == NULL)
99524df6592SIngo Weinhold 		return B_NO_MEMORY;
99624df6592SIngo Weinhold 
99724df6592SIngo Weinhold 	// check the ports limit
9987f64b301SJulian Harnath 	const int32 previouslyUsed = atomic_add(&sUsedPorts, 1);
9997f64b301SJulian Harnath 	if (previouslyUsed + 1 >= sMaxPorts) {
10007f64b301SJulian Harnath 		atomic_add(&sUsedPorts, -1);
10017f64b301SJulian Harnath 		delete port;
100224df6592SIngo Weinhold 		return B_NO_MORE_PORTS;
10037f64b301SJulian Harnath 	}
100424df6592SIngo Weinhold 
10057f64b301SJulian Harnath 	{
10067f64b301SJulian Harnath 		WriteLocker locker(sPortsLock);
1007224aee3fSIngo Weinhold 
100824df6592SIngo Weinhold 		// allocate a port ID
100924df6592SIngo Weinhold 		do {
101024df6592SIngo Weinhold 			port->id = sNextPortID++;
1011224aee3fSIngo Weinhold 
101224df6592SIngo Weinhold 			// handle integer overflow
101324df6592SIngo Weinhold 			if (sNextPortID < 0)
101424df6592SIngo Weinhold 				sNextPortID = 1;
101524df6592SIngo Weinhold 		} while (sPorts.Lookup(port->id) != NULL);
1016224aee3fSIngo Weinhold 
10177f64b301SJulian Harnath 		// Insert port physically:
10187f64b301SJulian Harnath 		// (1/2) Insert into hash tables
10197f64b301SJulian Harnath 		port->AcquireReference();
10207f64b301SJulian Harnath 			// joint reference for sPorts and sPortsByName
10217f64b301SJulian Harnath 
102224df6592SIngo Weinhold 		sPorts.Insert(port);
10237f64b301SJulian Harnath 		sPortsByName.Insert(port);
10247f64b301SJulian Harnath 	}
10257f64b301SJulian Harnath 
10267f64b301SJulian Harnath 	// (2/2) Insert into team list
10277f64b301SJulian Harnath 	{
10287f64b301SJulian Harnath 		const uint8 lockIndex = port->owner % kTeamListLockCount;
10297f64b301SJulian Harnath 		MutexLocker teamPortsListLocker(sTeamListLock[lockIndex]);
10307f64b301SJulian Harnath 		port->AcquireReference();
10317f64b301SJulian Harnath 		list_add_item(&team->port_list, port);
10327f64b301SJulian Harnath 	}
103324df6592SIngo Weinhold 
103424df6592SIngo Weinhold 	// tracing, notifications, etc.
103524df6592SIngo Weinhold 	T(Create(port));
103624df6592SIngo Weinhold 
10377f64b301SJulian Harnath 	const port_id id = port->id;
103824df6592SIngo Weinhold 
10397f64b301SJulian Harnath 	// Insert port logically by marking it active
10407f64b301SJulian Harnath 	const int32 oldState = atomic_test_and_set(&port->state,
10417f64b301SJulian Harnath 		Port::kActive, Port::kUnused);
10427f64b301SJulian Harnath 		// Linearization point for port creation
10437f64b301SJulian Harnath 
10447f64b301SJulian Harnath 	if (oldState != Port::kUnused) {
10457f64b301SJulian Harnath 		// Nobody is allowed to tamper with the port before it's active.
10467f64b301SJulian Harnath 		panic("Port state was modified during creation!\n");
10477f64b301SJulian Harnath 	}
1048224aee3fSIngo Weinhold 
1049224aee3fSIngo Weinhold 	TRACE(("create_port() done: port created %ld\n", id));
1050224aee3fSIngo Weinhold 
105151755cf8SAxel Dörfler 	sNotificationService.Notify(PORT_ADDED, id);
1052224aee3fSIngo Weinhold 	return id;
1053224aee3fSIngo Weinhold }
1054224aee3fSIngo Weinhold 
1055224aee3fSIngo Weinhold 
1056224aee3fSIngo Weinhold status_t
1057224aee3fSIngo Weinhold close_port(port_id id)
1058224aee3fSIngo Weinhold {
1059224aee3fSIngo Weinhold 	TRACE(("close_port(id = %ld)\n", id));
1060224aee3fSIngo Weinhold 
1061224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1062224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1063224aee3fSIngo Weinhold 
106424df6592SIngo Weinhold 	// get the port
10657f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
10667f64b301SJulian Harnath 	if (portRef == NULL) {
1067224aee3fSIngo Weinhold 		TRACE(("close_port: invalid port_id %ld\n", id));
1068224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1069224aee3fSIngo Weinhold 	}
10707f64b301SJulian Harnath 	MutexLocker lock(&portRef->lock, true);
1071224aee3fSIngo Weinhold 
1072224aee3fSIngo Weinhold 	// mark port to disable writing - deleting the semaphores will
1073224aee3fSIngo Weinhold 	// wake up waiting read/writes
10747f64b301SJulian Harnath 	portRef->capacity = 0;
1075224aee3fSIngo Weinhold 
10767f64b301SJulian Harnath 	notify_port_select_events(portRef, B_EVENT_INVALID);
10777f64b301SJulian Harnath 	portRef->select_infos = NULL;
1078224aee3fSIngo Weinhold 
1079d0f2d828SPawel Dziepak 	portRef->read_condition.NotifyAll(B_BAD_PORT_ID);
1080d0f2d828SPawel Dziepak 	portRef->write_condition.NotifyAll(B_BAD_PORT_ID);
1081224aee3fSIngo Weinhold 
1082e8885f20SAxel Dörfler 	return B_OK;
1083224aee3fSIngo Weinhold }
1084224aee3fSIngo Weinhold 
1085224aee3fSIngo Weinhold 
1086224aee3fSIngo Weinhold status_t
1087224aee3fSIngo Weinhold delete_port(port_id id)
1088224aee3fSIngo Weinhold {
1089224aee3fSIngo Weinhold 	TRACE(("delete_port(id = %ld)\n", id));
1090224aee3fSIngo Weinhold 
1091224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1092224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1093224aee3fSIngo Weinhold 
10947f64b301SJulian Harnath 	BReference<Port> portRef = get_port(id);
1095224aee3fSIngo Weinhold 
10967f64b301SJulian Harnath 	if (portRef == NULL) {
1097224aee3fSIngo Weinhold 		TRACE(("delete_port: invalid port_id %ld\n", id));
1098224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1099224aee3fSIngo Weinhold 	}
1100224aee3fSIngo Weinhold 
11017f64b301SJulian Harnath 	status_t status = delete_port_logical(portRef);
11027f64b301SJulian Harnath 		// Contains linearization point
11037f64b301SJulian Harnath 	if (status != B_OK)
11047f64b301SJulian Harnath 		return status;
1105f28dd36bSAxel Dörfler 
11067f64b301SJulian Harnath 	// Now remove port physically:
11077f64b301SJulian Harnath 	// (1/2) Remove from hash tables
11087f64b301SJulian Harnath 	{
11097f64b301SJulian Harnath 		WriteLocker portsLocker(sPortsLock);
111024df6592SIngo Weinhold 
11117f64b301SJulian Harnath 		sPorts.Remove(portRef);
11127f64b301SJulian Harnath 		sPortsByName.Remove(portRef);
111324df6592SIngo Weinhold 
11147f64b301SJulian Harnath 		portRef->ReleaseReference();
11157f64b301SJulian Harnath 			// joint reference for sPorts and sPortsByName
1116e8885f20SAxel Dörfler 	}
1117224aee3fSIngo Weinhold 
11187f64b301SJulian Harnath 	// (2/2) Remove from team port list
11197f64b301SJulian Harnath 	{
11207f64b301SJulian Harnath 		const uint8 lockIndex = portRef->owner % kTeamListLockCount;
11217f64b301SJulian Harnath 		MutexLocker teamPortsListLocker(sTeamListLock[lockIndex]);
1122224aee3fSIngo Weinhold 
11237f64b301SJulian Harnath 		list_remove_link(&portRef->team_link);
11247f64b301SJulian Harnath 		portRef->ReleaseReference();
11257f64b301SJulian Harnath 	}
1126e8885f20SAxel Dörfler 
11277f64b301SJulian Harnath 	uninit_port(portRef);
11287f64b301SJulian Harnath 
11297f64b301SJulian Harnath 	T(Delete(portRef));
11307f64b301SJulian Harnath 
11317f64b301SJulian Harnath 	atomic_add(&sUsedPorts, -1);
1132e8885f20SAxel Dörfler 
1133224aee3fSIngo Weinhold 	return B_OK;
1134224aee3fSIngo Weinhold }
1135224aee3fSIngo Weinhold 
1136224aee3fSIngo Weinhold 
1137224aee3fSIngo Weinhold status_t
1138224aee3fSIngo Weinhold select_port(int32 id, struct select_info* info, bool kernel)
1139224aee3fSIngo Weinhold {
1140224aee3fSIngo Weinhold 	if (id < 0)
1141224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1142224aee3fSIngo Weinhold 
114324df6592SIngo Weinhold 	// get the port
11447f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
11457f64b301SJulian Harnath 	if (portRef == NULL)
1146e8885f20SAxel Dörfler 		return B_BAD_PORT_ID;
11477f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
114824df6592SIngo Weinhold 
114924df6592SIngo Weinhold 	// port must not yet be closed
11507f64b301SJulian Harnath 	if (is_port_closed(portRef))
115124df6592SIngo Weinhold 		return B_BAD_PORT_ID;
115224df6592SIngo Weinhold 
11537f64b301SJulian Harnath 	if (!kernel && portRef->owner == team_get_kernel_team_id()) {
1154224aee3fSIngo Weinhold 		// kernel port, but call from userland
1155e8885f20SAxel Dörfler 		return B_NOT_ALLOWED;
1156e8885f20SAxel Dörfler 	}
1157e8885f20SAxel Dörfler 
1158224aee3fSIngo Weinhold 	info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID;
1159224aee3fSIngo Weinhold 
1160224aee3fSIngo Weinhold 	if (info->selected_events != 0) {
1161224aee3fSIngo Weinhold 		uint16 events = 0;
1162224aee3fSIngo Weinhold 
11637f64b301SJulian Harnath 		info->next = portRef->select_infos;
11647f64b301SJulian Harnath 		portRef->select_infos = info;
1165224aee3fSIngo Weinhold 
1166224aee3fSIngo Weinhold 		// check for events
1167224aee3fSIngo Weinhold 		if ((info->selected_events & B_EVENT_READ) != 0
11687f64b301SJulian Harnath 			&& !portRef->messages.IsEmpty()) {
1169224aee3fSIngo Weinhold 			events |= B_EVENT_READ;
1170224aee3fSIngo Weinhold 		}
1171224aee3fSIngo Weinhold 
11727f64b301SJulian Harnath 		if (portRef->write_count > 0)
1173224aee3fSIngo Weinhold 			events |= B_EVENT_WRITE;
1174224aee3fSIngo Weinhold 
1175224aee3fSIngo Weinhold 		if (events != 0)
1176224aee3fSIngo Weinhold 			notify_select_events(info, events);
1177224aee3fSIngo Weinhold 	}
1178224aee3fSIngo Weinhold 
1179e8885f20SAxel Dörfler 	return B_OK;
1180224aee3fSIngo Weinhold }
1181224aee3fSIngo Weinhold 
1182224aee3fSIngo Weinhold 
1183224aee3fSIngo Weinhold status_t
1184224aee3fSIngo Weinhold deselect_port(int32 id, struct select_info* info, bool kernel)
1185224aee3fSIngo Weinhold {
1186224aee3fSIngo Weinhold 	if (id < 0)
1187224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1188224aee3fSIngo Weinhold 	if (info->selected_events == 0)
1189224aee3fSIngo Weinhold 		return B_OK;
1190224aee3fSIngo Weinhold 
119124df6592SIngo Weinhold 	// get the port
11927f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
11937f64b301SJulian Harnath 	if (portRef == NULL)
119424df6592SIngo Weinhold 		return B_BAD_PORT_ID;
11957f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1196224aee3fSIngo Weinhold 
119724df6592SIngo Weinhold 	// find and remove the infos
11987f64b301SJulian Harnath 	select_info** infoLocation = &portRef->select_infos;
1199224aee3fSIngo Weinhold 	while (*infoLocation != NULL && *infoLocation != info)
1200224aee3fSIngo Weinhold 		infoLocation = &(*infoLocation)->next;
1201224aee3fSIngo Weinhold 
1202224aee3fSIngo Weinhold 	if (*infoLocation == info)
1203224aee3fSIngo Weinhold 		*infoLocation = info->next;
1204224aee3fSIngo Weinhold 
1205224aee3fSIngo Weinhold 	return B_OK;
1206224aee3fSIngo Weinhold }
1207224aee3fSIngo Weinhold 
1208224aee3fSIngo Weinhold 
1209224aee3fSIngo Weinhold port_id
1210224aee3fSIngo Weinhold find_port(const char* name)
1211224aee3fSIngo Weinhold {
1212224aee3fSIngo Weinhold 	TRACE(("find_port(name = \"%s\")\n", name));
1213224aee3fSIngo Weinhold 
1214e8885f20SAxel Dörfler 	if (!sPortsActive) {
1215e8885f20SAxel Dörfler 		panic("ports used too early!\n");
1216224aee3fSIngo Weinhold 		return B_NAME_NOT_FOUND;
1217e8885f20SAxel Dörfler 	}
1218224aee3fSIngo Weinhold 	if (name == NULL)
1219224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1220224aee3fSIngo Weinhold 
12217f64b301SJulian Harnath 	ReadLocker locker(sPortsLock);
12227f64b301SJulian Harnath 	Port* port = sPortsByName.Lookup(name);
12237f64b301SJulian Harnath 		// Since we have sPortsLock and don't return the port itself,
12247f64b301SJulian Harnath 		// no BReference necessary
1225224aee3fSIngo Weinhold 
12267f64b301SJulian Harnath 	if (port != NULL && port->state == Port::kActive)
122724df6592SIngo Weinhold 		return port->id;
1228224aee3fSIngo Weinhold 
1229e8885f20SAxel Dörfler 	return B_NAME_NOT_FOUND;
1230224aee3fSIngo Weinhold }
1231224aee3fSIngo Weinhold 
1232224aee3fSIngo Weinhold 
1233224aee3fSIngo Weinhold status_t
1234224aee3fSIngo Weinhold _get_port_info(port_id id, port_info* info, size_t size)
1235224aee3fSIngo Weinhold {
1236224aee3fSIngo Weinhold 	TRACE(("get_port_info(id = %ld)\n", id));
1237224aee3fSIngo Weinhold 
1238224aee3fSIngo Weinhold 	if (info == NULL || size != sizeof(port_info))
1239224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1240224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1241224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1242224aee3fSIngo Weinhold 
124324df6592SIngo Weinhold 	// get the port
12447f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
12457f64b301SJulian Harnath 	if (portRef == NULL) {
1246224aee3fSIngo Weinhold 		TRACE(("get_port_info: invalid port_id %ld\n", id));
1247224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1248224aee3fSIngo Weinhold 	}
12497f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1250224aee3fSIngo Weinhold 
1251224aee3fSIngo Weinhold 	// fill a port_info struct with info
12527f64b301SJulian Harnath 	fill_port_info(portRef, info, size);
1253224aee3fSIngo Weinhold 	return B_OK;
1254224aee3fSIngo Weinhold }
1255224aee3fSIngo Weinhold 
1256224aee3fSIngo Weinhold 
1257224aee3fSIngo Weinhold status_t
125824df6592SIngo Weinhold _get_next_port_info(team_id teamID, int32* _cookie, struct port_info* info,
1259e8885f20SAxel Dörfler 	size_t size)
1260224aee3fSIngo Weinhold {
126124df6592SIngo Weinhold 	TRACE(("get_next_port_info(team = %ld)\n", teamID));
1262224aee3fSIngo Weinhold 
1263e8885f20SAxel Dörfler 	if (info == NULL || size != sizeof(port_info) || _cookie == NULL
126424df6592SIngo Weinhold 		|| teamID < 0) {
1265224aee3fSIngo Weinhold 		return B_BAD_VALUE;
126624df6592SIngo Weinhold 	}
1267224aee3fSIngo Weinhold 	if (!sPortsActive)
1268224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1269224aee3fSIngo Weinhold 
127024df6592SIngo Weinhold 	Team* team = Team::Get(teamID);
127124df6592SIngo Weinhold 	if (team == NULL)
127224df6592SIngo Weinhold 		return B_BAD_TEAM_ID;
127324df6592SIngo Weinhold 	BReference<Team> teamReference(team, true);
1274224aee3fSIngo Weinhold 
127524df6592SIngo Weinhold 	// iterate through the team's port list
12767f64b301SJulian Harnath 	const uint8 lockIndex = teamID % kTeamListLockCount;
12777f64b301SJulian Harnath 	MutexLocker teamPortsListLocker(sTeamListLock[lockIndex]);
1278224aee3fSIngo Weinhold 
127924df6592SIngo Weinhold 	int32 stopIndex = *_cookie;
128024df6592SIngo Weinhold 	int32 index = 0;
1281224aee3fSIngo Weinhold 
128224df6592SIngo Weinhold 	Port* port = (Port*)list_get_first_item(&team->port_list);
128324df6592SIngo Weinhold 	while (port != NULL) {
128424df6592SIngo Weinhold 		if (!is_port_closed(port)) {
128524df6592SIngo Weinhold 			if (index == stopIndex)
1286224aee3fSIngo Weinhold 				break;
128724df6592SIngo Weinhold 			index++;
1288224aee3fSIngo Weinhold 		}
1289e8885f20SAxel Dörfler 
129024df6592SIngo Weinhold 		port = (Port*)list_get_next_item(&team->port_list, port);
1291224aee3fSIngo Weinhold 	}
1292224aee3fSIngo Weinhold 
129324df6592SIngo Weinhold 	if (port == NULL)
1294224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1295224aee3fSIngo Weinhold 
129624df6592SIngo Weinhold 	// fill in the port info
12977f64b301SJulian Harnath 	BReference<Port> portRef = port;
12987f64b301SJulian Harnath 	teamPortsListLocker.Unlock();
12997f64b301SJulian Harnath 		// Only use portRef below this line...
13007f64b301SJulian Harnath 
13017f64b301SJulian Harnath 	MutexLocker locker(portRef->lock);
13027f64b301SJulian Harnath 	fill_port_info(portRef, info, size);
130324df6592SIngo Weinhold 
130424df6592SIngo Weinhold 	*_cookie = stopIndex + 1;
1305e8885f20SAxel Dörfler 	return B_OK;
1306224aee3fSIngo Weinhold }
1307224aee3fSIngo Weinhold 
1308224aee3fSIngo Weinhold 
1309224aee3fSIngo Weinhold ssize_t
1310224aee3fSIngo Weinhold port_buffer_size(port_id id)
1311224aee3fSIngo Weinhold {
1312224aee3fSIngo Weinhold 	return port_buffer_size_etc(id, 0, 0);
1313224aee3fSIngo Weinhold }
1314224aee3fSIngo Weinhold 
1315224aee3fSIngo Weinhold 
1316224aee3fSIngo Weinhold ssize_t
1317224aee3fSIngo Weinhold port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
1318224aee3fSIngo Weinhold {
13197727e08eSIngo Weinhold 	port_message_info info;
13207727e08eSIngo Weinhold 	status_t error = get_port_message_info_etc(id, &info, flags, timeout);
13217727e08eSIngo Weinhold 	return error != B_OK ? error : info.size;
13227727e08eSIngo Weinhold }
13237727e08eSIngo Weinhold 
1324e8885f20SAxel Dörfler 
13257727e08eSIngo Weinhold status_t
13267727e08eSIngo Weinhold _get_port_message_info_etc(port_id id, port_message_info* info,
13277727e08eSIngo Weinhold 	size_t infoSize, uint32 flags, bigtime_t timeout)
13287727e08eSIngo Weinhold {
13297727e08eSIngo Weinhold 	if (info == NULL || infoSize != sizeof(port_message_info))
13307727e08eSIngo Weinhold 		return B_BAD_VALUE;
1331224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1332224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1333224aee3fSIngo Weinhold 
1334f28dd36bSAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1335f28dd36bSAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1336224aee3fSIngo Weinhold 
133724df6592SIngo Weinhold 	// get the port
13387f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
13397f64b301SJulian Harnath 	if (portRef == NULL)
134024df6592SIngo Weinhold 		return B_BAD_PORT_ID;
13417f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1342224aee3fSIngo Weinhold 
13437f64b301SJulian Harnath 	if (is_port_closed(portRef) && portRef->messages.IsEmpty()) {
13447f64b301SJulian Harnath 		T(Info(portRef, 0, B_BAD_PORT_ID));
134524df6592SIngo Weinhold 		TRACE(("_get_port_message_info_etc(): closed port %ld\n", id));
1346224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1347224aee3fSIngo Weinhold 	}
1348224aee3fSIngo Weinhold 
13497f64b301SJulian Harnath 	while (portRef->read_count == 0) {
1350e8885f20SAxel Dörfler 		// We need to wait for a message to appear
1351f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1352f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1353f28dd36bSAxel Dörfler 
1354e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
13557f64b301SJulian Harnath 		portRef->read_condition.Add(&entry);
1356224aee3fSIngo Weinhold 
1357e8885f20SAxel Dörfler 		locker.Unlock();
1358224aee3fSIngo Weinhold 
1359224aee3fSIngo Weinhold 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1360e8885f20SAxel Dörfler 		status_t status = entry.Wait(flags, timeout);
1361f28dd36bSAxel Dörfler 
1362f28dd36bSAxel Dörfler 		if (status != B_OK) {
1363748c0f30SAxel Dörfler 			T(Info(portRef, 0, status));
1364224aee3fSIngo Weinhold 			return status;
1365f28dd36bSAxel Dörfler 		}
1366224aee3fSIngo Weinhold 
136724df6592SIngo Weinhold 		// re-lock
13687f64b301SJulian Harnath 		BReference<Port> newPortRef = get_locked_port(id);
13697f64b301SJulian Harnath 		if (newPortRef == NULL) {
137024df6592SIngo Weinhold 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
137124df6592SIngo Weinhold 			return B_BAD_PORT_ID;
137224df6592SIngo Weinhold 		}
13737f64b301SJulian Harnath 		locker.SetTo(newPortRef->lock, true);
1374224aee3fSIngo Weinhold 
13757f64b301SJulian Harnath 		if (newPortRef != portRef
13767f64b301SJulian Harnath 			|| (is_port_closed(portRef) && portRef->messages.IsEmpty())) {
1377224aee3fSIngo Weinhold 			// the port is no longer there
137824df6592SIngo Weinhold 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
1379224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1380224aee3fSIngo Weinhold 		}
1381a73382f7SIngo Weinhold 	}
1382224aee3fSIngo Weinhold 
1383224aee3fSIngo Weinhold 	// determine tail & get the length of the message
13847f64b301SJulian Harnath 	port_message* message = portRef->messages.Head();
1385e8885f20SAxel Dörfler 	if (message == NULL) {
13867f64b301SJulian Harnath 		panic("port %" B_PRId32 ": no messages found\n", portRef->id);
1387e8885f20SAxel Dörfler 		return B_ERROR;
13887727e08eSIngo Weinhold 	}
1389224aee3fSIngo Weinhold 
1390e8885f20SAxel Dörfler 	info->size = message->size;
1391e8885f20SAxel Dörfler 	info->sender = message->sender;
1392e8885f20SAxel Dörfler 	info->sender_group = message->sender_group;
1393e8885f20SAxel Dörfler 	info->sender_team = message->sender_team;
1394224aee3fSIngo Weinhold 
1395748c0f30SAxel Dörfler 	T(Info(portRef, message->code, B_OK));
1396f28dd36bSAxel Dörfler 
1397e8885f20SAxel Dörfler 	// notify next one, as we haven't read from the port
13987f64b301SJulian Harnath 	portRef->read_condition.NotifyOne();
1399224aee3fSIngo Weinhold 
1400e8885f20SAxel Dörfler 	return B_OK;
1401224aee3fSIngo Weinhold }
1402224aee3fSIngo Weinhold 
1403224aee3fSIngo Weinhold 
1404224aee3fSIngo Weinhold ssize_t
1405224aee3fSIngo Weinhold port_count(port_id id)
1406224aee3fSIngo Weinhold {
1407224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1408224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1409224aee3fSIngo Weinhold 
141024df6592SIngo Weinhold 	// get the port
14117f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
14127f64b301SJulian Harnath 	if (portRef == NULL) {
1413224aee3fSIngo Weinhold 		TRACE(("port_count: invalid port_id %ld\n", id));
1414224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1415224aee3fSIngo Weinhold 	}
14167f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1417224aee3fSIngo Weinhold 
1418224aee3fSIngo Weinhold 	// return count of messages
14197f64b301SJulian Harnath 	return portRef->read_count;
1420224aee3fSIngo Weinhold }
1421224aee3fSIngo Weinhold 
1422224aee3fSIngo Weinhold 
1423224aee3fSIngo Weinhold ssize_t
1424e8885f20SAxel Dörfler read_port(port_id port, int32* msgCode, void* buffer, size_t bufferSize)
1425224aee3fSIngo Weinhold {
1426e8885f20SAxel Dörfler 	return read_port_etc(port, msgCode, buffer, bufferSize, 0, 0);
1427224aee3fSIngo Weinhold }
1428224aee3fSIngo Weinhold 
1429224aee3fSIngo Weinhold 
1430224aee3fSIngo Weinhold ssize_t
1431e8885f20SAxel Dörfler read_port_etc(port_id id, int32* _code, void* buffer, size_t bufferSize,
1432224aee3fSIngo Weinhold 	uint32 flags, bigtime_t timeout)
1433224aee3fSIngo Weinhold {
1434224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1435224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1436e8885f20SAxel Dörfler 	if ((buffer == NULL && bufferSize > 0) || timeout < 0)
1437224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1438224aee3fSIngo Weinhold 
1439e8885f20SAxel Dörfler 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0;
1440e8885f20SAxel Dörfler 	bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0;
1441e8885f20SAxel Dörfler 		// TODO: we could allow peeking for user apps now
1442224aee3fSIngo Weinhold 
1443e8885f20SAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1444e8885f20SAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1445e8885f20SAxel Dörfler 
144624df6592SIngo Weinhold 	// get the port
14477f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
14487f64b301SJulian Harnath 	if (portRef == NULL)
144924df6592SIngo Weinhold 		return B_BAD_PORT_ID;
14507f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1451e8885f20SAxel Dörfler 
14527f64b301SJulian Harnath 	if (is_port_closed(portRef) && portRef->messages.IsEmpty()) {
14537f64b301SJulian Harnath 		T(Read(portRef, 0, B_BAD_PORT_ID));
145424df6592SIngo Weinhold 		TRACE(("read_port_etc(): closed port %ld\n", id));
1455224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1456224aee3fSIngo Weinhold 	}
1457224aee3fSIngo Weinhold 
14587f64b301SJulian Harnath 	while (portRef->read_count == 0) {
1459f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1460f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1461f28dd36bSAxel Dörfler 
1462e8885f20SAxel Dörfler 		// We need to wait for a message to appear
1463e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
14647f64b301SJulian Harnath 		portRef->read_condition.Add(&entry);
1465224aee3fSIngo Weinhold 
1466e8885f20SAxel Dörfler 		locker.Unlock();
1467224aee3fSIngo Weinhold 
1468e8885f20SAxel Dörfler 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1469e8885f20SAxel Dörfler 		status_t status = entry.Wait(flags, timeout);
1470224aee3fSIngo Weinhold 
147124df6592SIngo Weinhold 		// re-lock
14727f64b301SJulian Harnath 		BReference<Port> newPortRef = get_locked_port(id);
14737f64b301SJulian Harnath 		if (newPortRef == NULL) {
147424df6592SIngo Weinhold 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
147524df6592SIngo Weinhold 			return B_BAD_PORT_ID;
147624df6592SIngo Weinhold 		}
14777f64b301SJulian Harnath 		locker.SetTo(newPortRef->lock, true);
1478224aee3fSIngo Weinhold 
14797f64b301SJulian Harnath 		if (newPortRef != portRef
14807f64b301SJulian Harnath 			|| (is_port_closed(portRef) && portRef->messages.IsEmpty())) {
1481e8885f20SAxel Dörfler 			// the port is no longer there
148224df6592SIngo Weinhold 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
1483224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1484224aee3fSIngo Weinhold 		}
1485224aee3fSIngo Weinhold 
1486c3bc71d6SIngo Weinhold 		if (status != B_OK) {
14877f64b301SJulian Harnath 			T(Read(portRef, 0, status));
1488c3bc71d6SIngo Weinhold 			return status;
1489e8885f20SAxel Dörfler 		}
14907d592ec4SAxel Dörfler 	}
1491224aee3fSIngo Weinhold 
1492e8885f20SAxel Dörfler 	// determine tail & get the length of the message
14937f64b301SJulian Harnath 	port_message* message = portRef->messages.Head();
1494e8885f20SAxel Dörfler 	if (message == NULL) {
14957f64b301SJulian Harnath 		panic("port %" B_PRId32 ": no messages found\n", portRef->id);
1496e8885f20SAxel Dörfler 		return B_ERROR;
1497224aee3fSIngo Weinhold 	}
1498224aee3fSIngo Weinhold 
1499b4ec7b8eSIngo Weinhold 	if (peekOnly) {
1500e8885f20SAxel Dörfler 		size_t size = copy_port_message(message, _code, buffer, bufferSize,
1501e8885f20SAxel Dörfler 			userCopy);
1502e8885f20SAxel Dörfler 
15037f64b301SJulian Harnath 		T(Read(portRef, message->code, size));
1504f28dd36bSAxel Dörfler 
15057f64b301SJulian Harnath 		portRef->read_condition.NotifyOne();
1506b4ec7b8eSIngo Weinhold 			// we only peeked, but didn't grab the message
1507b4ec7b8eSIngo Weinhold 		return size;
1508b4ec7b8eSIngo Weinhold 	}
1509b4ec7b8eSIngo Weinhold 
15107f64b301SJulian Harnath 	portRef->messages.RemoveHead();
15117f64b301SJulian Harnath 	portRef->total_count++;
15127f64b301SJulian Harnath 	portRef->write_count++;
15137f64b301SJulian Harnath 	portRef->read_count--;
1514224aee3fSIngo Weinhold 
15157f64b301SJulian Harnath 	notify_port_select_events(portRef, B_EVENT_WRITE);
15167f64b301SJulian Harnath 	portRef->write_condition.NotifyOne();
1517224aee3fSIngo Weinhold 		// make one spot in queue available again for write
1518224aee3fSIngo Weinhold 
1519748c0f30SAxel Dörfler 	T(Read(portRef, message->code, std::min(bufferSize, message->size)));
152024df6592SIngo Weinhold 
1521e8885f20SAxel Dörfler 	locker.Unlock();
1522e8885f20SAxel Dörfler 
1523e8885f20SAxel Dörfler 	size_t size = copy_port_message(message, _code, buffer, bufferSize,
1524e8885f20SAxel Dörfler 		userCopy);
1525e8885f20SAxel Dörfler 
1526e8885f20SAxel Dörfler 	put_port_message(message);
1527224aee3fSIngo Weinhold 	return size;
1528224aee3fSIngo Weinhold }
1529224aee3fSIngo Weinhold 
1530224aee3fSIngo Weinhold 
1531224aee3fSIngo Weinhold status_t
1532e8885f20SAxel Dörfler write_port(port_id id, int32 msgCode, const void* buffer, size_t bufferSize)
1533224aee3fSIngo Weinhold {
1534e8885f20SAxel Dörfler 	iovec vec = { (void*)buffer, bufferSize };
1535224aee3fSIngo Weinhold 
1536224aee3fSIngo Weinhold 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0);
1537224aee3fSIngo Weinhold }
1538224aee3fSIngo Weinhold 
1539224aee3fSIngo Weinhold 
1540224aee3fSIngo Weinhold status_t
1541e8885f20SAxel Dörfler write_port_etc(port_id id, int32 msgCode, const void* buffer,
1542224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1543224aee3fSIngo Weinhold {
1544e8885f20SAxel Dörfler 	iovec vec = { (void*)buffer, bufferSize };
1545224aee3fSIngo Weinhold 
1546224aee3fSIngo Weinhold 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout);
1547224aee3fSIngo Weinhold }
1548224aee3fSIngo Weinhold 
1549224aee3fSIngo Weinhold 
1550224aee3fSIngo Weinhold status_t
1551224aee3fSIngo Weinhold writev_port_etc(port_id id, int32 msgCode, const iovec* msgVecs,
1552e8885f20SAxel Dörfler 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1553224aee3fSIngo Weinhold {
1554224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1555224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1556224aee3fSIngo Weinhold 	if (bufferSize > PORT_MAX_MESSAGE_SIZE)
1557224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1558224aee3fSIngo Weinhold 
15596e28d809SJérôme Duval 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0;
15606e28d809SJérôme Duval 
1561e8885f20SAxel Dörfler 	// mask irrelevant flags (for acquire_sem() usage)
1562e8885f20SAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1563e8885f20SAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1564f28dd36bSAxel Dörfler 	if ((flags & B_RELATIVE_TIMEOUT) != 0
1565f28dd36bSAxel Dörfler 		&& timeout != B_INFINITE_TIMEOUT && timeout > 0) {
1566f28dd36bSAxel Dörfler 		// Make the timeout absolute, since we have more than one step where
1567f28dd36bSAxel Dörfler 		// we might have to wait
1568f28dd36bSAxel Dörfler 		flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT;
1569f28dd36bSAxel Dörfler 		timeout += system_time();
1570f28dd36bSAxel Dörfler 	}
1571f28dd36bSAxel Dörfler 
1572f28dd36bSAxel Dörfler 	status_t status;
15731c61ec1aSIngo Weinhold 	port_message* message = NULL;
1574e8885f20SAxel Dörfler 
157524df6592SIngo Weinhold 	// get the port
15767f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
15777f64b301SJulian Harnath 	if (portRef == NULL) {
1578224aee3fSIngo Weinhold 		TRACE(("write_port_etc: invalid port_id %ld\n", id));
1579224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1580224aee3fSIngo Weinhold 	}
15817f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
158224df6592SIngo Weinhold 
15837f64b301SJulian Harnath 	if (is_port_closed(portRef)) {
1584224aee3fSIngo Weinhold 		TRACE(("write_port_etc: port %ld closed\n", id));
1585224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1586224aee3fSIngo Weinhold 	}
1587224aee3fSIngo Weinhold 
15887f64b301SJulian Harnath 	if (portRef->write_count <= 0) {
1589f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1590f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1591f28dd36bSAxel Dörfler 
15927f64b301SJulian Harnath 		portRef->write_count--;
1593f28dd36bSAxel Dörfler 
1594e8885f20SAxel Dörfler 		// We need to block in order to wait for a free message slot
1595e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
15967f64b301SJulian Harnath 		portRef->write_condition.Add(&entry);
1597224aee3fSIngo Weinhold 
1598e8885f20SAxel Dörfler 		locker.Unlock();
1599224aee3fSIngo Weinhold 
1600f28dd36bSAxel Dörfler 		status = entry.Wait(flags, timeout);
1601224aee3fSIngo Weinhold 
160224df6592SIngo Weinhold 		// re-lock
16037f64b301SJulian Harnath 		BReference<Port> newPortRef = get_locked_port(id);
16047f64b301SJulian Harnath 		if (newPortRef == NULL) {
160524df6592SIngo Weinhold 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
160624df6592SIngo Weinhold 			return B_BAD_PORT_ID;
160724df6592SIngo Weinhold 		}
16087f64b301SJulian Harnath 		locker.SetTo(newPortRef->lock, true);
1609e8885f20SAxel Dörfler 
16107f64b301SJulian Harnath 		if (newPortRef != portRef || is_port_closed(portRef)) {
1611e8885f20SAxel Dörfler 			// the port is no longer there
161224df6592SIngo Weinhold 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1613224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1614224aee3fSIngo Weinhold 		}
1615224aee3fSIngo Weinhold 
1616c3bc71d6SIngo Weinhold 		if (status != B_OK)
1617f28dd36bSAxel Dörfler 			goto error;
1618f28dd36bSAxel Dörfler 	} else
16197f64b301SJulian Harnath 		portRef->write_count--;
1620e8885f20SAxel Dörfler 
1621f28dd36bSAxel Dörfler 	status = get_port_message(msgCode, bufferSize, flags, timeout,
16227f64b301SJulian Harnath 		&message, *portRef);
1623cd3e02caSMichael Lotz 	if (status != B_OK) {
1624cd3e02caSMichael Lotz 		if (status == B_BAD_PORT_ID) {
1625cd3e02caSMichael Lotz 			// the port had to be unlocked and is now no longer there
1626cd3e02caSMichael Lotz 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1627cd3e02caSMichael Lotz 			return B_BAD_PORT_ID;
1628cd3e02caSMichael Lotz 		}
1629cd3e02caSMichael Lotz 
1630f28dd36bSAxel Dörfler 		goto error;
1631cd3e02caSMichael Lotz 	}
1632224aee3fSIngo Weinhold 
16337727e08eSIngo Weinhold 	// sender credentials
1634e8885f20SAxel Dörfler 	message->sender = geteuid();
1635e8885f20SAxel Dörfler 	message->sender_group = getegid();
1636e8885f20SAxel Dörfler 	message->sender_team = team_get_current_team_id();
16377727e08eSIngo Weinhold 
1638224aee3fSIngo Weinhold 	if (bufferSize > 0) {
16392b861349SMichael Lotz 		size_t offset = 0;
16402b861349SMichael Lotz 		for (uint32 i = 0; i < vecCount; i++) {
1641224aee3fSIngo Weinhold 			size_t bytes = msgVecs[i].iov_len;
1642224aee3fSIngo Weinhold 			if (bytes > bufferSize)
1643224aee3fSIngo Weinhold 				bytes = bufferSize;
1644224aee3fSIngo Weinhold 
16452b861349SMichael Lotz 			if (userCopy) {
16462b861349SMichael Lotz 				status_t status = user_memcpy(message->buffer + offset,
1647e8885f20SAxel Dörfler 					msgVecs[i].iov_base, bytes);
1648e8885f20SAxel Dörfler 				if (status != B_OK) {
1649e8885f20SAxel Dörfler 					put_port_message(message);
1650f28dd36bSAxel Dörfler 					goto error;
165161de73e2SIngo Weinhold 				}
16522b861349SMichael Lotz 			} else
16532b861349SMichael Lotz 				memcpy(message->buffer + offset, msgVecs[i].iov_base, bytes);
1654224aee3fSIngo Weinhold 
1655224aee3fSIngo Weinhold 			bufferSize -= bytes;
1656224aee3fSIngo Weinhold 			if (bufferSize == 0)
1657224aee3fSIngo Weinhold 				break;
1658224aee3fSIngo Weinhold 
16592b861349SMichael Lotz 			offset += bytes;
1660224aee3fSIngo Weinhold 		}
1661224aee3fSIngo Weinhold 	}
1662224aee3fSIngo Weinhold 
16637f64b301SJulian Harnath 	portRef->messages.Add(message);
16647f64b301SJulian Harnath 	portRef->read_count++;
1665224aee3fSIngo Weinhold 
16667f64b301SJulian Harnath 	T(Write(id, portRef->read_count, portRef->write_count, message->code,
166724df6592SIngo Weinhold 		message->size, B_OK));
1668f28dd36bSAxel Dörfler 
16697f64b301SJulian Harnath 	notify_port_select_events(portRef, B_EVENT_READ);
16707f64b301SJulian Harnath 	portRef->read_condition.NotifyOne();
1671e8885f20SAxel Dörfler 	return B_OK;
1672f28dd36bSAxel Dörfler 
1673f28dd36bSAxel Dörfler error:
1674f28dd36bSAxel Dörfler 	// Give up our slot in the queue again, and let someone else
1675f28dd36bSAxel Dörfler 	// try and fail
16767f64b301SJulian Harnath 	T(Write(id, portRef->read_count, portRef->write_count, 0, 0, status));
16777f64b301SJulian Harnath 	portRef->write_count++;
16787f64b301SJulian Harnath 	notify_port_select_events(portRef, B_EVENT_WRITE);
16797f64b301SJulian Harnath 	portRef->write_condition.NotifyOne();
1680f28dd36bSAxel Dörfler 
1681f28dd36bSAxel Dörfler 	return status;
1682224aee3fSIngo Weinhold }
1683224aee3fSIngo Weinhold 
1684224aee3fSIngo Weinhold 
1685224aee3fSIngo Weinhold status_t
168625028839SAxel Dörfler set_port_owner(port_id id, team_id newTeamID)
1687224aee3fSIngo Weinhold {
168825028839SAxel Dörfler 	TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, newTeamID));
1689224aee3fSIngo Weinhold 
1690e8885f20SAxel Dörfler 	if (id < 0)
1691224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1692224aee3fSIngo Weinhold 
169324df6592SIngo Weinhold 	// get the new team
169424df6592SIngo Weinhold 	Team* team = Team::Get(newTeamID);
169524df6592SIngo Weinhold 	if (team == NULL)
169624df6592SIngo Weinhold 		return B_BAD_TEAM_ID;
169724df6592SIngo Weinhold 	BReference<Team> teamReference(team, true);
1698224aee3fSIngo Weinhold 
169924df6592SIngo Weinhold 	// get the port
17007f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
17017f64b301SJulian Harnath 	if (portRef == NULL) {
1702224aee3fSIngo Weinhold 		TRACE(("set_port_owner: invalid port_id %ld\n", id));
1703224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1704224aee3fSIngo Weinhold 	}
17057f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1706f28dd36bSAxel Dörfler 
1707224aee3fSIngo Weinhold 	// transfer ownership to other team
17087f64b301SJulian Harnath 	if (team->id != portRef->owner) {
17097f64b301SJulian Harnath 		uint8 firstLockIndex  = portRef->owner % kTeamListLockCount;
17107f64b301SJulian Harnath 		uint8 secondLockIndex = team->id % kTeamListLockCount;
17117f64b301SJulian Harnath 
17127f64b301SJulian Harnath 		// Avoid deadlocks: always lock lower index first
17137f64b301SJulian Harnath 		if (secondLockIndex < firstLockIndex) {
17147f64b301SJulian Harnath 			uint8 temp = secondLockIndex;
17157f64b301SJulian Harnath 			secondLockIndex = firstLockIndex;
17167f64b301SJulian Harnath 			firstLockIndex = temp;
171724df6592SIngo Weinhold 		}
1718224aee3fSIngo Weinhold 
17197f64b301SJulian Harnath 		MutexLocker oldTeamPortsListLocker(sTeamListLock[firstLockIndex]);
17207f64b301SJulian Harnath 		MutexLocker newTeamPortsListLocker;
17217f64b301SJulian Harnath 		if (firstLockIndex != secondLockIndex) {
17227f64b301SJulian Harnath 			newTeamPortsListLocker.SetTo(sTeamListLock[secondLockIndex],
17237f64b301SJulian Harnath 					false);
17247f64b301SJulian Harnath 		}
17257f64b301SJulian Harnath 
17267f64b301SJulian Harnath 		// Now that we have locked the team port lists, check the state again
17277f64b301SJulian Harnath 		if (portRef->state == Port::kActive) {
17287f64b301SJulian Harnath 			list_remove_link(&portRef->team_link);
17297f64b301SJulian Harnath 			list_add_item(&team->port_list, portRef.Get());
17307f64b301SJulian Harnath 			portRef->owner = team->id;
17317f64b301SJulian Harnath 		} else {
17327f64b301SJulian Harnath 			// Port was already deleted. We haven't changed anything yet so
17337f64b301SJulian Harnath 			// we can cancel the operation.
17347f64b301SJulian Harnath 			return B_BAD_PORT_ID;
17357f64b301SJulian Harnath 		}
17367f64b301SJulian Harnath 	}
17377f64b301SJulian Harnath 
17387f64b301SJulian Harnath 	T(OwnerChange(portRef, team->id, B_OK));
1739e8885f20SAxel Dörfler 	return B_OK;
1740224aee3fSIngo Weinhold }
1741224aee3fSIngo Weinhold 
1742224aee3fSIngo Weinhold 
1743224aee3fSIngo Weinhold //	#pragma mark - syscalls
1744224aee3fSIngo Weinhold 
1745224aee3fSIngo Weinhold 
1746224aee3fSIngo Weinhold port_id
1747224aee3fSIngo Weinhold _user_create_port(int32 queueLength, const char *userName)
1748224aee3fSIngo Weinhold {
1749224aee3fSIngo Weinhold 	char name[B_OS_NAME_LENGTH];
1750224aee3fSIngo Weinhold 
1751224aee3fSIngo Weinhold 	if (userName == NULL)
1752224aee3fSIngo Weinhold 		return create_port(queueLength, NULL);
1753224aee3fSIngo Weinhold 
1754224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userName)
1755224aee3fSIngo Weinhold 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1756224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1757224aee3fSIngo Weinhold 
1758224aee3fSIngo Weinhold 	return create_port(queueLength, name);
1759224aee3fSIngo Weinhold }
1760224aee3fSIngo Weinhold 
1761224aee3fSIngo Weinhold 
1762224aee3fSIngo Weinhold status_t
1763224aee3fSIngo Weinhold _user_close_port(port_id id)
1764224aee3fSIngo Weinhold {
1765224aee3fSIngo Weinhold 	return close_port(id);
1766224aee3fSIngo Weinhold }
1767224aee3fSIngo Weinhold 
1768224aee3fSIngo Weinhold 
1769224aee3fSIngo Weinhold status_t
1770224aee3fSIngo Weinhold _user_delete_port(port_id id)
1771224aee3fSIngo Weinhold {
1772224aee3fSIngo Weinhold 	return delete_port(id);
1773224aee3fSIngo Weinhold }
1774224aee3fSIngo Weinhold 
1775224aee3fSIngo Weinhold 
1776224aee3fSIngo Weinhold port_id
1777224aee3fSIngo Weinhold _user_find_port(const char *userName)
1778224aee3fSIngo Weinhold {
1779224aee3fSIngo Weinhold 	char name[B_OS_NAME_LENGTH];
1780224aee3fSIngo Weinhold 
1781224aee3fSIngo Weinhold 	if (userName == NULL)
1782224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1783224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userName)
1784224aee3fSIngo Weinhold 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1785224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1786224aee3fSIngo Weinhold 
1787224aee3fSIngo Weinhold 	return find_port(name);
1788224aee3fSIngo Weinhold }
1789224aee3fSIngo Weinhold 
1790224aee3fSIngo Weinhold 
1791224aee3fSIngo Weinhold status_t
1792224aee3fSIngo Weinhold _user_get_port_info(port_id id, struct port_info *userInfo)
1793224aee3fSIngo Weinhold {
1794224aee3fSIngo Weinhold 	struct port_info info;
1795224aee3fSIngo Weinhold 	status_t status;
1796224aee3fSIngo Weinhold 
1797224aee3fSIngo Weinhold 	if (userInfo == NULL)
1798224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1799224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userInfo))
1800224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1801224aee3fSIngo Weinhold 
1802224aee3fSIngo Weinhold 	status = get_port_info(id, &info);
1803224aee3fSIngo Weinhold 
1804224aee3fSIngo Weinhold 	// copy back to user space
18054048494cSIngo Weinhold 	if (status == B_OK
18064048494cSIngo Weinhold 		&& user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK)
1807224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1808224aee3fSIngo Weinhold 
1809224aee3fSIngo Weinhold 	return status;
1810224aee3fSIngo Weinhold }
1811224aee3fSIngo Weinhold 
1812224aee3fSIngo Weinhold 
1813224aee3fSIngo Weinhold status_t
18144048494cSIngo Weinhold _user_get_next_port_info(team_id team, int32 *userCookie,
18154048494cSIngo Weinhold 	struct port_info *userInfo)
1816224aee3fSIngo Weinhold {
1817224aee3fSIngo Weinhold 	struct port_info info;
1818224aee3fSIngo Weinhold 	status_t status;
1819224aee3fSIngo Weinhold 	int32 cookie;
1820224aee3fSIngo Weinhold 
1821224aee3fSIngo Weinhold 	if (userCookie == NULL || userInfo == NULL)
1822224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1823224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo)
1824224aee3fSIngo Weinhold 		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
1825224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1826224aee3fSIngo Weinhold 
1827224aee3fSIngo Weinhold 	status = get_next_port_info(team, &cookie, &info);
1828224aee3fSIngo Weinhold 
1829224aee3fSIngo Weinhold 	// copy back to user space
1830224aee3fSIngo Weinhold 	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
18314048494cSIngo Weinhold 		|| (status == B_OK && user_memcpy(userInfo, &info,
18324048494cSIngo Weinhold 				sizeof(struct port_info)) < B_OK))
1833224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1834224aee3fSIngo Weinhold 
1835224aee3fSIngo Weinhold 	return status;
1836224aee3fSIngo Weinhold }
1837224aee3fSIngo Weinhold 
1838224aee3fSIngo Weinhold 
1839224aee3fSIngo Weinhold ssize_t
1840224aee3fSIngo Weinhold _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout)
1841224aee3fSIngo Weinhold {
18424048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
18434048494cSIngo Weinhold 
18444048494cSIngo Weinhold 	status_t status = port_buffer_size_etc(port, flags | B_CAN_INTERRUPT,
18454048494cSIngo Weinhold 		timeout);
18464048494cSIngo Weinhold 
18474048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1848224aee3fSIngo Weinhold }
1849224aee3fSIngo Weinhold 
1850224aee3fSIngo Weinhold 
1851224aee3fSIngo Weinhold ssize_t
1852224aee3fSIngo Weinhold _user_port_count(port_id port)
1853224aee3fSIngo Weinhold {
1854224aee3fSIngo Weinhold 	return port_count(port);
1855224aee3fSIngo Weinhold }
1856224aee3fSIngo Weinhold 
1857224aee3fSIngo Weinhold 
1858224aee3fSIngo Weinhold status_t
1859224aee3fSIngo Weinhold _user_set_port_owner(port_id port, team_id team)
1860224aee3fSIngo Weinhold {
1861224aee3fSIngo Weinhold 	return set_port_owner(port, team);
1862224aee3fSIngo Weinhold }
1863224aee3fSIngo Weinhold 
1864224aee3fSIngo Weinhold 
1865224aee3fSIngo Weinhold ssize_t
1866224aee3fSIngo Weinhold _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer,
1867224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1868224aee3fSIngo Weinhold {
1869224aee3fSIngo Weinhold 	int32 messageCode;
1870224aee3fSIngo Weinhold 	ssize_t	bytesRead;
1871224aee3fSIngo Weinhold 
18724048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
18734048494cSIngo Weinhold 
1874224aee3fSIngo Weinhold 	if (userBuffer == NULL && bufferSize != 0)
1875224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1876224aee3fSIngo Weinhold 	if ((userCode != NULL && !IS_USER_ADDRESS(userCode))
1877224aee3fSIngo Weinhold 		|| (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)))
1878224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1879224aee3fSIngo Weinhold 
1880224aee3fSIngo Weinhold 	bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize,
1881224aee3fSIngo Weinhold 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1882224aee3fSIngo Weinhold 
1883224aee3fSIngo Weinhold 	if (bytesRead >= 0 && userCode != NULL
1884224aee3fSIngo Weinhold 		&& user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK)
1885224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1886224aee3fSIngo Weinhold 
18874048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(bytesRead, timeout);
1888224aee3fSIngo Weinhold }
1889224aee3fSIngo Weinhold 
1890224aee3fSIngo Weinhold 
1891224aee3fSIngo Weinhold status_t
1892224aee3fSIngo Weinhold _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer,
1893224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1894224aee3fSIngo Weinhold {
1895224aee3fSIngo Weinhold 	iovec vec = { (void *)userBuffer, bufferSize };
1896224aee3fSIngo Weinhold 
18974048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
18984048494cSIngo Weinhold 
1899224aee3fSIngo Weinhold 	if (userBuffer == NULL && bufferSize != 0)
1900224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1901224aee3fSIngo Weinhold 	if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))
1902224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1903224aee3fSIngo Weinhold 
19044048494cSIngo Weinhold 	status_t status = writev_port_etc(port, messageCode, &vec, 1, bufferSize,
1905224aee3fSIngo Weinhold 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
19064048494cSIngo Weinhold 
19074048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1908224aee3fSIngo Weinhold }
1909224aee3fSIngo Weinhold 
1910224aee3fSIngo Weinhold 
1911224aee3fSIngo Weinhold status_t
1912224aee3fSIngo Weinhold _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs,
1913224aee3fSIngo Weinhold 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1914224aee3fSIngo Weinhold {
19154048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
1916224aee3fSIngo Weinhold 
1917224aee3fSIngo Weinhold 	if (userVecs == NULL && bufferSize != 0)
1918224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1919224aee3fSIngo Weinhold 	if (userVecs != NULL && !IS_USER_ADDRESS(userVecs))
1920224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1921224aee3fSIngo Weinhold 
19224048494cSIngo Weinhold 	iovec *vecs = NULL;
1923224aee3fSIngo Weinhold 	if (userVecs && vecCount != 0) {
1924224aee3fSIngo Weinhold 		vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
1925224aee3fSIngo Weinhold 		if (vecs == NULL)
1926224aee3fSIngo Weinhold 			return B_NO_MEMORY;
1927224aee3fSIngo Weinhold 
1928224aee3fSIngo Weinhold 		if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) {
1929224aee3fSIngo Weinhold 			free(vecs);
1930224aee3fSIngo Weinhold 			return B_BAD_ADDRESS;
1931224aee3fSIngo Weinhold 		}
1932224aee3fSIngo Weinhold 	}
19334048494cSIngo Weinhold 
19344048494cSIngo Weinhold 	status_t status = writev_port_etc(port, messageCode, vecs, vecCount,
19354048494cSIngo Weinhold 		bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT,
19364048494cSIngo Weinhold 		timeout);
1937224aee3fSIngo Weinhold 
1938224aee3fSIngo Weinhold 	free(vecs);
19394048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1940224aee3fSIngo Weinhold }
19417727e08eSIngo Weinhold 
19427727e08eSIngo Weinhold 
19437727e08eSIngo Weinhold status_t
19447727e08eSIngo Weinhold _user_get_port_message_info_etc(port_id port, port_message_info *userInfo,
19457727e08eSIngo Weinhold 	size_t infoSize, uint32 flags, bigtime_t timeout)
19467727e08eSIngo Weinhold {
19477727e08eSIngo Weinhold 	if (userInfo == NULL || infoSize != sizeof(port_message_info))
19487727e08eSIngo Weinhold 		return B_BAD_VALUE;
19497727e08eSIngo Weinhold 
19507727e08eSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
19517727e08eSIngo Weinhold 
19527727e08eSIngo Weinhold 	port_message_info info;
19537727e08eSIngo Weinhold 	status_t error = _get_port_message_info_etc(port, &info, sizeof(info),
19547727e08eSIngo Weinhold 		flags | B_CAN_INTERRUPT, timeout);
19557727e08eSIngo Weinhold 
19567727e08eSIngo Weinhold 	// copy info to userland
19577727e08eSIngo Weinhold 	if (error == B_OK && (!IS_USER_ADDRESS(userInfo)
19587727e08eSIngo Weinhold 			|| user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) {
19597727e08eSIngo Weinhold 		error = B_BAD_ADDRESS;
19607727e08eSIngo Weinhold 	}
19617727e08eSIngo Weinhold 
19627727e08eSIngo Weinhold 	return syscall_restart_handle_timeout_post(error, timeout);
19637727e08eSIngo Weinhold }
1964