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