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