xref: /haiku/src/system/kernel/port.cpp (revision 8e56b86bdd555b2d587177ba9df4a03d98868a82)
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>
25*8e56b86bSAugustin Cavalier #include <StackOrHeapArray.h>
2624df6592SIngo Weinhold 
27224aee3fSIngo Weinhold #include <arch/int.h>
28e8885f20SAxel Dörfler #include <heap.h>
294048494cSIngo Weinhold #include <kernel.h>
3051755cf8SAxel Dörfler #include <Notifications.h>
314048494cSIngo Weinhold #include <sem.h>
324048494cSIngo Weinhold #include <syscall_restart.h>
334048494cSIngo Weinhold #include <team.h>
34f28dd36bSAxel Dörfler #include <tracing.h>
35b4ec7b8eSIngo Weinhold #include <util/AutoLock.h>
364048494cSIngo Weinhold #include <util/list.h>
3700f1e7c5SAugustin Cavalier #include <util/iovec_support.h>
387198f765SAxel Dörfler #include <vm/vm.h>
39224aee3fSIngo Weinhold #include <wait_for_objects.h>
40224aee3fSIngo Weinhold 
41224aee3fSIngo Weinhold 
42224aee3fSIngo Weinhold //#define TRACE_PORTS
43224aee3fSIngo Weinhold #ifdef TRACE_PORTS
44224aee3fSIngo Weinhold #	define TRACE(x) dprintf x
45224aee3fSIngo Weinhold #else
46224aee3fSIngo Weinhold #	define TRACE(x)
47224aee3fSIngo Weinhold #endif
48224aee3fSIngo Weinhold 
49224aee3fSIngo Weinhold 
507f64b301SJulian Harnath #if __GNUC__ >= 3
517f64b301SJulian Harnath #	define GCC_2_NRV(x)
527f64b301SJulian Harnath 	// GCC >= 3.1 doesn't need it anymore
537f64b301SJulian Harnath #else
547f64b301SJulian Harnath #	define GCC_2_NRV(x) return x;
557f64b301SJulian Harnath 	// GCC 2 named return value syntax
567f64b301SJulian Harnath 	// see http://gcc.gnu.org/onlinedocs/gcc-2.95.2/gcc_5.html#SEC106
577f64b301SJulian Harnath #endif
587f64b301SJulian Harnath 
597f64b301SJulian Harnath 
6024df6592SIngo Weinhold // Locking:
617f64b301SJulian Harnath // * sPortsLock: Protects the sPorts and sPortsByName hash tables.
627f64b301SJulian Harnath // * sTeamListLock[]: Protects Team::port_list. Lock index for given team is
637f64b301SJulian Harnath //   (Team::id % kTeamListLockCount).
647f64b301SJulian Harnath // * Port::lock: Protects all Port members save team_link, hash_link, lock and
657f64b301SJulian Harnath //   state. id is immutable.
6624df6592SIngo Weinhold //
677f64b301SJulian Harnath // Port::state ensures atomicity by providing a linearization point for adding
687f64b301SJulian Harnath // and removing ports to the hash tables and the team port list.
697f64b301SJulian Harnath // * sPortsLock and sTeamListLock[] are locked separately and not in a nested
707f64b301SJulian Harnath //   fashion, so a port can be in the hash table but not in the team port list
717f64b301SJulian Harnath //   or vice versa. => Without further provisions, insertion and removal are
727f64b301SJulian Harnath //   not linearizable and thus not concurrency-safe.
737f64b301SJulian Harnath // * To make insertion and removal linearizable, Port::state was added. It is
747f64b301SJulian Harnath //   always only accessed atomically and updates are done using
757f64b301SJulian Harnath //   atomic_test_and_set(). A port is only seen as existent when its state is
767f64b301SJulian Harnath //   Port::kActive.
777f64b301SJulian Harnath // * Deletion of ports is done in two steps: logical and physical deletion.
787f64b301SJulian Harnath //   First, logical deletion happens and sets Port::state to Port::kDeleted.
797f64b301SJulian Harnath //   This is an atomic operation and from then on, functions like
807f64b301SJulian Harnath //   get_locked_port() consider this port as deleted and ignore it. Secondly,
817f64b301SJulian Harnath //   physical deletion removes the port from hash tables and team port list.
827f64b301SJulian Harnath //   In a similar way, port creation first inserts into hashes and team list
837f64b301SJulian Harnath //   and only then sets port to Port::kActive.
847f64b301SJulian Harnath //   This creates a linearization point at the atomic update of Port::state,
857f64b301SJulian Harnath //   operations become linearizable and thus concurrency-safe. To help
867f64b301SJulian Harnath //   understanding, the linearization points are annotated with comments.
877f64b301SJulian Harnath // * Ports are reference-counted so it's not a problem when someone still
887f64b301SJulian Harnath //   has a reference to a deleted port.
8924df6592SIngo Weinhold 
9024df6592SIngo Weinhold 
91c73d1301SMichael Lotz namespace {
9224df6592SIngo Weinhold 
93e8885f20SAxel Dörfler struct port_message : DoublyLinkedListLinkImpl<port_message> {
94224aee3fSIngo Weinhold 	int32				code;
95224aee3fSIngo Weinhold 	size_t				size;
967727e08eSIngo Weinhold 	uid_t				sender;
977727e08eSIngo Weinhold 	gid_t				sender_group;
987727e08eSIngo Weinhold 	team_id				sender_team;
99e8885f20SAxel Dörfler 	char				buffer[0];
100e8885f20SAxel Dörfler };
101e8885f20SAxel Dörfler 
102e8885f20SAxel Dörfler typedef DoublyLinkedList<port_message> MessageList;
103224aee3fSIngo Weinhold 
104c73d1301SMichael Lotz } // namespace
105c73d1301SMichael Lotz 
106c73d1301SMichael Lotz 
107c73d1301SMichael Lotz static void put_port_message(port_message* message);
108c73d1301SMichael Lotz 
109c73d1301SMichael Lotz 
110c73d1301SMichael Lotz namespace {
11124df6592SIngo Weinhold 
1127f64b301SJulian Harnath struct Port : public KernelReferenceable {
1137f64b301SJulian Harnath 	enum State {
1147f64b301SJulian Harnath 		kUnused = 0,
1157f64b301SJulian Harnath 		kActive,
1167f64b301SJulian Harnath 		kDeleted
1177f64b301SJulian Harnath 	};
1187f64b301SJulian Harnath 
11986a999adSAxel Dörfler 	struct list_link	team_link;
12024df6592SIngo Weinhold 	Port*				hash_link;
121224aee3fSIngo Weinhold 	port_id				id;
122224aee3fSIngo Weinhold 	team_id				owner;
1237f64b301SJulian Harnath 	Port*				name_hash_link;
1247f64b301SJulian Harnath 	size_t				name_hash;
125224aee3fSIngo Weinhold 	int32				capacity;
126e8885f20SAxel Dörfler 	mutex				lock;
127d0f2d828SPawel Dziepak 	int32				state;
1287d592ec4SAxel Dörfler 	uint32				read_count;
129e8885f20SAxel Dörfler 	int32				write_count;
130e8885f20SAxel Dörfler 	ConditionVariable	read_condition;
131e8885f20SAxel Dörfler 	ConditionVariable	write_condition;
132e8885f20SAxel Dörfler 	int32				total_count;
133e8885f20SAxel Dörfler 		// messages read from port since creation
134224aee3fSIngo Weinhold 	select_info*		select_infos;
135e8885f20SAxel Dörfler 	MessageList			messages;
13624df6592SIngo Weinhold 
Port__anone3cefd910211::Port1373c47c28aSAugustin Cavalier 	Port(team_id owner, int32 queueLength, const char* name)
13824df6592SIngo Weinhold 		:
13924df6592SIngo Weinhold 		owner(owner),
1407f64b301SJulian Harnath 		name_hash(0),
14124df6592SIngo Weinhold 		capacity(queueLength),
1427f64b301SJulian Harnath 		state(kUnused),
14324df6592SIngo Weinhold 		read_count(0),
14424df6592SIngo Weinhold 		write_count(queueLength),
14524df6592SIngo Weinhold 		total_count(0),
14624df6592SIngo Weinhold 		select_infos(NULL)
14724df6592SIngo Weinhold 	{
14824df6592SIngo Weinhold 		// id is initialized when the caller adds the port to the hash table
14924df6592SIngo Weinhold 
1503c47c28aSAugustin Cavalier 		mutex_init_etc(&lock, name, MUTEX_FLAG_CLONE_NAME);
15124df6592SIngo Weinhold 		read_condition.Init(this, "port read");
15224df6592SIngo Weinhold 		write_condition.Init(this, "port write");
15324df6592SIngo Weinhold 	}
15424df6592SIngo Weinhold 
~Port__anone3cefd910211::Port1557f64b301SJulian Harnath 	virtual ~Port()
15624df6592SIngo Weinhold 	{
15724df6592SIngo Weinhold 		while (port_message* message = messages.RemoveHead())
15824df6592SIngo Weinhold 			put_port_message(message);
15924df6592SIngo Weinhold 
1603c47c28aSAugustin Cavalier 		mutex_destroy(&lock);
16124df6592SIngo Weinhold 	}
162224aee3fSIngo Weinhold };
163224aee3fSIngo Weinhold 
16424df6592SIngo Weinhold 
16524df6592SIngo Weinhold struct PortHashDefinition {
16624df6592SIngo Weinhold 	typedef port_id		KeyType;
16724df6592SIngo Weinhold 	typedef	Port		ValueType;
16824df6592SIngo Weinhold 
HashKey__anone3cefd910211::PortHashDefinition16924df6592SIngo Weinhold 	size_t HashKey(port_id key) const
17024df6592SIngo Weinhold 	{
17124df6592SIngo Weinhold 		return key;
17224df6592SIngo Weinhold 	}
17324df6592SIngo Weinhold 
Hash__anone3cefd910211::PortHashDefinition17424df6592SIngo Weinhold 	size_t Hash(Port* value) const
17524df6592SIngo Weinhold 	{
17624df6592SIngo Weinhold 		return HashKey(value->id);
17724df6592SIngo Weinhold 	}
17824df6592SIngo Weinhold 
Compare__anone3cefd910211::PortHashDefinition17924df6592SIngo Weinhold 	bool Compare(port_id key, Port* value) const
18024df6592SIngo Weinhold 	{
18124df6592SIngo Weinhold 		return value->id == key;
18224df6592SIngo Weinhold 	}
18324df6592SIngo Weinhold 
GetLink__anone3cefd910211::PortHashDefinition18424df6592SIngo Weinhold 	Port*& GetLink(Port* value) const
18524df6592SIngo Weinhold 	{
18624df6592SIngo Weinhold 		return value->hash_link;
18724df6592SIngo Weinhold 	}
18824df6592SIngo Weinhold };
18924df6592SIngo Weinhold 
19024df6592SIngo Weinhold typedef BOpenHashTable<PortHashDefinition> PortHashTable;
19124df6592SIngo Weinhold 
19224df6592SIngo Weinhold 
1937f64b301SJulian Harnath struct PortNameHashDefinition {
1947f64b301SJulian Harnath 	typedef const char*	KeyType;
1957f64b301SJulian Harnath 	typedef	Port		ValueType;
1967f64b301SJulian Harnath 
HashKey__anone3cefd910211::PortNameHashDefinition1977f64b301SJulian Harnath 	size_t HashKey(const char* key) const
1987f64b301SJulian Harnath 	{
1997f64b301SJulian Harnath 		// Hash function: hash(key) =  key[0] * 31^(length - 1)
2007f64b301SJulian Harnath 		//   + key[1] * 31^(length - 2) + ... + key[length - 1]
2017f64b301SJulian Harnath 
2027f64b301SJulian Harnath 		const size_t length = strlen(key);
2037f64b301SJulian Harnath 
2047f64b301SJulian Harnath 		size_t hash = 0;
2057f64b301SJulian Harnath 		for (size_t index = 0; index < length; index++)
2067f64b301SJulian Harnath 			hash = 31 * hash + key[index];
2077f64b301SJulian Harnath 
2087f64b301SJulian Harnath 		return hash;
2097f64b301SJulian Harnath 	}
2107f64b301SJulian Harnath 
Hash__anone3cefd910211::PortNameHashDefinition2117f64b301SJulian Harnath 	size_t Hash(Port* value) const
2127f64b301SJulian Harnath 	{
2137f64b301SJulian Harnath 		size_t& hash = value->name_hash;
2147f64b301SJulian Harnath 		if (hash == 0)
2157f64b301SJulian Harnath 			hash = HashKey(value->lock.name);
2167f64b301SJulian Harnath 		return hash;
2177f64b301SJulian Harnath 	}
2187f64b301SJulian Harnath 
Compare__anone3cefd910211::PortNameHashDefinition2197f64b301SJulian Harnath 	bool Compare(const char* key, Port* value) const
2207f64b301SJulian Harnath 	{
2217f64b301SJulian Harnath 		return (strcmp(key, value->lock.name) == 0);
2227f64b301SJulian Harnath 	}
2237f64b301SJulian Harnath 
GetLink__anone3cefd910211::PortNameHashDefinition2247f64b301SJulian Harnath 	Port*& GetLink(Port* value) const
2257f64b301SJulian Harnath 	{
2267f64b301SJulian Harnath 		return value->name_hash_link;
2277f64b301SJulian Harnath 	}
2287f64b301SJulian Harnath };
2297f64b301SJulian Harnath 
2307f64b301SJulian Harnath typedef BOpenHashTable<PortNameHashDefinition> PortNameHashTable;
2317f64b301SJulian Harnath 
2327f64b301SJulian Harnath 
23351755cf8SAxel Dörfler class PortNotificationService : public DefaultNotificationService {
23451755cf8SAxel Dörfler public:
23551755cf8SAxel Dörfler 							PortNotificationService();
23651755cf8SAxel Dörfler 
23751755cf8SAxel Dörfler 			void			Notify(uint32 opcode, port_id team);
23851755cf8SAxel Dörfler };
239224aee3fSIngo Weinhold 
240c73d1301SMichael Lotz } // namespace
241c73d1301SMichael Lotz 
242f28dd36bSAxel Dörfler 
2437f64b301SJulian Harnath // #pragma mark - tracing
2447f64b301SJulian Harnath 
2457f64b301SJulian Harnath 
246f28dd36bSAxel Dörfler #if PORT_TRACING
247f28dd36bSAxel Dörfler namespace PortTracing {
248f28dd36bSAxel Dörfler 
249f28dd36bSAxel Dörfler class Create : public AbstractTraceEntry {
250f28dd36bSAxel Dörfler public:
Create(Port * port)25124df6592SIngo Weinhold 	Create(Port* port)
252f28dd36bSAxel Dörfler 		:
25324df6592SIngo Weinhold 		fID(port->id),
25424df6592SIngo Weinhold 		fOwner(port->owner),
25524df6592SIngo Weinhold 		fCapacity(port->capacity)
256f28dd36bSAxel Dörfler 	{
25724df6592SIngo Weinhold 		fName = alloc_tracing_buffer_strcpy(port->lock.name, B_OS_NAME_LENGTH,
258f28dd36bSAxel Dörfler 			false);
259f28dd36bSAxel Dörfler 
260f28dd36bSAxel Dörfler 		Initialized();
261f28dd36bSAxel Dörfler 	}
262f28dd36bSAxel Dörfler 
AddDump(TraceOutput & out)263f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
264f28dd36bSAxel Dörfler 	{
265f28dd36bSAxel Dörfler 		out.Print("port %ld created, name \"%s\", owner %ld, capacity %ld",
266f28dd36bSAxel Dörfler 			fID, fName, fOwner, fCapacity);
267f28dd36bSAxel Dörfler 	}
268f28dd36bSAxel Dörfler 
269f28dd36bSAxel Dörfler private:
270f28dd36bSAxel Dörfler 	port_id				fID;
271f28dd36bSAxel Dörfler 	char*				fName;
272f28dd36bSAxel Dörfler 	team_id				fOwner;
273f28dd36bSAxel Dörfler 	int32		 		fCapacity;
274f28dd36bSAxel Dörfler };
275f28dd36bSAxel Dörfler 
276f28dd36bSAxel Dörfler 
277f28dd36bSAxel Dörfler class Delete : public AbstractTraceEntry {
278f28dd36bSAxel Dörfler public:
Delete(Port * port)27924df6592SIngo Weinhold 	Delete(Port* port)
280f28dd36bSAxel Dörfler 		:
28124df6592SIngo Weinhold 		fID(port->id)
282f28dd36bSAxel Dörfler 	{
283f28dd36bSAxel Dörfler 		Initialized();
284f28dd36bSAxel Dörfler 	}
285f28dd36bSAxel Dörfler 
AddDump(TraceOutput & out)286f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
287f28dd36bSAxel Dörfler 	{
288f28dd36bSAxel Dörfler 		out.Print("port %ld deleted", fID);
289f28dd36bSAxel Dörfler 	}
290f28dd36bSAxel Dörfler 
291f28dd36bSAxel Dörfler private:
292f28dd36bSAxel Dörfler 	port_id				fID;
293f28dd36bSAxel Dörfler };
294f28dd36bSAxel Dörfler 
295f28dd36bSAxel Dörfler 
296f28dd36bSAxel Dörfler class Read : public AbstractTraceEntry {
297f28dd36bSAxel Dörfler public:
Read(const BReference<Port> & portRef,int32 code,ssize_t result)298748c0f30SAxel Dörfler 	Read(const BReference<Port>& portRef, int32 code, ssize_t result)
299748c0f30SAxel Dörfler 		:
300748c0f30SAxel Dörfler 		fID(portRef->id),
301748c0f30SAxel Dörfler 		fReadCount(portRef->read_count),
302748c0f30SAxel Dörfler 		fWriteCount(portRef->write_count),
303748c0f30SAxel Dörfler 		fCode(code),
304748c0f30SAxel Dörfler 		fResult(result)
305748c0f30SAxel Dörfler 	{
306748c0f30SAxel Dörfler 		Initialized();
307748c0f30SAxel Dörfler 	}
308748c0f30SAxel Dörfler 
Read(port_id id,int32 readCount,int32 writeCount,int32 code,ssize_t result)30924df6592SIngo Weinhold 	Read(port_id id, int32 readCount, int32 writeCount, int32 code,
31024df6592SIngo Weinhold 		ssize_t result)
311f28dd36bSAxel Dörfler 		:
31224df6592SIngo Weinhold 		fID(id),
31324df6592SIngo Weinhold 		fReadCount(readCount),
31424df6592SIngo Weinhold 		fWriteCount(writeCount),
315f28dd36bSAxel Dörfler 		fCode(code),
316f28dd36bSAxel Dörfler 		fResult(result)
317f28dd36bSAxel Dörfler 	{
318f28dd36bSAxel Dörfler 		Initialized();
319f28dd36bSAxel Dörfler 	}
320f28dd36bSAxel Dörfler 
AddDump(TraceOutput & out)321f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
322f28dd36bSAxel Dörfler 	{
323f28dd36bSAxel Dörfler 		out.Print("port %ld read, read %ld, write %ld, code %lx: %ld",
324f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fResult);
325f28dd36bSAxel Dörfler 	}
326f28dd36bSAxel Dörfler 
327f28dd36bSAxel Dörfler private:
328f28dd36bSAxel Dörfler 	port_id				fID;
329f28dd36bSAxel Dörfler 	int32				fReadCount;
330f28dd36bSAxel Dörfler 	int32				fWriteCount;
331f28dd36bSAxel Dörfler 	int32				fCode;
332f28dd36bSAxel Dörfler 	ssize_t				fResult;
333f28dd36bSAxel Dörfler };
334f28dd36bSAxel Dörfler 
335f28dd36bSAxel Dörfler 
336f28dd36bSAxel Dörfler class Write : public AbstractTraceEntry {
337f28dd36bSAxel Dörfler public:
Write(port_id id,int32 readCount,int32 writeCount,int32 code,size_t bufferSize,ssize_t result)33824df6592SIngo Weinhold 	Write(port_id id, int32 readCount, int32 writeCount, int32 code,
33924df6592SIngo Weinhold 		size_t bufferSize, ssize_t result)
340f28dd36bSAxel Dörfler 		:
34124df6592SIngo Weinhold 		fID(id),
34224df6592SIngo Weinhold 		fReadCount(readCount),
34324df6592SIngo Weinhold 		fWriteCount(writeCount),
344f28dd36bSAxel Dörfler 		fCode(code),
345f28dd36bSAxel Dörfler 		fBufferSize(bufferSize),
346f28dd36bSAxel Dörfler 		fResult(result)
347f28dd36bSAxel Dörfler 	{
348f28dd36bSAxel Dörfler 		Initialized();
349f28dd36bSAxel Dörfler 	}
350f28dd36bSAxel Dörfler 
AddDump(TraceOutput & out)351f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
352f28dd36bSAxel Dörfler 	{
353f28dd36bSAxel Dörfler 		out.Print("port %ld write, read %ld, write %ld, code %lx, size %ld: %ld",
354f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fBufferSize, fResult);
355f28dd36bSAxel Dörfler 	}
356f28dd36bSAxel Dörfler 
357f28dd36bSAxel Dörfler private:
358f28dd36bSAxel Dörfler 	port_id				fID;
359f28dd36bSAxel Dörfler 	int32				fReadCount;
360f28dd36bSAxel Dörfler 	int32				fWriteCount;
361f28dd36bSAxel Dörfler 	int32				fCode;
362f28dd36bSAxel Dörfler 	size_t				fBufferSize;
363f28dd36bSAxel Dörfler 	ssize_t				fResult;
364f28dd36bSAxel Dörfler };
365f28dd36bSAxel Dörfler 
366f28dd36bSAxel Dörfler 
367f28dd36bSAxel Dörfler class Info : public AbstractTraceEntry {
368f28dd36bSAxel Dörfler public:
Info(const BReference<Port> & portRef,int32 code,ssize_t result)369748c0f30SAxel Dörfler 	Info(const BReference<Port>& portRef, int32 code, ssize_t result)
370748c0f30SAxel Dörfler 		:
371748c0f30SAxel Dörfler 		fID(portRef->id),
372748c0f30SAxel Dörfler 		fReadCount(portRef->read_count),
373748c0f30SAxel Dörfler 		fWriteCount(portRef->write_count),
374748c0f30SAxel Dörfler 		fCode(code),
375748c0f30SAxel Dörfler 		fResult(result)
376748c0f30SAxel Dörfler 	{
377748c0f30SAxel Dörfler 		Initialized();
378748c0f30SAxel Dörfler 	}
379748c0f30SAxel Dörfler 
Info(port_id id,int32 readCount,int32 writeCount,int32 code,ssize_t result)38024df6592SIngo Weinhold 	Info(port_id id, int32 readCount, int32 writeCount, int32 code,
38124df6592SIngo Weinhold 		ssize_t result)
382f28dd36bSAxel Dörfler 		:
38324df6592SIngo Weinhold 		fID(id),
38424df6592SIngo Weinhold 		fReadCount(readCount),
38524df6592SIngo Weinhold 		fWriteCount(writeCount),
386f28dd36bSAxel Dörfler 		fCode(code),
387f28dd36bSAxel Dörfler 		fResult(result)
388f28dd36bSAxel Dörfler 	{
389f28dd36bSAxel Dörfler 		Initialized();
390f28dd36bSAxel Dörfler 	}
391f28dd36bSAxel Dörfler 
AddDump(TraceOutput & out)392f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
393f28dd36bSAxel Dörfler 	{
394f28dd36bSAxel Dörfler 		out.Print("port %ld info, read %ld, write %ld, code %lx: %ld",
395f28dd36bSAxel Dörfler 			fID, fReadCount, fWriteCount, fCode, fResult);
396f28dd36bSAxel Dörfler 	}
397f28dd36bSAxel Dörfler 
398f28dd36bSAxel Dörfler private:
399f28dd36bSAxel Dörfler 	port_id				fID;
400f28dd36bSAxel Dörfler 	int32				fReadCount;
401f28dd36bSAxel Dörfler 	int32				fWriteCount;
402f28dd36bSAxel Dörfler 	int32				fCode;
403f28dd36bSAxel Dörfler 	ssize_t				fResult;
404f28dd36bSAxel Dörfler };
405f28dd36bSAxel Dörfler 
406f28dd36bSAxel Dörfler 
407f28dd36bSAxel Dörfler class OwnerChange : public AbstractTraceEntry {
408f28dd36bSAxel Dörfler public:
OwnerChange(Port * port,team_id newOwner,status_t status)40924df6592SIngo Weinhold 	OwnerChange(Port* port, team_id newOwner, status_t status)
410f28dd36bSAxel Dörfler 		:
41124df6592SIngo Weinhold 		fID(port->id),
41224df6592SIngo Weinhold 		fOldOwner(port->owner),
413f28dd36bSAxel Dörfler 		fNewOwner(newOwner),
414f28dd36bSAxel Dörfler 		fStatus(status)
415f28dd36bSAxel Dörfler 	{
416f28dd36bSAxel Dörfler 		Initialized();
417f28dd36bSAxel Dörfler 	}
418f28dd36bSAxel Dörfler 
AddDump(TraceOutput & out)419f28dd36bSAxel Dörfler 	virtual void AddDump(TraceOutput& out)
420f28dd36bSAxel Dörfler 	{
421f28dd36bSAxel Dörfler 		out.Print("port %ld owner change from %ld to %ld: %s", fID, fOldOwner,
422f28dd36bSAxel Dörfler 			fNewOwner, strerror(fStatus));
423f28dd36bSAxel Dörfler 	}
424f28dd36bSAxel Dörfler 
425f28dd36bSAxel Dörfler private:
426f28dd36bSAxel Dörfler 	port_id				fID;
427f28dd36bSAxel Dörfler 	team_id				fOldOwner;
428f28dd36bSAxel Dörfler 	team_id				fNewOwner;
429f28dd36bSAxel Dörfler 	status_t	 		fStatus;
430f28dd36bSAxel Dörfler };
431f28dd36bSAxel Dörfler 
432f28dd36bSAxel Dörfler }	// namespace PortTracing
433f28dd36bSAxel Dörfler 
434f28dd36bSAxel Dörfler #	define T(x) new(std::nothrow) PortTracing::x;
435f28dd36bSAxel Dörfler #else
436f28dd36bSAxel Dörfler #	define T(x) ;
437f28dd36bSAxel Dörfler #endif
438f28dd36bSAxel Dörfler 
439f28dd36bSAxel Dörfler 
440e8885f20SAxel Dörfler static const size_t kInitialPortBufferSize = 4 * 1024 * 1024;
441f28dd36bSAxel Dörfler static const size_t kTotalSpaceLimit = 64 * 1024 * 1024;
442f28dd36bSAxel Dörfler static const size_t kTeamSpaceLimit = 8 * 1024 * 1024;
443f28dd36bSAxel Dörfler static const size_t kBufferGrowRate = kInitialPortBufferSize;
444f28dd36bSAxel Dörfler 
445224aee3fSIngo Weinhold #define MAX_QUEUE_LENGTH 4096
4465f87692cSIngo Weinhold #define PORT_MAX_MESSAGE_SIZE (256 * 1024)
447224aee3fSIngo Weinhold 
448224aee3fSIngo Weinhold static int32 sMaxPorts = 4096;
449d0f2d828SPawel Dziepak static int32 sUsedPorts;
450224aee3fSIngo Weinhold 
45124df6592SIngo Weinhold static PortHashTable sPorts;
4527f64b301SJulian Harnath static PortNameHashTable sPortsByName;
453f28dd36bSAxel Dörfler static ConditionVariable sNoSpaceCondition;
454d0f2d828SPawel Dziepak static int32 sTotalSpaceCommited;
455cd3e02caSMichael Lotz static int32 sWaitingForSpace;
45624df6592SIngo Weinhold static port_id sNextPortID = 1;
457224aee3fSIngo Weinhold static bool sPortsActive = false;
4587f64b301SJulian Harnath static rw_lock sPortsLock = RW_LOCK_INITIALIZER("ports list");
4597f64b301SJulian Harnath 
4607f64b301SJulian Harnath enum {
4617f64b301SJulian Harnath 	kTeamListLockCount = 8
4627f64b301SJulian Harnath };
4637f64b301SJulian Harnath 
4647f64b301SJulian Harnath static mutex sTeamListLock[kTeamListLockCount] = {
4657f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 1"),
4667f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 2"),
4677f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 3"),
4687f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 4"),
4697f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 5"),
4707f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 6"),
4717f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 7"),
4727f64b301SJulian Harnath 	MUTEX_INITIALIZER("team ports list 8")
4737f64b301SJulian Harnath };
474224aee3fSIngo Weinhold 
47551755cf8SAxel Dörfler static PortNotificationService sNotificationService;
47651755cf8SAxel Dörfler 
477224aee3fSIngo Weinhold 
47851755cf8SAxel Dörfler //	#pragma mark - TeamNotificationService
47951755cf8SAxel Dörfler 
48051755cf8SAxel Dörfler 
PortNotificationService()48151755cf8SAxel Dörfler PortNotificationService::PortNotificationService()
482e8885f20SAxel Dörfler 	:
483e8885f20SAxel Dörfler 	DefaultNotificationService("ports")
48451755cf8SAxel Dörfler {
48551755cf8SAxel Dörfler }
48651755cf8SAxel Dörfler 
48751755cf8SAxel Dörfler 
48851755cf8SAxel Dörfler void
Notify(uint32 opcode,port_id port)48951755cf8SAxel Dörfler PortNotificationService::Notify(uint32 opcode, port_id port)
49051755cf8SAxel Dörfler {
491fae2ce19SIngo Weinhold 	char eventBuffer[128];
49251755cf8SAxel Dörfler 	KMessage event;
49351755cf8SAxel Dörfler 	event.SetTo(eventBuffer, sizeof(eventBuffer), PORT_MONITOR);
494efd536ffSIngo Weinhold 	event.AddInt32("event", opcode);
49551755cf8SAxel Dörfler 	event.AddInt32("port", port);
49651755cf8SAxel Dörfler 
497efd536ffSIngo Weinhold 	DefaultNotificationService::Notify(event, opcode);
49851755cf8SAxel Dörfler }
49951755cf8SAxel Dörfler 
50051755cf8SAxel Dörfler 
5017f64b301SJulian Harnath //	#pragma mark - debugger commands
50251755cf8SAxel Dörfler 
50351755cf8SAxel Dörfler 
504224aee3fSIngo Weinhold static int
dump_port_list(int argc,char ** argv)505224aee3fSIngo Weinhold dump_port_list(int argc, char** argv)
506224aee3fSIngo Weinhold {
507224aee3fSIngo Weinhold 	const char* name = NULL;
508224aee3fSIngo Weinhold 	team_id owner = -1;
509224aee3fSIngo Weinhold 
510224aee3fSIngo Weinhold 	if (argc > 2) {
511224aee3fSIngo Weinhold 		if (!strcmp(argv[1], "team") || !strcmp(argv[1], "owner"))
512224aee3fSIngo Weinhold 			owner = strtoul(argv[2], NULL, 0);
513224aee3fSIngo Weinhold 		else if (!strcmp(argv[1], "name"))
514224aee3fSIngo Weinhold 			name = argv[2];
515224aee3fSIngo Weinhold 	} else if (argc > 1)
516224aee3fSIngo Weinhold 		owner = strtoul(argv[1], NULL, 0);
517224aee3fSIngo Weinhold 
518e8885f20SAxel Dörfler 	kprintf("port             id  cap  read-cnt  write-cnt   total   team  "
519e8885f20SAxel Dörfler 		"name\n");
520224aee3fSIngo Weinhold 
52124df6592SIngo Weinhold 	for (PortHashTable::Iterator it = sPorts.GetIterator();
52224df6592SIngo Weinhold 		Port* port = it.Next();) {
52324df6592SIngo Weinhold 		if ((owner != -1 && port->owner != owner)
524e8885f20SAxel Dörfler 			|| (name != NULL && strstr(port->lock.name, name) == NULL))
525224aee3fSIngo Weinhold 			continue;
526224aee3fSIngo Weinhold 
5270e88a887SAlex Smith 		kprintf("%p %8" B_PRId32 " %4" B_PRId32 " %9" B_PRIu32 " %9" B_PRId32
5280e88a887SAlex Smith 			" %8" B_PRId32 " %6" B_PRId32 "  %s\n", port, port->id,
5290e88a887SAlex Smith 			port->capacity, port->read_count, port->write_count,
530e8885f20SAxel Dörfler 			port->total_count, port->owner, port->lock.name);
531224aee3fSIngo Weinhold 	}
532e8885f20SAxel Dörfler 
533224aee3fSIngo Weinhold 	return 0;
534224aee3fSIngo Weinhold }
535224aee3fSIngo Weinhold 
536224aee3fSIngo Weinhold 
537224aee3fSIngo Weinhold static void
_dump_port_info(Port * port)53824df6592SIngo Weinhold _dump_port_info(Port* port)
539224aee3fSIngo Weinhold {
540224aee3fSIngo Weinhold 	kprintf("PORT: %p\n", port);
5410e88a887SAlex Smith 	kprintf(" id:              %" B_PRId32 "\n", port->id);
542e8885f20SAxel Dörfler 	kprintf(" name:            \"%s\"\n", port->lock.name);
5430e88a887SAlex Smith 	kprintf(" owner:           %" B_PRId32 "\n", port->owner);
5440e88a887SAlex Smith 	kprintf(" capacity:        %" B_PRId32 "\n", port->capacity);
5450e88a887SAlex Smith 	kprintf(" read_count:      %" B_PRIu32 "\n", port->read_count);
5460e88a887SAlex Smith 	kprintf(" write_count:     %" B_PRId32 "\n", port->write_count);
5470e88a887SAlex Smith 	kprintf(" total count:     %" B_PRId32 "\n", port->total_count);
5485aee691eSIngo Weinhold 
549f28dd36bSAxel Dörfler 	if (!port->messages.IsEmpty()) {
550f28dd36bSAxel Dörfler 		kprintf("messages:\n");
551f28dd36bSAxel Dörfler 
552f28dd36bSAxel Dörfler 		MessageList::Iterator iterator = port->messages.GetIterator();
553f28dd36bSAxel Dörfler 		while (port_message* message = iterator.Next()) {
5540e88a887SAlex Smith 			kprintf(" %p  %08" B_PRIx32 "  %ld\n", message, message->code, message->size);
555f28dd36bSAxel Dörfler 		}
556f28dd36bSAxel Dörfler 	}
557f28dd36bSAxel Dörfler 
5585aee691eSIngo Weinhold 	set_debug_variable("_port", (addr_t)port);
5595aee691eSIngo Weinhold 	set_debug_variable("_portID", port->id);
5605aee691eSIngo Weinhold 	set_debug_variable("_owner", port->owner);
561224aee3fSIngo Weinhold }
562224aee3fSIngo Weinhold 
563224aee3fSIngo Weinhold 
564224aee3fSIngo Weinhold static int
dump_port_info(int argc,char ** argv)565224aee3fSIngo Weinhold dump_port_info(int argc, char** argv)
566224aee3fSIngo Weinhold {
567e8885f20SAxel Dörfler 	ConditionVariable* condition = NULL;
568f28dd36bSAxel Dörfler 	const char* name = NULL;
569224aee3fSIngo Weinhold 
570224aee3fSIngo Weinhold 	if (argc < 2) {
571ce637fdaSIngo Weinhold 		print_debugger_command_usage(argv[0]);
572224aee3fSIngo Weinhold 		return 0;
573224aee3fSIngo Weinhold 	}
574224aee3fSIngo Weinhold 
575224aee3fSIngo Weinhold 	if (argc > 2) {
576224aee3fSIngo Weinhold 		if (!strcmp(argv[1], "address")) {
57724df6592SIngo Weinhold 			_dump_port_info((Port*)parse_expression(argv[2]));
578224aee3fSIngo Weinhold 			return 0;
579e8885f20SAxel Dörfler 		} else if (!strcmp(argv[1], "condition"))
580f28dd36bSAxel Dörfler 			condition = (ConditionVariable*)parse_expression(argv[2]);
581224aee3fSIngo Weinhold 		else if (!strcmp(argv[1], "name"))
582224aee3fSIngo Weinhold 			name = argv[2];
583f28dd36bSAxel Dörfler 	} else if (parse_expression(argv[1]) > 0) {
584224aee3fSIngo Weinhold 		// if the argument looks like a number, treat it as such
585f28dd36bSAxel Dörfler 		int32 num = parse_expression(argv[1]);
58624df6592SIngo Weinhold 		Port* port = sPorts.Lookup(num);
5877f64b301SJulian Harnath 		if (port == NULL || port->state != Port::kActive) {
5880e88a887SAlex Smith 			kprintf("port %" B_PRId32 " (%#" B_PRIx32 ") doesn't exist!\n",
5890e88a887SAlex Smith 				num, num);
590224aee3fSIngo Weinhold 			return 0;
591224aee3fSIngo Weinhold 		}
59224df6592SIngo Weinhold 		_dump_port_info(port);
593224aee3fSIngo Weinhold 		return 0;
594224aee3fSIngo Weinhold 	} else
595224aee3fSIngo Weinhold 		name = argv[1];
596224aee3fSIngo Weinhold 
597224aee3fSIngo Weinhold 	// walk through the ports list, trying to match name
59824df6592SIngo Weinhold 	for (PortHashTable::Iterator it = sPorts.GetIterator();
59924df6592SIngo Weinhold 		Port* port = it.Next();) {
60024df6592SIngo Weinhold 		if ((name != NULL && port->lock.name != NULL
60124df6592SIngo Weinhold 				&& !strcmp(name, port->lock.name))
60224df6592SIngo Weinhold 			|| (condition != NULL && (&port->read_condition == condition
60324df6592SIngo Weinhold 				|| &port->write_condition == condition))) {
60424df6592SIngo Weinhold 			_dump_port_info(port);
605224aee3fSIngo Weinhold 			return 0;
606224aee3fSIngo Weinhold 		}
607224aee3fSIngo Weinhold 	}
608224aee3fSIngo Weinhold 
609224aee3fSIngo Weinhold 	return 0;
610224aee3fSIngo Weinhold }
611224aee3fSIngo Weinhold 
612224aee3fSIngo Weinhold 
6137f64b301SJulian Harnath // #pragma mark - internal helper functions
6147f64b301SJulian Harnath 
6157f64b301SJulian Harnath 
61624df6592SIngo Weinhold /*!	Notifies the port's select events.
61724df6592SIngo Weinhold 	The port must be locked.
61824df6592SIngo Weinhold */
619224aee3fSIngo Weinhold static void
notify_port_select_events(Port * port,uint16 events)62024df6592SIngo Weinhold notify_port_select_events(Port* port, uint16 events)
621224aee3fSIngo Weinhold {
62224df6592SIngo Weinhold 	if (port->select_infos)
62324df6592SIngo Weinhold 		notify_select_events_list(port->select_infos, events);
624224aee3fSIngo Weinhold }
625224aee3fSIngo Weinhold 
626224aee3fSIngo Weinhold 
6277f64b301SJulian Harnath static BReference<Port>
get_locked_port(port_id id)6287f64b301SJulian Harnath get_locked_port(port_id id) GCC_2_NRV(portRef)
629cd3e02caSMichael Lotz {
6307f64b301SJulian Harnath #if __GNUC__ >= 3
6317f64b301SJulian Harnath 	BReference<Port> portRef;
6327f64b301SJulian Harnath #endif
6337f64b301SJulian Harnath 	{
6347f64b301SJulian Harnath 		ReadLocker portsLocker(sPortsLock);
6357f64b301SJulian Harnath 		portRef.SetTo(sPorts.Lookup(id));
6367f64b301SJulian Harnath 	}
637cd3e02caSMichael Lotz 
638057719efSAugustin Cavalier 	if (portRef != NULL && portRef->state == Port::kActive) {
639057719efSAugustin Cavalier 		if (mutex_lock(&portRef->lock) != B_OK)
640057719efSAugustin Cavalier 			portRef.Unset();
641057719efSAugustin Cavalier 	} else
6427f64b301SJulian Harnath 		portRef.Unset();
6437f64b301SJulian Harnath 
6447f64b301SJulian Harnath 	return portRef;
6457f64b301SJulian Harnath }
6467f64b301SJulian Harnath 
6477f64b301SJulian Harnath 
6487f64b301SJulian Harnath static BReference<Port>
get_port(port_id id)6497f64b301SJulian Harnath get_port(port_id id) GCC_2_NRV(portRef)
6507f64b301SJulian Harnath {
6517f64b301SJulian Harnath #if __GNUC__ >= 3
6527f64b301SJulian Harnath 	BReference<Port> portRef;
6537f64b301SJulian Harnath #endif
6547f64b301SJulian Harnath 	ReadLocker portsLocker(sPortsLock);
6557f64b301SJulian Harnath 	portRef.SetTo(sPorts.Lookup(id));
6567f64b301SJulian Harnath 
6577f64b301SJulian Harnath 	return portRef;
658cd3e02caSMichael Lotz }
659cd3e02caSMichael Lotz 
660cd3e02caSMichael Lotz 
661cd3e02caSMichael Lotz /*!	You need to own the port's lock when calling this function */
662cd3e02caSMichael Lotz static inline bool
is_port_closed(Port * port)663cd3e02caSMichael Lotz is_port_closed(Port* port)
664cd3e02caSMichael Lotz {
665cd3e02caSMichael Lotz 	return port->capacity == 0;
666cd3e02caSMichael Lotz }
667cd3e02caSMichael Lotz 
668cd3e02caSMichael Lotz 
669224aee3fSIngo Weinhold static void
put_port_message(port_message * message)670e8885f20SAxel Dörfler put_port_message(port_message* message)
671224aee3fSIngo Weinhold {
6727f64b301SJulian Harnath 	const size_t size = sizeof(port_message) + message->size;
6737f64b301SJulian Harnath 	free(message);
674f28dd36bSAxel Dörfler 
6757f64b301SJulian Harnath 	atomic_add(&sTotalSpaceCommited, -size);
676cd3e02caSMichael Lotz 	if (sWaitingForSpace > 0)
677f28dd36bSAxel Dörfler 		sNoSpaceCondition.NotifyAll();
678224aee3fSIngo Weinhold }
679224aee3fSIngo Weinhold 
680224aee3fSIngo Weinhold 
6817f64b301SJulian Harnath /*! Port must be locked. */
682f28dd36bSAxel Dörfler static status_t
get_port_message(int32 code,size_t bufferSize,uint32 flags,bigtime_t timeout,port_message ** _message,Port & port)683f28dd36bSAxel Dörfler get_port_message(int32 code, size_t bufferSize, uint32 flags, bigtime_t timeout,
684cd3e02caSMichael Lotz 	port_message** _message, Port& port)
685224aee3fSIngo Weinhold {
6867f64b301SJulian Harnath 	const size_t size = sizeof(port_message) + bufferSize;
687f28dd36bSAxel Dörfler 
688f28dd36bSAxel Dörfler 	while (true) {
6897f64b301SJulian Harnath 		int32 previouslyCommited = atomic_add(&sTotalSpaceCommited, size);
6907f64b301SJulian Harnath 
6917f64b301SJulian Harnath 		while (previouslyCommited + size > kTotalSpaceLimit) {
692f28dd36bSAxel Dörfler 			// TODO: add per team limit
6937f64b301SJulian Harnath 
6947f64b301SJulian Harnath 			// We are not allowed to allocate more memory, as our
695f28dd36bSAxel Dörfler 			// space limit has been reached - just wait until we get
696f28dd36bSAxel Dörfler 			// some free space again.
697f28dd36bSAxel Dörfler 
6987f64b301SJulian Harnath 			atomic_add(&sTotalSpaceCommited, -size);
6997f64b301SJulian Harnath 
700f28dd36bSAxel Dörfler 			// TODO: we don't want to wait - but does that also mean we
7017f64b301SJulian Harnath 			// shouldn't wait for free memory?
702cd3e02caSMichael Lotz 			if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
703f28dd36bSAxel Dörfler 				return B_WOULD_BLOCK;
704f28dd36bSAxel Dörfler 
705f28dd36bSAxel Dörfler 			ConditionVariableEntry entry;
706f28dd36bSAxel Dörfler 			sNoSpaceCondition.Add(&entry);
707f28dd36bSAxel Dörfler 
708cd3e02caSMichael Lotz 			port_id portID = port.id;
709cd3e02caSMichael Lotz 			mutex_unlock(&port.lock);
710f28dd36bSAxel Dörfler 
7117f64b301SJulian Harnath 			atomic_add(&sWaitingForSpace, 1);
7127f64b301SJulian Harnath 
7137f64b301SJulian Harnath 			// TODO: right here the condition could be notified and we'd
7147f64b301SJulian Harnath 			//       miss it.
7157f64b301SJulian Harnath 
716f28dd36bSAxel Dörfler 			status_t status = entry.Wait(flags, timeout);
717cd3e02caSMichael Lotz 
7187f64b301SJulian Harnath 			atomic_add(&sWaitingForSpace, -1);
719cd3e02caSMichael Lotz 
7207f64b301SJulian Harnath 			// re-lock the port
7217f64b301SJulian Harnath 			BReference<Port> newPortRef = get_locked_port(portID);
7227f64b301SJulian Harnath 
7237f64b301SJulian Harnath 			if (newPortRef.Get() != &port || is_port_closed(&port)) {
724cd3e02caSMichael Lotz 				// the port is no longer usable
725cd3e02caSMichael Lotz 				return B_BAD_PORT_ID;
726cd3e02caSMichael Lotz 			}
727cd3e02caSMichael Lotz 
728f28dd36bSAxel Dörfler 			if (status == B_TIMED_OUT)
729f28dd36bSAxel Dörfler 				return B_TIMED_OUT;
730f28dd36bSAxel Dörfler 
7317f64b301SJulian Harnath 			previouslyCommited = atomic_add(&sTotalSpaceCommited, size);
732f28dd36bSAxel Dörfler 			continue;
733224aee3fSIngo Weinhold 		}
734224aee3fSIngo Weinhold 
735f28dd36bSAxel Dörfler 		// Quota is fulfilled, try to allocate the buffer
7367f64b301SJulian Harnath 		port_message* message = (port_message*)malloc(size);
737f28dd36bSAxel Dörfler 		if (message != NULL) {
738e8885f20SAxel Dörfler 			message->code = code;
739e8885f20SAxel Dörfler 			message->size = bufferSize;
740e8885f20SAxel Dörfler 
741f28dd36bSAxel Dörfler 			*_message = message;
742f28dd36bSAxel Dörfler 			return B_OK;
743f28dd36bSAxel Dörfler 		}
744f28dd36bSAxel Dörfler 
7457f64b301SJulian Harnath 		// We weren't able to allocate and we'll start over,so we remove our
7467f64b301SJulian Harnath 		// size from the commited-counter again.
7477f64b301SJulian Harnath 		atomic_add(&sTotalSpaceCommited, -size);
748f28dd36bSAxel Dörfler 		continue;
749f28dd36bSAxel Dörfler 	}
750224aee3fSIngo Weinhold }
751224aee3fSIngo Weinhold 
752224aee3fSIngo Weinhold 
753224aee3fSIngo Weinhold /*!	Fills the port_info structure with information from the specified
754224aee3fSIngo Weinhold 	port.
75524df6592SIngo Weinhold 	The port's lock must be held when called.
756224aee3fSIngo Weinhold */
757224aee3fSIngo Weinhold static void
fill_port_info(Port * port,port_info * info,size_t size)75824df6592SIngo Weinhold fill_port_info(Port* port, port_info* info, size_t size)
759224aee3fSIngo Weinhold {
760224aee3fSIngo Weinhold 	info->port = port->id;
761224aee3fSIngo Weinhold 	info->team = port->owner;
762224aee3fSIngo Weinhold 	info->capacity = port->capacity;
763224aee3fSIngo Weinhold 
7647d592ec4SAxel Dörfler 	info->queue_count = port->read_count;
765224aee3fSIngo Weinhold 	info->total_count = port->total_count;
766224aee3fSIngo Weinhold 
767e8885f20SAxel Dörfler 	strlcpy(info->name, port->lock.name, B_OS_NAME_LENGTH);
768e8885f20SAxel Dörfler }
769e8885f20SAxel Dörfler 
770e8885f20SAxel Dörfler 
771e8885f20SAxel Dörfler static ssize_t
copy_port_message(port_message * message,int32 * _code,void * buffer,size_t bufferSize,bool userCopy)772e8885f20SAxel Dörfler copy_port_message(port_message* message, int32* _code, void* buffer,
773e8885f20SAxel Dörfler 	size_t bufferSize, bool userCopy)
774e8885f20SAxel Dörfler {
775e8885f20SAxel Dörfler 	// check output buffer size
776748c0f30SAxel Dörfler 	size_t size = std::min(bufferSize, message->size);
777e8885f20SAxel Dörfler 
778e8885f20SAxel Dörfler 	// copy message
779e8885f20SAxel Dörfler 	if (_code != NULL)
780e8885f20SAxel Dörfler 		*_code = message->code;
781e8885f20SAxel Dörfler 
782e8885f20SAxel Dörfler 	if (size > 0) {
783e8885f20SAxel Dörfler 		if (userCopy) {
784e8885f20SAxel Dörfler 			status_t status = user_memcpy(buffer, message->buffer, size);
785e8885f20SAxel Dörfler 			if (status != B_OK)
786e8885f20SAxel Dörfler 				return status;
787e8885f20SAxel Dörfler 		} else
788e8885f20SAxel Dörfler 			memcpy(buffer, message->buffer, size);
789e8885f20SAxel Dörfler 	}
790e8885f20SAxel Dörfler 
791e8885f20SAxel Dörfler 	return size;
792224aee3fSIngo Weinhold }
793224aee3fSIngo Weinhold 
794224aee3fSIngo Weinhold 
79586a999adSAxel Dörfler static void
uninit_port(Port * port)7967f64b301SJulian Harnath uninit_port(Port* port)
79786a999adSAxel Dörfler {
7987f64b301SJulian Harnath 	MutexLocker locker(port->lock);
7997f64b301SJulian Harnath 
80024df6592SIngo Weinhold 	notify_port_select_events(port, B_EVENT_INVALID);
80124df6592SIngo Weinhold 	port->select_infos = NULL;
80286a999adSAxel Dörfler 
80386a999adSAxel Dörfler 	// Release the threads that were blocking on this port.
80486a999adSAxel Dörfler 	// read_port() will see the B_BAD_PORT_ID return value, and act accordingly
80503fb2d88SPawel Dziepak 	port->read_condition.NotifyAll(B_BAD_PORT_ID);
80603fb2d88SPawel Dziepak 	port->write_condition.NotifyAll(B_BAD_PORT_ID);
80724df6592SIngo Weinhold 	sNotificationService.Notify(PORT_REMOVED, port->id);
80824df6592SIngo Weinhold }
80924df6592SIngo Weinhold 
81024df6592SIngo Weinhold 
8117f64b301SJulian Harnath /*! Caller must ensure there is still a reference to the port. (Either by
8127f64b301SJulian Harnath  *  holding a reference itself or by holding a lock on one of the data
8137f64b301SJulian Harnath  *  structures in which it is referenced.)
8147f64b301SJulian Harnath  */
8157f64b301SJulian Harnath static status_t
delete_port_logical(Port * port)8167f64b301SJulian Harnath delete_port_logical(Port* port)
8177f64b301SJulian Harnath {
8187f64b301SJulian Harnath 	for (;;) {
8197f64b301SJulian Harnath 		// Try to logically delete
8207f64b301SJulian Harnath 		const int32 oldState = atomic_test_and_set(&port->state,
8217f64b301SJulian Harnath 			Port::kDeleted, Port::kActive);
8227f64b301SJulian Harnath 			// Linearization point for port deletion
8237f64b301SJulian Harnath 
8247f64b301SJulian Harnath 		switch (oldState) {
8257f64b301SJulian Harnath 			case Port::kActive:
8267f64b301SJulian Harnath 				// Logical deletion succesful
8277f64b301SJulian Harnath 				return B_OK;
8287f64b301SJulian Harnath 
8297f64b301SJulian Harnath 			case Port::kDeleted:
8307f64b301SJulian Harnath 				// Someone else already deleted it in the meantime
8317f64b301SJulian Harnath 				TRACE(("delete_port_logical: already deleted port_id %ld\n",
8327f64b301SJulian Harnath 						port->id));
8337f64b301SJulian Harnath 				return B_BAD_PORT_ID;
8347f64b301SJulian Harnath 
8357f64b301SJulian Harnath 			case Port::kUnused:
8367f64b301SJulian Harnath 				// Port is still being created, retry
8377f64b301SJulian Harnath 				continue;
8387f64b301SJulian Harnath 
8397f64b301SJulian Harnath 			default:
8407f64b301SJulian Harnath 				// Port state got corrupted somehow
8417f64b301SJulian Harnath 				panic("Invalid port state!\n");
8427f64b301SJulian Harnath 		}
8437f64b301SJulian Harnath 	}
8447f64b301SJulian Harnath }
8457f64b301SJulian Harnath 
8467f64b301SJulian Harnath 
847224aee3fSIngo Weinhold //	#pragma mark - private kernel API
848224aee3fSIngo Weinhold 
849224aee3fSIngo Weinhold 
85024df6592SIngo Weinhold /*! This function deletes all the ports that are owned by the passed team.
851224aee3fSIngo Weinhold */
85286a999adSAxel Dörfler void
delete_owned_ports(Team * team)8534535495dSIngo Weinhold delete_owned_ports(Team* team)
854224aee3fSIngo Weinhold {
85586a999adSAxel Dörfler 	TRACE(("delete_owned_ports(owner = %ld)\n", team->id));
856224aee3fSIngo Weinhold 
8577f64b301SJulian Harnath 	list deletionList;
8587f64b301SJulian Harnath 	list_init_etc(&deletionList, port_team_link_offset());
85924df6592SIngo Weinhold 
8607f64b301SJulian Harnath 	const uint8 lockIndex = team->id % kTeamListLockCount;
8617f64b301SJulian Harnath 	MutexLocker teamPortsListLocker(sTeamListLock[lockIndex]);
862224aee3fSIngo Weinhold 
8637f64b301SJulian Harnath 	// Try to logically delete all ports from the team's port list.
8647f64b301SJulian Harnath 	// On success, move the port to deletionList.
8657f64b301SJulian Harnath 	Port* port = (Port*)list_get_first_item(&team->port_list);
86624df6592SIngo Weinhold 	while (port != NULL) {
8677f64b301SJulian Harnath 		status_t status = delete_port_logical(port);
8687f64b301SJulian Harnath 			// Contains linearization point
86924df6592SIngo Weinhold 
8707f64b301SJulian Harnath 		Port* nextPort = (Port*)list_get_next_item(&team->port_list, port);
8717f64b301SJulian Harnath 
8727f64b301SJulian Harnath 		if (status == B_OK) {
8737f64b301SJulian Harnath 			list_remove_link(&port->team_link);
8747f64b301SJulian Harnath 			list_add_item(&deletionList, port);
87586a999adSAxel Dörfler 		}
8768cd9a524SAxel Dörfler 
8777f64b301SJulian Harnath 		port = nextPort;
8787f64b301SJulian Harnath 	}
8798cd9a524SAxel Dörfler 
8807f64b301SJulian Harnath 	teamPortsListLocker.Unlock();
8817f64b301SJulian Harnath 
8827f64b301SJulian Harnath 	// Remove all ports in deletionList from hashes
8837f64b301SJulian Harnath 	{
8847f64b301SJulian Harnath 		WriteLocker portsLocker(sPortsLock);
8857f64b301SJulian Harnath 
8867f64b301SJulian Harnath 		for (Port* port = (Port*)list_get_first_item(&deletionList);
8877f64b301SJulian Harnath 			 port != NULL;
8887f64b301SJulian Harnath 			 port = (Port*)list_get_next_item(&deletionList, port)) {
8897f64b301SJulian Harnath 
8907f64b301SJulian Harnath 			sPorts.Remove(port);
8917f64b301SJulian Harnath 			sPortsByName.Remove(port);
8927f64b301SJulian Harnath 			port->ReleaseReference();
8937f64b301SJulian Harnath 				// joint reference for sPorts and sPortsByName
8947f64b301SJulian Harnath 		}
8957f64b301SJulian Harnath 	}
8967f64b301SJulian Harnath 
8977f64b301SJulian Harnath 	// Uninitialize ports and release team port list references
8987f64b301SJulian Harnath 	while (Port* port = (Port*)list_remove_head_item(&deletionList)) {
8997f64b301SJulian Harnath 		atomic_add(&sUsedPorts, -1);
9007f64b301SJulian Harnath 		uninit_port(port);
9017f64b301SJulian Harnath 		port->ReleaseReference();
9027f64b301SJulian Harnath 			// Reference for team port list
9037f64b301SJulian Harnath 	}
904224aee3fSIngo Weinhold }
905224aee3fSIngo Weinhold 
906224aee3fSIngo Weinhold 
907224aee3fSIngo Weinhold int32
port_max_ports(void)908224aee3fSIngo Weinhold port_max_ports(void)
909224aee3fSIngo Weinhold {
910224aee3fSIngo Weinhold 	return sMaxPorts;
911224aee3fSIngo Weinhold }
912224aee3fSIngo Weinhold 
913224aee3fSIngo Weinhold 
914224aee3fSIngo Weinhold int32
port_used_ports(void)915224aee3fSIngo Weinhold port_used_ports(void)
916224aee3fSIngo Weinhold {
917224aee3fSIngo Weinhold 	return sUsedPorts;
918224aee3fSIngo Weinhold }
919224aee3fSIngo Weinhold 
920224aee3fSIngo Weinhold 
9217f64b301SJulian Harnath size_t
port_team_link_offset()9227f64b301SJulian Harnath port_team_link_offset()
9237f64b301SJulian Harnath {
9247f64b301SJulian Harnath 	// Somewhat ugly workaround since we cannot use offsetof() for a class
9257f64b301SJulian Harnath 	// with vtable (GCC4 throws a warning then).
9267f64b301SJulian Harnath 	Port* port = (Port*)0;
9277f64b301SJulian Harnath 	return (size_t)&port->team_link;
9287f64b301SJulian Harnath }
9297f64b301SJulian Harnath 
9307f64b301SJulian Harnath 
931224aee3fSIngo Weinhold status_t
port_init(kernel_args * args)932224aee3fSIngo Weinhold port_init(kernel_args *args)
933224aee3fSIngo Weinhold {
9347f64b301SJulian Harnath 	// initialize ports table and by-name hash
93524df6592SIngo Weinhold 	new(&sPorts) PortHashTable;
93624df6592SIngo Weinhold 	if (sPorts.Init() != B_OK) {
93724df6592SIngo Weinhold 		panic("Failed to init port hash table!");
93824df6592SIngo Weinhold 		return B_NO_MEMORY;
939e8885f20SAxel Dörfler 	}
940e8885f20SAxel Dörfler 
9417f64b301SJulian Harnath 	new(&sPortsByName) PortNameHashTable;
9427f64b301SJulian Harnath 	if (sPortsByName.Init() != B_OK) {
9437f64b301SJulian Harnath 		panic("Failed to init port by name hash table!");
944f28dd36bSAxel Dörfler 		return B_NO_MEMORY;
945f28dd36bSAxel Dörfler 	}
946f28dd36bSAxel Dörfler 
94724df6592SIngo Weinhold 	sNoSpaceCondition.Init(&sPorts, "port space");
948224aee3fSIngo Weinhold 
949224aee3fSIngo Weinhold 	// add debugger commands
950ce637fdaSIngo Weinhold 	add_debugger_command_etc("ports", &dump_port_list,
951ce637fdaSIngo Weinhold 		"Dump a list of all active ports (for team, with name, etc.)",
952ce637fdaSIngo Weinhold 		"[ ([ \"team\" | \"owner\" ] <team>) | (\"name\" <name>) ]\n"
953ce637fdaSIngo Weinhold 		"Prints a list of all active ports meeting the given\n"
954ce637fdaSIngo Weinhold 		"requirement. If no argument is given, all ports are listed.\n"
955ce637fdaSIngo Weinhold 		"  <team>             - The team owning the ports.\n"
956ce637fdaSIngo Weinhold 		"  <name>             - Part of the name of the ports.\n", 0);
957ce637fdaSIngo Weinhold 	add_debugger_command_etc("port", &dump_port_info,
958ce637fdaSIngo Weinhold 		"Dump info about a particular port",
959f28dd36bSAxel Dörfler 		"(<id> | [ \"address\" ] <address>) | ([ \"name\" ] <name>) "
960f28dd36bSAxel Dörfler 			"| (\"condition\" <address>)\n"
961ce637fdaSIngo Weinhold 		"Prints info about the specified port.\n"
962ce637fdaSIngo Weinhold 		"  <address>   - Pointer to the port structure.\n"
963ce637fdaSIngo Weinhold 		"  <name>      - Name of the port.\n"
964f28dd36bSAxel Dörfler 		"  <condition> - address of the port's read or write condition.\n", 0);
965224aee3fSIngo Weinhold 
96651755cf8SAxel Dörfler 	new(&sNotificationService) PortNotificationService();
967c24adb29SRene Gollent 	sNotificationService.Register();
968224aee3fSIngo Weinhold 	sPortsActive = true;
969224aee3fSIngo Weinhold 	return B_OK;
970224aee3fSIngo Weinhold }
971224aee3fSIngo Weinhold 
972224aee3fSIngo Weinhold 
973224aee3fSIngo Weinhold //	#pragma mark - public kernel API
974224aee3fSIngo Weinhold 
975224aee3fSIngo Weinhold 
976224aee3fSIngo Weinhold port_id
create_port(int32 queueLength,const char * name)977224aee3fSIngo Weinhold create_port(int32 queueLength, const char* name)
978224aee3fSIngo Weinhold {
97951755cf8SAxel Dörfler 	TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength,
98051755cf8SAxel Dörfler 		name));
981224aee3fSIngo Weinhold 
982e8885f20SAxel Dörfler 	if (!sPortsActive) {
983e8885f20SAxel Dörfler 		panic("ports used too early!\n");
984224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
985e8885f20SAxel Dörfler 	}
986e8885f20SAxel Dörfler 	if (queueLength < 1 || queueLength > MAX_QUEUE_LENGTH)
987224aee3fSIngo Weinhold 		return B_BAD_VALUE;
988224aee3fSIngo Weinhold 
9894535495dSIngo Weinhold 	Team* team = thread_get_current_thread()->team;
99086a999adSAxel Dörfler 	if (team == NULL)
99186a999adSAxel Dörfler 		return B_BAD_TEAM_ID;
99286a999adSAxel Dörfler 
99324df6592SIngo Weinhold 	// create a port
99412ca3674SAugustin Cavalier 	BReference<Port> port;
99512ca3674SAugustin Cavalier 	{
99612ca3674SAugustin Cavalier 		Port* newPort = new(std::nothrow) Port(team_get_current_team_id(),
99712ca3674SAugustin Cavalier 			queueLength, name != NULL ? name : "unnamed port");
99812ca3674SAugustin Cavalier 		if (newPort == NULL)
99924df6592SIngo Weinhold 			return B_NO_MEMORY;
100012ca3674SAugustin Cavalier 		port.SetTo(newPort, true);
100112ca3674SAugustin Cavalier 	}
100224df6592SIngo Weinhold 
100324df6592SIngo Weinhold 	// check the ports limit
10047f64b301SJulian Harnath 	const int32 previouslyUsed = atomic_add(&sUsedPorts, 1);
10057f64b301SJulian Harnath 	if (previouslyUsed + 1 >= sMaxPorts) {
10067f64b301SJulian Harnath 		atomic_add(&sUsedPorts, -1);
100724df6592SIngo Weinhold 		return B_NO_MORE_PORTS;
10087f64b301SJulian Harnath 	}
100924df6592SIngo Weinhold 
10107f64b301SJulian Harnath 	{
10117f64b301SJulian Harnath 		WriteLocker locker(sPortsLock);
1012224aee3fSIngo Weinhold 
101324df6592SIngo Weinhold 		// allocate a port ID
101424df6592SIngo Weinhold 		do {
101524df6592SIngo Weinhold 			port->id = sNextPortID++;
1016224aee3fSIngo Weinhold 
101724df6592SIngo Weinhold 			// handle integer overflow
101824df6592SIngo Weinhold 			if (sNextPortID < 0)
101924df6592SIngo Weinhold 				sNextPortID = 1;
102024df6592SIngo Weinhold 		} while (sPorts.Lookup(port->id) != NULL);
1021224aee3fSIngo Weinhold 
10227f64b301SJulian Harnath 		// Insert port physically:
10237f64b301SJulian Harnath 		// (1/2) Insert into hash tables
10247f64b301SJulian Harnath 		port->AcquireReference();
10257f64b301SJulian Harnath 			// joint reference for sPorts and sPortsByName
10267f64b301SJulian Harnath 
102724df6592SIngo Weinhold 		sPorts.Insert(port);
10287f64b301SJulian Harnath 		sPortsByName.Insert(port);
10297f64b301SJulian Harnath 	}
10307f64b301SJulian Harnath 
10317f64b301SJulian Harnath 	// (2/2) Insert into team list
10327f64b301SJulian Harnath 	{
10337f64b301SJulian Harnath 		const uint8 lockIndex = port->owner % kTeamListLockCount;
10347f64b301SJulian Harnath 		MutexLocker teamPortsListLocker(sTeamListLock[lockIndex]);
10357f64b301SJulian Harnath 		port->AcquireReference();
10367f64b301SJulian Harnath 		list_add_item(&team->port_list, port);
10377f64b301SJulian Harnath 	}
103824df6592SIngo Weinhold 
103924df6592SIngo Weinhold 	// tracing, notifications, etc.
104024df6592SIngo Weinhold 	T(Create(port));
104124df6592SIngo Weinhold 
10427f64b301SJulian Harnath 	const port_id id = port->id;
104324df6592SIngo Weinhold 
10447f64b301SJulian Harnath 	// Insert port logically by marking it active
10457f64b301SJulian Harnath 	const int32 oldState = atomic_test_and_set(&port->state,
10467f64b301SJulian Harnath 		Port::kActive, Port::kUnused);
10477f64b301SJulian Harnath 		// Linearization point for port creation
10487f64b301SJulian Harnath 
10497f64b301SJulian Harnath 	if (oldState != Port::kUnused) {
10507f64b301SJulian Harnath 		// Nobody is allowed to tamper with the port before it's active.
10517f64b301SJulian Harnath 		panic("Port state was modified during creation!\n");
10527f64b301SJulian Harnath 	}
1053224aee3fSIngo Weinhold 
1054224aee3fSIngo Weinhold 	TRACE(("create_port() done: port created %ld\n", id));
1055224aee3fSIngo Weinhold 
105651755cf8SAxel Dörfler 	sNotificationService.Notify(PORT_ADDED, id);
1057224aee3fSIngo Weinhold 	return id;
1058224aee3fSIngo Weinhold }
1059224aee3fSIngo Weinhold 
1060224aee3fSIngo Weinhold 
1061224aee3fSIngo Weinhold status_t
close_port(port_id id)1062224aee3fSIngo Weinhold close_port(port_id id)
1063224aee3fSIngo Weinhold {
1064224aee3fSIngo Weinhold 	TRACE(("close_port(id = %ld)\n", id));
1065224aee3fSIngo Weinhold 
1066224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1067224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1068224aee3fSIngo Weinhold 
106924df6592SIngo Weinhold 	// get the port
10707f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
10717f64b301SJulian Harnath 	if (portRef == NULL) {
1072224aee3fSIngo Weinhold 		TRACE(("close_port: invalid port_id %ld\n", id));
1073224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1074224aee3fSIngo Weinhold 	}
10757f64b301SJulian Harnath 	MutexLocker lock(&portRef->lock, true);
1076224aee3fSIngo Weinhold 
1077224aee3fSIngo Weinhold 	// mark port to disable writing - deleting the semaphores will
1078224aee3fSIngo Weinhold 	// wake up waiting read/writes
10797f64b301SJulian Harnath 	portRef->capacity = 0;
1080224aee3fSIngo Weinhold 
10817f64b301SJulian Harnath 	notify_port_select_events(portRef, B_EVENT_INVALID);
10827f64b301SJulian Harnath 	portRef->select_infos = NULL;
1083224aee3fSIngo Weinhold 
1084d0f2d828SPawel Dziepak 	portRef->read_condition.NotifyAll(B_BAD_PORT_ID);
1085d0f2d828SPawel Dziepak 	portRef->write_condition.NotifyAll(B_BAD_PORT_ID);
1086224aee3fSIngo Weinhold 
1087e8885f20SAxel Dörfler 	return B_OK;
1088224aee3fSIngo Weinhold }
1089224aee3fSIngo Weinhold 
1090224aee3fSIngo Weinhold 
1091224aee3fSIngo Weinhold status_t
delete_port(port_id id)1092224aee3fSIngo Weinhold delete_port(port_id id)
1093224aee3fSIngo Weinhold {
1094224aee3fSIngo Weinhold 	TRACE(("delete_port(id = %ld)\n", id));
1095224aee3fSIngo Weinhold 
1096224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1097224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1098224aee3fSIngo Weinhold 
10997f64b301SJulian Harnath 	BReference<Port> portRef = get_port(id);
1100224aee3fSIngo Weinhold 
11017f64b301SJulian Harnath 	if (portRef == NULL) {
1102224aee3fSIngo Weinhold 		TRACE(("delete_port: invalid port_id %ld\n", id));
1103224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1104224aee3fSIngo Weinhold 	}
1105224aee3fSIngo Weinhold 
11067f64b301SJulian Harnath 	status_t status = delete_port_logical(portRef);
11077f64b301SJulian Harnath 		// Contains linearization point
11087f64b301SJulian Harnath 	if (status != B_OK)
11097f64b301SJulian Harnath 		return status;
1110f28dd36bSAxel Dörfler 
11117f64b301SJulian Harnath 	// Now remove port physically:
11127f64b301SJulian Harnath 	// (1/2) Remove from hash tables
11137f64b301SJulian Harnath 	{
11147f64b301SJulian Harnath 		WriteLocker portsLocker(sPortsLock);
111524df6592SIngo Weinhold 
11167f64b301SJulian Harnath 		sPorts.Remove(portRef);
11177f64b301SJulian Harnath 		sPortsByName.Remove(portRef);
111824df6592SIngo Weinhold 
11197f64b301SJulian Harnath 		portRef->ReleaseReference();
11207f64b301SJulian Harnath 			// joint reference for sPorts and sPortsByName
1121e8885f20SAxel Dörfler 	}
1122224aee3fSIngo Weinhold 
11237f64b301SJulian Harnath 	// (2/2) Remove from team port list
11247f64b301SJulian Harnath 	{
11257f64b301SJulian Harnath 		const uint8 lockIndex = portRef->owner % kTeamListLockCount;
11267f64b301SJulian Harnath 		MutexLocker teamPortsListLocker(sTeamListLock[lockIndex]);
1127224aee3fSIngo Weinhold 
11287f64b301SJulian Harnath 		list_remove_link(&portRef->team_link);
11297f64b301SJulian Harnath 		portRef->ReleaseReference();
11307f64b301SJulian Harnath 	}
1131e8885f20SAxel Dörfler 
11327f64b301SJulian Harnath 	uninit_port(portRef);
11337f64b301SJulian Harnath 
11347f64b301SJulian Harnath 	T(Delete(portRef));
11357f64b301SJulian Harnath 
11367f64b301SJulian Harnath 	atomic_add(&sUsedPorts, -1);
1137e8885f20SAxel Dörfler 
1138224aee3fSIngo Weinhold 	return B_OK;
1139224aee3fSIngo Weinhold }
1140224aee3fSIngo Weinhold 
1141224aee3fSIngo Weinhold 
1142224aee3fSIngo Weinhold status_t
select_port(int32 id,struct select_info * info,bool kernel)1143224aee3fSIngo Weinhold select_port(int32 id, struct select_info* info, bool kernel)
1144224aee3fSIngo Weinhold {
1145224aee3fSIngo Weinhold 	if (id < 0)
1146224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1147224aee3fSIngo Weinhold 
114824df6592SIngo Weinhold 	// get the port
11497f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
11507f64b301SJulian Harnath 	if (portRef == NULL)
1151e8885f20SAxel Dörfler 		return B_BAD_PORT_ID;
11527f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
115324df6592SIngo Weinhold 
115424df6592SIngo Weinhold 	// port must not yet be closed
11557f64b301SJulian Harnath 	if (is_port_closed(portRef))
115624df6592SIngo Weinhold 		return B_BAD_PORT_ID;
115724df6592SIngo Weinhold 
11587f64b301SJulian Harnath 	if (!kernel && portRef->owner == team_get_kernel_team_id()) {
1159224aee3fSIngo Weinhold 		// kernel port, but call from userland
1160e8885f20SAxel Dörfler 		return B_NOT_ALLOWED;
1161e8885f20SAxel Dörfler 	}
1162e8885f20SAxel Dörfler 
1163224aee3fSIngo Weinhold 	info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID;
1164224aee3fSIngo Weinhold 
1165224aee3fSIngo Weinhold 	if (info->selected_events != 0) {
1166224aee3fSIngo Weinhold 		uint16 events = 0;
1167224aee3fSIngo Weinhold 
11687f64b301SJulian Harnath 		info->next = portRef->select_infos;
11697f64b301SJulian Harnath 		portRef->select_infos = info;
1170224aee3fSIngo Weinhold 
1171224aee3fSIngo Weinhold 		// check for events
1172224aee3fSIngo Weinhold 		if ((info->selected_events & B_EVENT_READ) != 0
11737f64b301SJulian Harnath 			&& !portRef->messages.IsEmpty()) {
1174224aee3fSIngo Weinhold 			events |= B_EVENT_READ;
1175224aee3fSIngo Weinhold 		}
1176224aee3fSIngo Weinhold 
11777f64b301SJulian Harnath 		if (portRef->write_count > 0)
1178224aee3fSIngo Weinhold 			events |= B_EVENT_WRITE;
1179224aee3fSIngo Weinhold 
1180224aee3fSIngo Weinhold 		if (events != 0)
1181224aee3fSIngo Weinhold 			notify_select_events(info, events);
1182224aee3fSIngo Weinhold 	}
1183224aee3fSIngo Weinhold 
1184e8885f20SAxel Dörfler 	return B_OK;
1185224aee3fSIngo Weinhold }
1186224aee3fSIngo Weinhold 
1187224aee3fSIngo Weinhold 
1188224aee3fSIngo Weinhold status_t
deselect_port(int32 id,struct select_info * info,bool kernel)1189224aee3fSIngo Weinhold deselect_port(int32 id, struct select_info* info, bool kernel)
1190224aee3fSIngo Weinhold {
1191224aee3fSIngo Weinhold 	if (id < 0)
1192224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1193224aee3fSIngo Weinhold 	if (info->selected_events == 0)
1194224aee3fSIngo Weinhold 		return B_OK;
1195224aee3fSIngo Weinhold 
119624df6592SIngo Weinhold 	// get the port
11977f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
11987f64b301SJulian Harnath 	if (portRef == NULL)
119924df6592SIngo Weinhold 		return B_BAD_PORT_ID;
12007f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1201224aee3fSIngo Weinhold 
120224df6592SIngo Weinhold 	// find and remove the infos
12037f64b301SJulian Harnath 	select_info** infoLocation = &portRef->select_infos;
1204224aee3fSIngo Weinhold 	while (*infoLocation != NULL && *infoLocation != info)
1205224aee3fSIngo Weinhold 		infoLocation = &(*infoLocation)->next;
1206224aee3fSIngo Weinhold 
1207224aee3fSIngo Weinhold 	if (*infoLocation == info)
1208224aee3fSIngo Weinhold 		*infoLocation = info->next;
1209224aee3fSIngo Weinhold 
1210224aee3fSIngo Weinhold 	return B_OK;
1211224aee3fSIngo Weinhold }
1212224aee3fSIngo Weinhold 
1213224aee3fSIngo Weinhold 
1214224aee3fSIngo Weinhold port_id
find_port(const char * name)1215224aee3fSIngo Weinhold find_port(const char* name)
1216224aee3fSIngo Weinhold {
1217224aee3fSIngo Weinhold 	TRACE(("find_port(name = \"%s\")\n", name));
1218224aee3fSIngo Weinhold 
1219e8885f20SAxel Dörfler 	if (!sPortsActive) {
1220e8885f20SAxel Dörfler 		panic("ports used too early!\n");
1221224aee3fSIngo Weinhold 		return B_NAME_NOT_FOUND;
1222e8885f20SAxel Dörfler 	}
1223224aee3fSIngo Weinhold 	if (name == NULL)
1224224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1225224aee3fSIngo Weinhold 
12267f64b301SJulian Harnath 	ReadLocker locker(sPortsLock);
12277f64b301SJulian Harnath 	Port* port = sPortsByName.Lookup(name);
12287f64b301SJulian Harnath 		// Since we have sPortsLock and don't return the port itself,
12297f64b301SJulian Harnath 		// no BReference necessary
1230224aee3fSIngo Weinhold 
12317f64b301SJulian Harnath 	if (port != NULL && port->state == Port::kActive)
123224df6592SIngo Weinhold 		return port->id;
1233224aee3fSIngo Weinhold 
1234e8885f20SAxel Dörfler 	return B_NAME_NOT_FOUND;
1235224aee3fSIngo Weinhold }
1236224aee3fSIngo Weinhold 
1237224aee3fSIngo Weinhold 
1238224aee3fSIngo Weinhold status_t
_get_port_info(port_id id,port_info * info,size_t size)1239224aee3fSIngo Weinhold _get_port_info(port_id id, port_info* info, size_t size)
1240224aee3fSIngo Weinhold {
1241224aee3fSIngo Weinhold 	TRACE(("get_port_info(id = %ld)\n", id));
1242224aee3fSIngo Weinhold 
1243224aee3fSIngo Weinhold 	if (info == NULL || size != sizeof(port_info))
1244224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1245224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1246224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1247224aee3fSIngo Weinhold 
124824df6592SIngo Weinhold 	// get the port
12497f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
12507f64b301SJulian Harnath 	if (portRef == NULL) {
1251224aee3fSIngo Weinhold 		TRACE(("get_port_info: invalid port_id %ld\n", id));
1252224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1253224aee3fSIngo Weinhold 	}
12547f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1255224aee3fSIngo Weinhold 
1256224aee3fSIngo Weinhold 	// fill a port_info struct with info
12577f64b301SJulian Harnath 	fill_port_info(portRef, info, size);
1258224aee3fSIngo Weinhold 	return B_OK;
1259224aee3fSIngo Weinhold }
1260224aee3fSIngo Weinhold 
1261224aee3fSIngo Weinhold 
1262224aee3fSIngo Weinhold status_t
_get_next_port_info(team_id teamID,int32 * _cookie,struct port_info * info,size_t size)126324df6592SIngo Weinhold _get_next_port_info(team_id teamID, int32* _cookie, struct port_info* info,
1264e8885f20SAxel Dörfler 	size_t size)
1265224aee3fSIngo Weinhold {
126624df6592SIngo Weinhold 	TRACE(("get_next_port_info(team = %ld)\n", teamID));
1267224aee3fSIngo Weinhold 
1268e8885f20SAxel Dörfler 	if (info == NULL || size != sizeof(port_info) || _cookie == NULL
126924df6592SIngo Weinhold 		|| teamID < 0) {
1270224aee3fSIngo Weinhold 		return B_BAD_VALUE;
127124df6592SIngo Weinhold 	}
1272224aee3fSIngo Weinhold 	if (!sPortsActive)
1273224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1274224aee3fSIngo Weinhold 
127524df6592SIngo Weinhold 	Team* team = Team::Get(teamID);
127624df6592SIngo Weinhold 	if (team == NULL)
127724df6592SIngo Weinhold 		return B_BAD_TEAM_ID;
127824df6592SIngo Weinhold 	BReference<Team> teamReference(team, true);
1279224aee3fSIngo Weinhold 
128024df6592SIngo Weinhold 	// iterate through the team's port list
12817f64b301SJulian Harnath 	const uint8 lockIndex = teamID % kTeamListLockCount;
12827f64b301SJulian Harnath 	MutexLocker teamPortsListLocker(sTeamListLock[lockIndex]);
1283224aee3fSIngo Weinhold 
128424df6592SIngo Weinhold 	int32 stopIndex = *_cookie;
128524df6592SIngo Weinhold 	int32 index = 0;
1286224aee3fSIngo Weinhold 
128724df6592SIngo Weinhold 	Port* port = (Port*)list_get_first_item(&team->port_list);
128824df6592SIngo Weinhold 	while (port != NULL) {
128924df6592SIngo Weinhold 		if (!is_port_closed(port)) {
129024df6592SIngo Weinhold 			if (index == stopIndex)
1291224aee3fSIngo Weinhold 				break;
129224df6592SIngo Weinhold 			index++;
1293224aee3fSIngo Weinhold 		}
1294e8885f20SAxel Dörfler 
129524df6592SIngo Weinhold 		port = (Port*)list_get_next_item(&team->port_list, port);
1296224aee3fSIngo Weinhold 	}
1297224aee3fSIngo Weinhold 
129824df6592SIngo Weinhold 	if (port == NULL)
1299224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1300224aee3fSIngo Weinhold 
130124df6592SIngo Weinhold 	// fill in the port info
13027f64b301SJulian Harnath 	BReference<Port> portRef = port;
13037f64b301SJulian Harnath 	teamPortsListLocker.Unlock();
13047f64b301SJulian Harnath 		// Only use portRef below this line...
13057f64b301SJulian Harnath 
13067f64b301SJulian Harnath 	MutexLocker locker(portRef->lock);
13077f64b301SJulian Harnath 	fill_port_info(portRef, info, size);
130824df6592SIngo Weinhold 
130924df6592SIngo Weinhold 	*_cookie = stopIndex + 1;
1310e8885f20SAxel Dörfler 	return B_OK;
1311224aee3fSIngo Weinhold }
1312224aee3fSIngo Weinhold 
1313224aee3fSIngo Weinhold 
1314224aee3fSIngo Weinhold ssize_t
port_buffer_size(port_id id)1315224aee3fSIngo Weinhold port_buffer_size(port_id id)
1316224aee3fSIngo Weinhold {
1317224aee3fSIngo Weinhold 	return port_buffer_size_etc(id, 0, 0);
1318224aee3fSIngo Weinhold }
1319224aee3fSIngo Weinhold 
1320224aee3fSIngo Weinhold 
1321224aee3fSIngo Weinhold ssize_t
port_buffer_size_etc(port_id id,uint32 flags,bigtime_t timeout)1322224aee3fSIngo Weinhold port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
1323224aee3fSIngo Weinhold {
13247727e08eSIngo Weinhold 	port_message_info info;
13257727e08eSIngo Weinhold 	status_t error = get_port_message_info_etc(id, &info, flags, timeout);
13267727e08eSIngo Weinhold 	return error != B_OK ? error : info.size;
13277727e08eSIngo Weinhold }
13287727e08eSIngo Weinhold 
1329e8885f20SAxel Dörfler 
13307727e08eSIngo Weinhold status_t
_get_port_message_info_etc(port_id id,port_message_info * info,size_t infoSize,uint32 flags,bigtime_t timeout)13317727e08eSIngo Weinhold _get_port_message_info_etc(port_id id, port_message_info* info,
13327727e08eSIngo Weinhold 	size_t infoSize, uint32 flags, bigtime_t timeout)
13337727e08eSIngo Weinhold {
13347727e08eSIngo Weinhold 	if (info == NULL || infoSize != sizeof(port_message_info))
13357727e08eSIngo Weinhold 		return B_BAD_VALUE;
1336224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1337224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1338224aee3fSIngo Weinhold 
1339f28dd36bSAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1340f28dd36bSAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1341224aee3fSIngo Weinhold 
134224df6592SIngo Weinhold 	// get the port
13437f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
13447f64b301SJulian Harnath 	if (portRef == NULL)
134524df6592SIngo Weinhold 		return B_BAD_PORT_ID;
13467f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1347224aee3fSIngo Weinhold 
13487f64b301SJulian Harnath 	if (is_port_closed(portRef) && portRef->messages.IsEmpty()) {
13497f64b301SJulian Harnath 		T(Info(portRef, 0, B_BAD_PORT_ID));
135024df6592SIngo Weinhold 		TRACE(("_get_port_message_info_etc(): closed port %ld\n", id));
1351224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1352224aee3fSIngo Weinhold 	}
1353224aee3fSIngo Weinhold 
13547f64b301SJulian Harnath 	while (portRef->read_count == 0) {
1355e8885f20SAxel Dörfler 		// We need to wait for a message to appear
1356f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1357f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1358f28dd36bSAxel Dörfler 
1359e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
13607f64b301SJulian Harnath 		portRef->read_condition.Add(&entry);
1361224aee3fSIngo Weinhold 
1362e8885f20SAxel Dörfler 		locker.Unlock();
1363224aee3fSIngo Weinhold 
1364224aee3fSIngo Weinhold 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1365e8885f20SAxel Dörfler 		status_t status = entry.Wait(flags, timeout);
1366f28dd36bSAxel Dörfler 
1367f28dd36bSAxel Dörfler 		if (status != B_OK) {
1368748c0f30SAxel Dörfler 			T(Info(portRef, 0, status));
1369224aee3fSIngo Weinhold 			return status;
1370f28dd36bSAxel Dörfler 		}
1371224aee3fSIngo Weinhold 
137224df6592SIngo Weinhold 		// re-lock
13737f64b301SJulian Harnath 		BReference<Port> newPortRef = get_locked_port(id);
13747f64b301SJulian Harnath 		if (newPortRef == NULL) {
137524df6592SIngo Weinhold 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
137624df6592SIngo Weinhold 			return B_BAD_PORT_ID;
137724df6592SIngo Weinhold 		}
13787f64b301SJulian Harnath 		locker.SetTo(newPortRef->lock, true);
1379224aee3fSIngo Weinhold 
13807f64b301SJulian Harnath 		if (newPortRef != portRef
13817f64b301SJulian Harnath 			|| (is_port_closed(portRef) && portRef->messages.IsEmpty())) {
1382224aee3fSIngo Weinhold 			// the port is no longer there
138324df6592SIngo Weinhold 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
1384224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1385224aee3fSIngo Weinhold 		}
1386a73382f7SIngo Weinhold 	}
1387224aee3fSIngo Weinhold 
1388224aee3fSIngo Weinhold 	// determine tail & get the length of the message
13897f64b301SJulian Harnath 	port_message* message = portRef->messages.Head();
1390e8885f20SAxel Dörfler 	if (message == NULL) {
13917f64b301SJulian Harnath 		panic("port %" B_PRId32 ": no messages found\n", portRef->id);
1392e8885f20SAxel Dörfler 		return B_ERROR;
13937727e08eSIngo Weinhold 	}
1394224aee3fSIngo Weinhold 
1395e8885f20SAxel Dörfler 	info->size = message->size;
1396e8885f20SAxel Dörfler 	info->sender = message->sender;
1397e8885f20SAxel Dörfler 	info->sender_group = message->sender_group;
1398e8885f20SAxel Dörfler 	info->sender_team = message->sender_team;
1399224aee3fSIngo Weinhold 
1400748c0f30SAxel Dörfler 	T(Info(portRef, message->code, B_OK));
1401f28dd36bSAxel Dörfler 
1402e8885f20SAxel Dörfler 	// notify next one, as we haven't read from the port
14037f64b301SJulian Harnath 	portRef->read_condition.NotifyOne();
1404224aee3fSIngo Weinhold 
1405e8885f20SAxel Dörfler 	return B_OK;
1406224aee3fSIngo Weinhold }
1407224aee3fSIngo Weinhold 
1408224aee3fSIngo Weinhold 
1409224aee3fSIngo Weinhold ssize_t
port_count(port_id id)1410224aee3fSIngo Weinhold port_count(port_id id)
1411224aee3fSIngo Weinhold {
1412224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1413224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1414224aee3fSIngo Weinhold 
141524df6592SIngo Weinhold 	// get the port
14167f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
14177f64b301SJulian Harnath 	if (portRef == NULL) {
1418224aee3fSIngo Weinhold 		TRACE(("port_count: invalid port_id %ld\n", id));
1419224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1420224aee3fSIngo Weinhold 	}
14217f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1422224aee3fSIngo Weinhold 
1423224aee3fSIngo Weinhold 	// return count of messages
14247f64b301SJulian Harnath 	return portRef->read_count;
1425224aee3fSIngo Weinhold }
1426224aee3fSIngo Weinhold 
1427224aee3fSIngo Weinhold 
1428224aee3fSIngo Weinhold ssize_t
read_port(port_id port,int32 * msgCode,void * buffer,size_t bufferSize)1429e8885f20SAxel Dörfler read_port(port_id port, int32* msgCode, void* buffer, size_t bufferSize)
1430224aee3fSIngo Weinhold {
1431e8885f20SAxel Dörfler 	return read_port_etc(port, msgCode, buffer, bufferSize, 0, 0);
1432224aee3fSIngo Weinhold }
1433224aee3fSIngo Weinhold 
1434224aee3fSIngo Weinhold 
1435224aee3fSIngo Weinhold ssize_t
read_port_etc(port_id id,int32 * _code,void * buffer,size_t bufferSize,uint32 flags,bigtime_t timeout)1436e8885f20SAxel Dörfler read_port_etc(port_id id, int32* _code, void* buffer, size_t bufferSize,
1437224aee3fSIngo Weinhold 	uint32 flags, bigtime_t timeout)
1438224aee3fSIngo Weinhold {
1439224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1440224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1441e8885f20SAxel Dörfler 	if ((buffer == NULL && bufferSize > 0) || timeout < 0)
1442224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1443224aee3fSIngo Weinhold 
1444e8885f20SAxel Dörfler 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0;
1445e8885f20SAxel Dörfler 	bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0;
1446e8885f20SAxel Dörfler 		// TODO: we could allow peeking for user apps now
1447224aee3fSIngo Weinhold 
1448e8885f20SAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1449e8885f20SAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1450e8885f20SAxel Dörfler 
145124df6592SIngo Weinhold 	// get the port
14527f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
14537f64b301SJulian Harnath 	if (portRef == NULL)
145424df6592SIngo Weinhold 		return B_BAD_PORT_ID;
14557f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1456e8885f20SAxel Dörfler 
14577f64b301SJulian Harnath 	if (is_port_closed(portRef) && portRef->messages.IsEmpty()) {
14587f64b301SJulian Harnath 		T(Read(portRef, 0, B_BAD_PORT_ID));
145924df6592SIngo Weinhold 		TRACE(("read_port_etc(): closed port %ld\n", id));
1460224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1461224aee3fSIngo Weinhold 	}
1462224aee3fSIngo Weinhold 
14637f64b301SJulian Harnath 	while (portRef->read_count == 0) {
1464f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1465f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1466f28dd36bSAxel Dörfler 
1467e8885f20SAxel Dörfler 		// We need to wait for a message to appear
1468e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
14697f64b301SJulian Harnath 		portRef->read_condition.Add(&entry);
1470224aee3fSIngo Weinhold 
1471e8885f20SAxel Dörfler 		locker.Unlock();
1472224aee3fSIngo Weinhold 
1473e8885f20SAxel Dörfler 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1474e8885f20SAxel Dörfler 		status_t status = entry.Wait(flags, timeout);
1475224aee3fSIngo Weinhold 
147624df6592SIngo Weinhold 		// re-lock
14777f64b301SJulian Harnath 		BReference<Port> newPortRef = get_locked_port(id);
14787f64b301SJulian Harnath 		if (newPortRef == NULL) {
147924df6592SIngo Weinhold 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
148024df6592SIngo Weinhold 			return B_BAD_PORT_ID;
148124df6592SIngo Weinhold 		}
14827f64b301SJulian Harnath 		locker.SetTo(newPortRef->lock, true);
1483224aee3fSIngo Weinhold 
14847f64b301SJulian Harnath 		if (newPortRef != portRef
14857f64b301SJulian Harnath 			|| (is_port_closed(portRef) && portRef->messages.IsEmpty())) {
1486e8885f20SAxel Dörfler 			// the port is no longer there
148724df6592SIngo Weinhold 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
1488224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1489224aee3fSIngo Weinhold 		}
1490224aee3fSIngo Weinhold 
1491c3bc71d6SIngo Weinhold 		if (status != B_OK) {
14927f64b301SJulian Harnath 			T(Read(portRef, 0, status));
1493c3bc71d6SIngo Weinhold 			return status;
1494e8885f20SAxel Dörfler 		}
14957d592ec4SAxel Dörfler 	}
1496224aee3fSIngo Weinhold 
1497e8885f20SAxel Dörfler 	// determine tail & get the length of the message
14987f64b301SJulian Harnath 	port_message* message = portRef->messages.Head();
1499e8885f20SAxel Dörfler 	if (message == NULL) {
15007f64b301SJulian Harnath 		panic("port %" B_PRId32 ": no messages found\n", portRef->id);
1501e8885f20SAxel Dörfler 		return B_ERROR;
1502224aee3fSIngo Weinhold 	}
1503224aee3fSIngo Weinhold 
1504b4ec7b8eSIngo Weinhold 	if (peekOnly) {
1505e8885f20SAxel Dörfler 		size_t size = copy_port_message(message, _code, buffer, bufferSize,
1506e8885f20SAxel Dörfler 			userCopy);
1507e8885f20SAxel Dörfler 
15087f64b301SJulian Harnath 		T(Read(portRef, message->code, size));
1509f28dd36bSAxel Dörfler 
15107f64b301SJulian Harnath 		portRef->read_condition.NotifyOne();
1511b4ec7b8eSIngo Weinhold 			// we only peeked, but didn't grab the message
1512b4ec7b8eSIngo Weinhold 		return size;
1513b4ec7b8eSIngo Weinhold 	}
1514b4ec7b8eSIngo Weinhold 
15157f64b301SJulian Harnath 	portRef->messages.RemoveHead();
15167f64b301SJulian Harnath 	portRef->total_count++;
15177f64b301SJulian Harnath 	portRef->write_count++;
15187f64b301SJulian Harnath 	portRef->read_count--;
1519224aee3fSIngo Weinhold 
15207f64b301SJulian Harnath 	notify_port_select_events(portRef, B_EVENT_WRITE);
15217f64b301SJulian Harnath 	portRef->write_condition.NotifyOne();
1522224aee3fSIngo Weinhold 		// make one spot in queue available again for write
1523224aee3fSIngo Weinhold 
1524748c0f30SAxel Dörfler 	T(Read(portRef, message->code, std::min(bufferSize, message->size)));
152524df6592SIngo Weinhold 
1526e8885f20SAxel Dörfler 	locker.Unlock();
1527e8885f20SAxel Dörfler 
1528e8885f20SAxel Dörfler 	size_t size = copy_port_message(message, _code, buffer, bufferSize,
1529e8885f20SAxel Dörfler 		userCopy);
1530e8885f20SAxel Dörfler 
1531e8885f20SAxel Dörfler 	put_port_message(message);
1532224aee3fSIngo Weinhold 	return size;
1533224aee3fSIngo Weinhold }
1534224aee3fSIngo Weinhold 
1535224aee3fSIngo Weinhold 
1536224aee3fSIngo Weinhold status_t
write_port(port_id id,int32 msgCode,const void * buffer,size_t bufferSize)1537e8885f20SAxel Dörfler write_port(port_id id, int32 msgCode, const void* buffer, size_t bufferSize)
1538224aee3fSIngo Weinhold {
1539e8885f20SAxel Dörfler 	iovec vec = { (void*)buffer, bufferSize };
1540224aee3fSIngo Weinhold 
1541224aee3fSIngo Weinhold 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0);
1542224aee3fSIngo Weinhold }
1543224aee3fSIngo Weinhold 
1544224aee3fSIngo Weinhold 
1545224aee3fSIngo Weinhold status_t
write_port_etc(port_id id,int32 msgCode,const void * buffer,size_t bufferSize,uint32 flags,bigtime_t timeout)1546e8885f20SAxel Dörfler write_port_etc(port_id id, int32 msgCode, const void* buffer,
1547224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1548224aee3fSIngo Weinhold {
1549e8885f20SAxel Dörfler 	iovec vec = { (void*)buffer, bufferSize };
1550224aee3fSIngo Weinhold 
1551224aee3fSIngo Weinhold 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout);
1552224aee3fSIngo Weinhold }
1553224aee3fSIngo Weinhold 
1554224aee3fSIngo Weinhold 
1555224aee3fSIngo Weinhold status_t
writev_port_etc(port_id id,int32 msgCode,const iovec * msgVecs,size_t vecCount,size_t bufferSize,uint32 flags,bigtime_t timeout)1556224aee3fSIngo Weinhold writev_port_etc(port_id id, int32 msgCode, const iovec* msgVecs,
1557e8885f20SAxel Dörfler 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1558224aee3fSIngo Weinhold {
1559224aee3fSIngo Weinhold 	if (!sPortsActive || id < 0)
1560224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1561224aee3fSIngo Weinhold 	if (bufferSize > PORT_MAX_MESSAGE_SIZE)
1562224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1563224aee3fSIngo Weinhold 
15646e28d809SJérôme Duval 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0;
15656e28d809SJérôme Duval 
1566e8885f20SAxel Dörfler 	// mask irrelevant flags (for acquire_sem() usage)
1567e8885f20SAxel Dörfler 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1568e8885f20SAxel Dörfler 		| B_ABSOLUTE_TIMEOUT;
1569f28dd36bSAxel Dörfler 	if ((flags & B_RELATIVE_TIMEOUT) != 0
1570f28dd36bSAxel Dörfler 		&& timeout != B_INFINITE_TIMEOUT && timeout > 0) {
1571f28dd36bSAxel Dörfler 		// Make the timeout absolute, since we have more than one step where
1572f28dd36bSAxel Dörfler 		// we might have to wait
1573f28dd36bSAxel Dörfler 		flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT;
1574f28dd36bSAxel Dörfler 		timeout += system_time();
1575f28dd36bSAxel Dörfler 	}
1576f28dd36bSAxel Dörfler 
1577f28dd36bSAxel Dörfler 	status_t status;
15781c61ec1aSIngo Weinhold 	port_message* message = NULL;
1579e8885f20SAxel Dörfler 
158024df6592SIngo Weinhold 	// get the port
15817f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
15827f64b301SJulian Harnath 	if (portRef == NULL) {
1583224aee3fSIngo Weinhold 		TRACE(("write_port_etc: invalid port_id %ld\n", id));
1584224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1585224aee3fSIngo Weinhold 	}
15867f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
158724df6592SIngo Weinhold 
15887f64b301SJulian Harnath 	if (is_port_closed(portRef)) {
1589224aee3fSIngo Weinhold 		TRACE(("write_port_etc: port %ld closed\n", id));
1590224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1591224aee3fSIngo Weinhold 	}
1592224aee3fSIngo Weinhold 
15937f64b301SJulian Harnath 	if (portRef->write_count <= 0) {
1594f28dd36bSAxel Dörfler 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1595f28dd36bSAxel Dörfler 			return B_WOULD_BLOCK;
1596f28dd36bSAxel Dörfler 
15977f64b301SJulian Harnath 		portRef->write_count--;
1598f28dd36bSAxel Dörfler 
1599e8885f20SAxel Dörfler 		// We need to block in order to wait for a free message slot
1600e8885f20SAxel Dörfler 		ConditionVariableEntry entry;
16017f64b301SJulian Harnath 		portRef->write_condition.Add(&entry);
1602224aee3fSIngo Weinhold 
1603e8885f20SAxel Dörfler 		locker.Unlock();
1604224aee3fSIngo Weinhold 
1605f28dd36bSAxel Dörfler 		status = entry.Wait(flags, timeout);
1606224aee3fSIngo Weinhold 
160724df6592SIngo Weinhold 		// re-lock
16087f64b301SJulian Harnath 		BReference<Port> newPortRef = get_locked_port(id);
16097f64b301SJulian Harnath 		if (newPortRef == NULL) {
161024df6592SIngo Weinhold 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
161124df6592SIngo Weinhold 			return B_BAD_PORT_ID;
161224df6592SIngo Weinhold 		}
16137f64b301SJulian Harnath 		locker.SetTo(newPortRef->lock, true);
1614e8885f20SAxel Dörfler 
16157f64b301SJulian Harnath 		if (newPortRef != portRef || is_port_closed(portRef)) {
1616e8885f20SAxel Dörfler 			// the port is no longer there
161724df6592SIngo Weinhold 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1618224aee3fSIngo Weinhold 			return B_BAD_PORT_ID;
1619224aee3fSIngo Weinhold 		}
1620224aee3fSIngo Weinhold 
1621c3bc71d6SIngo Weinhold 		if (status != B_OK)
1622f28dd36bSAxel Dörfler 			goto error;
1623f28dd36bSAxel Dörfler 	} else
16247f64b301SJulian Harnath 		portRef->write_count--;
1625e8885f20SAxel Dörfler 
1626f28dd36bSAxel Dörfler 	status = get_port_message(msgCode, bufferSize, flags, timeout,
16277f64b301SJulian Harnath 		&message, *portRef);
1628cd3e02caSMichael Lotz 	if (status != B_OK) {
1629cd3e02caSMichael Lotz 		if (status == B_BAD_PORT_ID) {
1630cd3e02caSMichael Lotz 			// the port had to be unlocked and is now no longer there
1631cd3e02caSMichael Lotz 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1632cd3e02caSMichael Lotz 			return B_BAD_PORT_ID;
1633cd3e02caSMichael Lotz 		}
1634cd3e02caSMichael Lotz 
1635f28dd36bSAxel Dörfler 		goto error;
1636cd3e02caSMichael Lotz 	}
1637224aee3fSIngo Weinhold 
16387727e08eSIngo Weinhold 	// sender credentials
1639e8885f20SAxel Dörfler 	message->sender = geteuid();
1640e8885f20SAxel Dörfler 	message->sender_group = getegid();
1641e8885f20SAxel Dörfler 	message->sender_team = team_get_current_team_id();
16427727e08eSIngo Weinhold 
1643224aee3fSIngo Weinhold 	if (bufferSize > 0) {
16442b861349SMichael Lotz 		size_t offset = 0;
16452b861349SMichael Lotz 		for (uint32 i = 0; i < vecCount; i++) {
1646224aee3fSIngo Weinhold 			size_t bytes = msgVecs[i].iov_len;
1647224aee3fSIngo Weinhold 			if (bytes > bufferSize)
1648224aee3fSIngo Weinhold 				bytes = bufferSize;
1649224aee3fSIngo Weinhold 
16502b861349SMichael Lotz 			if (userCopy) {
16512b861349SMichael Lotz 				status_t status = user_memcpy(message->buffer + offset,
1652e8885f20SAxel Dörfler 					msgVecs[i].iov_base, bytes);
1653e8885f20SAxel Dörfler 				if (status != B_OK) {
1654e8885f20SAxel Dörfler 					put_port_message(message);
1655f28dd36bSAxel Dörfler 					goto error;
165661de73e2SIngo Weinhold 				}
16572b861349SMichael Lotz 			} else
16582b861349SMichael Lotz 				memcpy(message->buffer + offset, msgVecs[i].iov_base, bytes);
1659224aee3fSIngo Weinhold 
1660224aee3fSIngo Weinhold 			bufferSize -= bytes;
1661224aee3fSIngo Weinhold 			if (bufferSize == 0)
1662224aee3fSIngo Weinhold 				break;
1663224aee3fSIngo Weinhold 
16642b861349SMichael Lotz 			offset += bytes;
1665224aee3fSIngo Weinhold 		}
1666224aee3fSIngo Weinhold 	}
1667224aee3fSIngo Weinhold 
16687f64b301SJulian Harnath 	portRef->messages.Add(message);
16697f64b301SJulian Harnath 	portRef->read_count++;
1670224aee3fSIngo Weinhold 
16717f64b301SJulian Harnath 	T(Write(id, portRef->read_count, portRef->write_count, message->code,
167224df6592SIngo Weinhold 		message->size, B_OK));
1673f28dd36bSAxel Dörfler 
16747f64b301SJulian Harnath 	notify_port_select_events(portRef, B_EVENT_READ);
16757f64b301SJulian Harnath 	portRef->read_condition.NotifyOne();
1676e8885f20SAxel Dörfler 	return B_OK;
1677f28dd36bSAxel Dörfler 
1678f28dd36bSAxel Dörfler error:
1679f28dd36bSAxel Dörfler 	// Give up our slot in the queue again, and let someone else
1680f28dd36bSAxel Dörfler 	// try and fail
16817f64b301SJulian Harnath 	T(Write(id, portRef->read_count, portRef->write_count, 0, 0, status));
16827f64b301SJulian Harnath 	portRef->write_count++;
16837f64b301SJulian Harnath 	notify_port_select_events(portRef, B_EVENT_WRITE);
16847f64b301SJulian Harnath 	portRef->write_condition.NotifyOne();
1685f28dd36bSAxel Dörfler 
1686f28dd36bSAxel Dörfler 	return status;
1687224aee3fSIngo Weinhold }
1688224aee3fSIngo Weinhold 
1689224aee3fSIngo Weinhold 
1690224aee3fSIngo Weinhold status_t
set_port_owner(port_id id,team_id newTeamID)169125028839SAxel Dörfler set_port_owner(port_id id, team_id newTeamID)
1692224aee3fSIngo Weinhold {
169325028839SAxel Dörfler 	TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, newTeamID));
1694224aee3fSIngo Weinhold 
1695e8885f20SAxel Dörfler 	if (id < 0)
1696224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1697224aee3fSIngo Weinhold 
169824df6592SIngo Weinhold 	// get the new team
169924df6592SIngo Weinhold 	Team* team = Team::Get(newTeamID);
170024df6592SIngo Weinhold 	if (team == NULL)
170124df6592SIngo Weinhold 		return B_BAD_TEAM_ID;
170224df6592SIngo Weinhold 	BReference<Team> teamReference(team, true);
1703224aee3fSIngo Weinhold 
170424df6592SIngo Weinhold 	// get the port
17057f64b301SJulian Harnath 	BReference<Port> portRef = get_locked_port(id);
17067f64b301SJulian Harnath 	if (portRef == NULL) {
1707224aee3fSIngo Weinhold 		TRACE(("set_port_owner: invalid port_id %ld\n", id));
1708224aee3fSIngo Weinhold 		return B_BAD_PORT_ID;
1709224aee3fSIngo Weinhold 	}
17107f64b301SJulian Harnath 	MutexLocker locker(portRef->lock, true);
1711f28dd36bSAxel Dörfler 
1712224aee3fSIngo Weinhold 	// transfer ownership to other team
17137f64b301SJulian Harnath 	if (team->id != portRef->owner) {
17147f64b301SJulian Harnath 		uint8 firstLockIndex  = portRef->owner % kTeamListLockCount;
17157f64b301SJulian Harnath 		uint8 secondLockIndex = team->id % kTeamListLockCount;
17167f64b301SJulian Harnath 
17177f64b301SJulian Harnath 		// Avoid deadlocks: always lock lower index first
17187f64b301SJulian Harnath 		if (secondLockIndex < firstLockIndex) {
17197f64b301SJulian Harnath 			uint8 temp = secondLockIndex;
17207f64b301SJulian Harnath 			secondLockIndex = firstLockIndex;
17217f64b301SJulian Harnath 			firstLockIndex = temp;
172224df6592SIngo Weinhold 		}
1723224aee3fSIngo Weinhold 
17247f64b301SJulian Harnath 		MutexLocker oldTeamPortsListLocker(sTeamListLock[firstLockIndex]);
17257f64b301SJulian Harnath 		MutexLocker newTeamPortsListLocker;
17267f64b301SJulian Harnath 		if (firstLockIndex != secondLockIndex) {
17277f64b301SJulian Harnath 			newTeamPortsListLocker.SetTo(sTeamListLock[secondLockIndex],
17287f64b301SJulian Harnath 					false);
17297f64b301SJulian Harnath 		}
17307f64b301SJulian Harnath 
17317f64b301SJulian Harnath 		// Now that we have locked the team port lists, check the state again
17327f64b301SJulian Harnath 		if (portRef->state == Port::kActive) {
17337f64b301SJulian Harnath 			list_remove_link(&portRef->team_link);
17347f64b301SJulian Harnath 			list_add_item(&team->port_list, portRef.Get());
17357f64b301SJulian Harnath 			portRef->owner = team->id;
17367f64b301SJulian Harnath 		} else {
17377f64b301SJulian Harnath 			// Port was already deleted. We haven't changed anything yet so
17387f64b301SJulian Harnath 			// we can cancel the operation.
17397f64b301SJulian Harnath 			return B_BAD_PORT_ID;
17407f64b301SJulian Harnath 		}
17417f64b301SJulian Harnath 	}
17427f64b301SJulian Harnath 
17437f64b301SJulian Harnath 	T(OwnerChange(portRef, team->id, B_OK));
1744e8885f20SAxel Dörfler 	return B_OK;
1745224aee3fSIngo Weinhold }
1746224aee3fSIngo Weinhold 
1747224aee3fSIngo Weinhold 
1748224aee3fSIngo Weinhold //	#pragma mark - syscalls
1749224aee3fSIngo Weinhold 
1750224aee3fSIngo Weinhold 
1751224aee3fSIngo Weinhold port_id
_user_create_port(int32 queueLength,const char * userName)1752224aee3fSIngo Weinhold _user_create_port(int32 queueLength, const char *userName)
1753224aee3fSIngo Weinhold {
1754224aee3fSIngo Weinhold 	char name[B_OS_NAME_LENGTH];
1755224aee3fSIngo Weinhold 
1756224aee3fSIngo Weinhold 	if (userName == NULL)
1757224aee3fSIngo Weinhold 		return create_port(queueLength, NULL);
1758224aee3fSIngo Weinhold 
1759224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userName)
1760224aee3fSIngo Weinhold 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1761224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1762224aee3fSIngo Weinhold 
1763224aee3fSIngo Weinhold 	return create_port(queueLength, name);
1764224aee3fSIngo Weinhold }
1765224aee3fSIngo Weinhold 
1766224aee3fSIngo Weinhold 
1767224aee3fSIngo Weinhold status_t
_user_close_port(port_id id)1768224aee3fSIngo Weinhold _user_close_port(port_id id)
1769224aee3fSIngo Weinhold {
1770224aee3fSIngo Weinhold 	return close_port(id);
1771224aee3fSIngo Weinhold }
1772224aee3fSIngo Weinhold 
1773224aee3fSIngo Weinhold 
1774224aee3fSIngo Weinhold status_t
_user_delete_port(port_id id)1775224aee3fSIngo Weinhold _user_delete_port(port_id id)
1776224aee3fSIngo Weinhold {
1777224aee3fSIngo Weinhold 	return delete_port(id);
1778224aee3fSIngo Weinhold }
1779224aee3fSIngo Weinhold 
1780224aee3fSIngo Weinhold 
1781224aee3fSIngo Weinhold port_id
_user_find_port(const char * userName)1782224aee3fSIngo Weinhold _user_find_port(const char *userName)
1783224aee3fSIngo Weinhold {
1784224aee3fSIngo Weinhold 	char name[B_OS_NAME_LENGTH];
1785224aee3fSIngo Weinhold 
1786224aee3fSIngo Weinhold 	if (userName == NULL)
1787224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1788224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userName)
1789224aee3fSIngo Weinhold 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1790224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1791224aee3fSIngo Weinhold 
1792224aee3fSIngo Weinhold 	return find_port(name);
1793224aee3fSIngo Weinhold }
1794224aee3fSIngo Weinhold 
1795224aee3fSIngo Weinhold 
1796224aee3fSIngo Weinhold status_t
_user_get_port_info(port_id id,struct port_info * userInfo)1797224aee3fSIngo Weinhold _user_get_port_info(port_id id, struct port_info *userInfo)
1798224aee3fSIngo Weinhold {
1799224aee3fSIngo Weinhold 	struct port_info info;
1800224aee3fSIngo Weinhold 	status_t status;
1801224aee3fSIngo Weinhold 
1802224aee3fSIngo Weinhold 	if (userInfo == NULL)
1803224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1804224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userInfo))
1805224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1806224aee3fSIngo Weinhold 
1807224aee3fSIngo Weinhold 	status = get_port_info(id, &info);
1808224aee3fSIngo Weinhold 
1809224aee3fSIngo Weinhold 	// copy back to user space
18104048494cSIngo Weinhold 	if (status == B_OK
18114048494cSIngo Weinhold 		&& user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK)
1812224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1813224aee3fSIngo Weinhold 
1814224aee3fSIngo Weinhold 	return status;
1815224aee3fSIngo Weinhold }
1816224aee3fSIngo Weinhold 
1817224aee3fSIngo Weinhold 
1818224aee3fSIngo Weinhold status_t
_user_get_next_port_info(team_id team,int32 * userCookie,struct port_info * userInfo)18194048494cSIngo Weinhold _user_get_next_port_info(team_id team, int32 *userCookie,
18204048494cSIngo Weinhold 	struct port_info *userInfo)
1821224aee3fSIngo Weinhold {
1822224aee3fSIngo Weinhold 	struct port_info info;
1823224aee3fSIngo Weinhold 	status_t status;
1824224aee3fSIngo Weinhold 	int32 cookie;
1825224aee3fSIngo Weinhold 
1826224aee3fSIngo Weinhold 	if (userCookie == NULL || userInfo == NULL)
1827224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1828224aee3fSIngo Weinhold 	if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo)
1829224aee3fSIngo Weinhold 		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
1830224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1831224aee3fSIngo Weinhold 
1832224aee3fSIngo Weinhold 	status = get_next_port_info(team, &cookie, &info);
1833224aee3fSIngo Weinhold 
1834224aee3fSIngo Weinhold 	// copy back to user space
1835224aee3fSIngo Weinhold 	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
18364048494cSIngo Weinhold 		|| (status == B_OK && user_memcpy(userInfo, &info,
18374048494cSIngo Weinhold 				sizeof(struct port_info)) < B_OK))
1838224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1839224aee3fSIngo Weinhold 
1840224aee3fSIngo Weinhold 	return status;
1841224aee3fSIngo Weinhold }
1842224aee3fSIngo Weinhold 
1843224aee3fSIngo Weinhold 
1844224aee3fSIngo Weinhold ssize_t
_user_port_buffer_size_etc(port_id port,uint32 flags,bigtime_t timeout)1845224aee3fSIngo Weinhold _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout)
1846224aee3fSIngo Weinhold {
18474048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
18484048494cSIngo Weinhold 
18494048494cSIngo Weinhold 	status_t status = port_buffer_size_etc(port, flags | B_CAN_INTERRUPT,
18504048494cSIngo Weinhold 		timeout);
18514048494cSIngo Weinhold 
18524048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1853224aee3fSIngo Weinhold }
1854224aee3fSIngo Weinhold 
1855224aee3fSIngo Weinhold 
1856224aee3fSIngo Weinhold ssize_t
_user_port_count(port_id port)1857224aee3fSIngo Weinhold _user_port_count(port_id port)
1858224aee3fSIngo Weinhold {
1859224aee3fSIngo Weinhold 	return port_count(port);
1860224aee3fSIngo Weinhold }
1861224aee3fSIngo Weinhold 
1862224aee3fSIngo Weinhold 
1863224aee3fSIngo Weinhold status_t
_user_set_port_owner(port_id port,team_id team)1864224aee3fSIngo Weinhold _user_set_port_owner(port_id port, team_id team)
1865224aee3fSIngo Weinhold {
1866224aee3fSIngo Weinhold 	return set_port_owner(port, team);
1867224aee3fSIngo Weinhold }
1868224aee3fSIngo Weinhold 
1869224aee3fSIngo Weinhold 
1870224aee3fSIngo Weinhold ssize_t
_user_read_port_etc(port_id port,int32 * userCode,void * userBuffer,size_t bufferSize,uint32 flags,bigtime_t timeout)1871224aee3fSIngo Weinhold _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer,
1872224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1873224aee3fSIngo Weinhold {
1874224aee3fSIngo Weinhold 	int32 messageCode;
1875224aee3fSIngo Weinhold 	ssize_t	bytesRead;
1876224aee3fSIngo Weinhold 
18774048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
18784048494cSIngo Weinhold 
1879224aee3fSIngo Weinhold 	if (userBuffer == NULL && bufferSize != 0)
1880224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1881224aee3fSIngo Weinhold 	if ((userCode != NULL && !IS_USER_ADDRESS(userCode))
1882224aee3fSIngo Weinhold 		|| (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)))
1883224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1884224aee3fSIngo Weinhold 
1885224aee3fSIngo Weinhold 	bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize,
1886224aee3fSIngo Weinhold 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1887224aee3fSIngo Weinhold 
1888224aee3fSIngo Weinhold 	if (bytesRead >= 0 && userCode != NULL
1889224aee3fSIngo Weinhold 		&& user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK)
1890224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1891224aee3fSIngo Weinhold 
18924048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(bytesRead, timeout);
1893224aee3fSIngo Weinhold }
1894224aee3fSIngo Weinhold 
1895224aee3fSIngo Weinhold 
1896224aee3fSIngo Weinhold status_t
_user_write_port_etc(port_id port,int32 messageCode,const void * userBuffer,size_t bufferSize,uint32 flags,bigtime_t timeout)1897224aee3fSIngo Weinhold _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer,
1898224aee3fSIngo Weinhold 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1899224aee3fSIngo Weinhold {
1900224aee3fSIngo Weinhold 	iovec vec = { (void *)userBuffer, bufferSize };
1901224aee3fSIngo Weinhold 
19024048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
19034048494cSIngo Weinhold 
1904224aee3fSIngo Weinhold 	if (userBuffer == NULL && bufferSize != 0)
1905224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1906224aee3fSIngo Weinhold 	if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))
1907224aee3fSIngo Weinhold 		return B_BAD_ADDRESS;
1908224aee3fSIngo Weinhold 
19094048494cSIngo Weinhold 	status_t status = writev_port_etc(port, messageCode, &vec, 1, bufferSize,
1910224aee3fSIngo Weinhold 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
19114048494cSIngo Weinhold 
19124048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1913224aee3fSIngo Weinhold }
1914224aee3fSIngo Weinhold 
1915224aee3fSIngo Weinhold 
1916224aee3fSIngo Weinhold status_t
_user_writev_port_etc(port_id port,int32 messageCode,const iovec * userVecs,size_t vecCount,size_t bufferSize,uint32 flags,bigtime_t timeout)1917224aee3fSIngo Weinhold _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs,
1918224aee3fSIngo Weinhold 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1919224aee3fSIngo Weinhold {
19204048494cSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
1921224aee3fSIngo Weinhold 
1922224aee3fSIngo Weinhold 	if (userVecs == NULL && bufferSize != 0)
1923224aee3fSIngo Weinhold 		return B_BAD_VALUE;
1924*8e56b86bSAugustin Cavalier 	if (vecCount > IOV_MAX)
1925*8e56b86bSAugustin Cavalier 		return B_BAD_VALUE;
1926224aee3fSIngo Weinhold 
1927*8e56b86bSAugustin Cavalier 	BStackOrHeapArray<iovec, 16> vecs(vecCount);
1928*8e56b86bSAugustin Cavalier 	if (!vecs.IsValid())
1929*8e56b86bSAugustin Cavalier 		return B_NO_MEMORY;
1930*8e56b86bSAugustin Cavalier 
193100f1e7c5SAugustin Cavalier 	if (userVecs != NULL && vecCount != 0) {
193200f1e7c5SAugustin Cavalier 		status_t status = get_iovecs_from_user(userVecs, vecCount, vecs);
193300f1e7c5SAugustin Cavalier 		if (status != B_OK)
193400f1e7c5SAugustin Cavalier 			return status;
1935224aee3fSIngo Weinhold 	}
19364048494cSIngo Weinhold 
19374048494cSIngo Weinhold 	status_t status = writev_port_etc(port, messageCode, vecs, vecCount,
19384048494cSIngo Weinhold 		bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT,
19394048494cSIngo Weinhold 		timeout);
1940224aee3fSIngo Weinhold 
19414048494cSIngo Weinhold 	return syscall_restart_handle_timeout_post(status, timeout);
1942224aee3fSIngo Weinhold }
19437727e08eSIngo Weinhold 
19447727e08eSIngo Weinhold 
19457727e08eSIngo Weinhold status_t
_user_get_port_message_info_etc(port_id port,port_message_info * userInfo,size_t infoSize,uint32 flags,bigtime_t timeout)19467727e08eSIngo Weinhold _user_get_port_message_info_etc(port_id port, port_message_info *userInfo,
19477727e08eSIngo Weinhold 	size_t infoSize, uint32 flags, bigtime_t timeout)
19487727e08eSIngo Weinhold {
19497727e08eSIngo Weinhold 	if (userInfo == NULL || infoSize != sizeof(port_message_info))
19507727e08eSIngo Weinhold 		return B_BAD_VALUE;
19517727e08eSIngo Weinhold 
19527727e08eSIngo Weinhold 	syscall_restart_handle_timeout_pre(flags, timeout);
19537727e08eSIngo Weinhold 
19547727e08eSIngo Weinhold 	port_message_info info;
19557727e08eSIngo Weinhold 	status_t error = _get_port_message_info_etc(port, &info, sizeof(info),
19567727e08eSIngo Weinhold 		flags | B_CAN_INTERRUPT, timeout);
19577727e08eSIngo Weinhold 
19587727e08eSIngo Weinhold 	// copy info to userland
19597727e08eSIngo Weinhold 	if (error == B_OK && (!IS_USER_ADDRESS(userInfo)
19607727e08eSIngo Weinhold 			|| user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) {
19617727e08eSIngo Weinhold 		error = B_BAD_ADDRESS;
19627727e08eSIngo Weinhold 	}
19637727e08eSIngo Weinhold 
19647727e08eSIngo Weinhold 	return syscall_restart_handle_timeout_post(error, timeout);
19657727e08eSIngo Weinhold }
1966