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