1224aee3fSIngo Weinhold /* 251755cf8SAxel Dörfler * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. 3224aee3fSIngo Weinhold * Distributed under the terms of the MIT License. 4224aee3fSIngo Weinhold * 5224aee3fSIngo Weinhold * Copyright 2001, Mark-Jan Bastian. All rights reserved. 6224aee3fSIngo Weinhold * Distributed under the terms of the NewOS License. 7224aee3fSIngo Weinhold */ 8224aee3fSIngo Weinhold 9f28dd36bSAxel Dörfler 10224aee3fSIngo Weinhold /*! Ports for IPC */ 11224aee3fSIngo Weinhold 12f28dd36bSAxel Dörfler 134048494cSIngo Weinhold #include <port.h> 144048494cSIngo Weinhold 154048494cSIngo Weinhold #include <ctype.h> 164048494cSIngo Weinhold #include <iovec.h> 174048494cSIngo Weinhold #include <stdlib.h> 184048494cSIngo Weinhold #include <string.h> 19224aee3fSIngo Weinhold 20224aee3fSIngo Weinhold #include <OS.h> 21224aee3fSIngo Weinhold 22224aee3fSIngo Weinhold #include <arch/int.h> 23e8885f20SAxel Dörfler #include <heap.h> 244048494cSIngo Weinhold #include <kernel.h> 2551755cf8SAxel Dörfler #include <Notifications.h> 264048494cSIngo Weinhold #include <sem.h> 274048494cSIngo Weinhold #include <syscall_restart.h> 284048494cSIngo Weinhold #include <team.h> 29f28dd36bSAxel Dörfler #include <tracing.h> 30b4ec7b8eSIngo Weinhold #include <util/AutoLock.h> 314048494cSIngo Weinhold #include <util/list.h> 32224aee3fSIngo Weinhold #include <wait_for_objects.h> 33224aee3fSIngo Weinhold 34224aee3fSIngo Weinhold 35224aee3fSIngo Weinhold //#define TRACE_PORTS 36224aee3fSIngo Weinhold #ifdef TRACE_PORTS 37224aee3fSIngo Weinhold # define TRACE(x) dprintf x 38224aee3fSIngo Weinhold #else 39224aee3fSIngo Weinhold # define TRACE(x) 40224aee3fSIngo Weinhold #endif 41224aee3fSIngo Weinhold 42224aee3fSIngo Weinhold 43e8885f20SAxel Dörfler struct port_message : DoublyLinkedListLinkImpl<port_message> { 44224aee3fSIngo Weinhold int32 code; 45224aee3fSIngo Weinhold size_t size; 467727e08eSIngo Weinhold uid_t sender; 477727e08eSIngo Weinhold gid_t sender_group; 487727e08eSIngo Weinhold team_id sender_team; 49e8885f20SAxel Dörfler char buffer[0]; 50e8885f20SAxel Dörfler }; 51e8885f20SAxel Dörfler 52e8885f20SAxel Dörfler typedef DoublyLinkedList<port_message> MessageList; 53224aee3fSIngo Weinhold 54224aee3fSIngo Weinhold struct port_entry { 5586a999adSAxel Dörfler struct list_link team_link; 56224aee3fSIngo Weinhold port_id id; 57224aee3fSIngo Weinhold team_id owner; 58224aee3fSIngo Weinhold int32 capacity; 59e8885f20SAxel Dörfler mutex lock; 607d592ec4SAxel Dörfler uint32 read_count; 61e8885f20SAxel Dörfler int32 write_count; 62e8885f20SAxel Dörfler ConditionVariable read_condition; 63e8885f20SAxel Dörfler ConditionVariable write_condition; 64e8885f20SAxel Dörfler int32 total_count; 65e8885f20SAxel Dörfler // messages read from port since creation 66224aee3fSIngo Weinhold select_info* select_infos; 67e8885f20SAxel Dörfler MessageList messages; 68224aee3fSIngo Weinhold }; 69224aee3fSIngo Weinhold 7051755cf8SAxel Dörfler class PortNotificationService : public DefaultNotificationService { 7151755cf8SAxel Dörfler public: 7251755cf8SAxel Dörfler PortNotificationService(); 7351755cf8SAxel Dörfler 7451755cf8SAxel Dörfler void Notify(uint32 opcode, port_id team); 7551755cf8SAxel Dörfler }; 76224aee3fSIngo Weinhold 77f28dd36bSAxel Dörfler 78f28dd36bSAxel Dörfler #if PORT_TRACING 79f28dd36bSAxel Dörfler namespace PortTracing { 80f28dd36bSAxel Dörfler 81f28dd36bSAxel Dörfler class Create : public AbstractTraceEntry { 82f28dd36bSAxel Dörfler public: 83f28dd36bSAxel Dörfler Create(port_entry& port) 84f28dd36bSAxel Dörfler : 85f28dd36bSAxel Dörfler fID(port.id), 86f28dd36bSAxel Dörfler fOwner(port.owner), 87f28dd36bSAxel Dörfler fCapacity(port.capacity) 88f28dd36bSAxel Dörfler { 89f28dd36bSAxel Dörfler fName = alloc_tracing_buffer_strcpy(port.lock.name, B_OS_NAME_LENGTH, 90f28dd36bSAxel Dörfler false); 91f28dd36bSAxel Dörfler 92f28dd36bSAxel Dörfler Initialized(); 93f28dd36bSAxel Dörfler } 94f28dd36bSAxel Dörfler 95f28dd36bSAxel Dörfler virtual void AddDump(TraceOutput& out) 96f28dd36bSAxel Dörfler { 97f28dd36bSAxel Dörfler out.Print("port %ld created, name \"%s\", owner %ld, capacity %ld", 98f28dd36bSAxel Dörfler fID, fName, fOwner, fCapacity); 99f28dd36bSAxel Dörfler } 100f28dd36bSAxel Dörfler 101f28dd36bSAxel Dörfler private: 102f28dd36bSAxel Dörfler port_id fID; 103f28dd36bSAxel Dörfler char* fName; 104f28dd36bSAxel Dörfler team_id fOwner; 105f28dd36bSAxel Dörfler int32 fCapacity; 106f28dd36bSAxel Dörfler }; 107f28dd36bSAxel Dörfler 108f28dd36bSAxel Dörfler 109f28dd36bSAxel Dörfler class Delete : public AbstractTraceEntry { 110f28dd36bSAxel Dörfler public: 111f28dd36bSAxel Dörfler Delete(port_entry& port) 112f28dd36bSAxel Dörfler : 113f28dd36bSAxel Dörfler fID(port.id) 114f28dd36bSAxel Dörfler { 115f28dd36bSAxel Dörfler Initialized(); 116f28dd36bSAxel Dörfler } 117f28dd36bSAxel Dörfler 118f28dd36bSAxel Dörfler virtual void AddDump(TraceOutput& out) 119f28dd36bSAxel Dörfler { 120f28dd36bSAxel Dörfler out.Print("port %ld deleted", fID); 121f28dd36bSAxel Dörfler } 122f28dd36bSAxel Dörfler 123f28dd36bSAxel Dörfler private: 124f28dd36bSAxel Dörfler port_id fID; 125f28dd36bSAxel Dörfler }; 126f28dd36bSAxel Dörfler 127f28dd36bSAxel Dörfler 128f28dd36bSAxel Dörfler class Read : public AbstractTraceEntry { 129f28dd36bSAxel Dörfler public: 130f28dd36bSAxel Dörfler Read(port_entry& port, int32 code, ssize_t result) 131f28dd36bSAxel Dörfler : 132f28dd36bSAxel Dörfler fID(port.id), 133f28dd36bSAxel Dörfler fReadCount(port.read_count), 134f28dd36bSAxel Dörfler fWriteCount(port.write_count), 135f28dd36bSAxel Dörfler fCode(code), 136f28dd36bSAxel Dörfler fResult(result) 137f28dd36bSAxel Dörfler { 138f28dd36bSAxel Dörfler Initialized(); 139f28dd36bSAxel Dörfler } 140f28dd36bSAxel Dörfler 141f28dd36bSAxel Dörfler virtual void AddDump(TraceOutput& out) 142f28dd36bSAxel Dörfler { 143f28dd36bSAxel Dörfler out.Print("port %ld read, read %ld, write %ld, code %lx: %ld", 144f28dd36bSAxel Dörfler fID, fReadCount, fWriteCount, fCode, fResult); 145f28dd36bSAxel Dörfler } 146f28dd36bSAxel Dörfler 147f28dd36bSAxel Dörfler private: 148f28dd36bSAxel Dörfler port_id fID; 149f28dd36bSAxel Dörfler int32 fReadCount; 150f28dd36bSAxel Dörfler int32 fWriteCount; 151f28dd36bSAxel Dörfler int32 fCode; 152f28dd36bSAxel Dörfler ssize_t fResult; 153f28dd36bSAxel Dörfler }; 154f28dd36bSAxel Dörfler 155f28dd36bSAxel Dörfler 156f28dd36bSAxel Dörfler class Write : public AbstractTraceEntry { 157f28dd36bSAxel Dörfler public: 158f28dd36bSAxel Dörfler Write(port_entry& port, int32 code, size_t bufferSize, ssize_t result) 159f28dd36bSAxel Dörfler : 160f28dd36bSAxel Dörfler fID(port.id), 161f28dd36bSAxel Dörfler fReadCount(port.read_count), 162f28dd36bSAxel Dörfler fWriteCount(port.write_count), 163f28dd36bSAxel Dörfler fCode(code), 164f28dd36bSAxel Dörfler fBufferSize(bufferSize), 165f28dd36bSAxel Dörfler fResult(result) 166f28dd36bSAxel Dörfler { 167f28dd36bSAxel Dörfler Initialized(); 168f28dd36bSAxel Dörfler } 169f28dd36bSAxel Dörfler 170f28dd36bSAxel Dörfler virtual void AddDump(TraceOutput& out) 171f28dd36bSAxel Dörfler { 172f28dd36bSAxel Dörfler out.Print("port %ld write, read %ld, write %ld, code %lx, size %ld: %ld", 173f28dd36bSAxel Dörfler fID, fReadCount, fWriteCount, fCode, fBufferSize, fResult); 174f28dd36bSAxel Dörfler } 175f28dd36bSAxel Dörfler 176f28dd36bSAxel Dörfler private: 177f28dd36bSAxel Dörfler port_id fID; 178f28dd36bSAxel Dörfler int32 fReadCount; 179f28dd36bSAxel Dörfler int32 fWriteCount; 180f28dd36bSAxel Dörfler int32 fCode; 181f28dd36bSAxel Dörfler size_t fBufferSize; 182f28dd36bSAxel Dörfler ssize_t fResult; 183f28dd36bSAxel Dörfler }; 184f28dd36bSAxel Dörfler 185f28dd36bSAxel Dörfler 186f28dd36bSAxel Dörfler class Info : public AbstractTraceEntry { 187f28dd36bSAxel Dörfler public: 188f28dd36bSAxel Dörfler Info(port_entry& port, int32 code, ssize_t result) 189f28dd36bSAxel Dörfler : 190f28dd36bSAxel Dörfler fID(port.id), 191f28dd36bSAxel Dörfler fReadCount(port.read_count), 192f28dd36bSAxel Dörfler fWriteCount(port.write_count), 193f28dd36bSAxel Dörfler fCode(code), 194f28dd36bSAxel Dörfler fResult(result) 195f28dd36bSAxel Dörfler { 196f28dd36bSAxel Dörfler Initialized(); 197f28dd36bSAxel Dörfler } 198f28dd36bSAxel Dörfler 199f28dd36bSAxel Dörfler virtual void AddDump(TraceOutput& out) 200f28dd36bSAxel Dörfler { 201f28dd36bSAxel Dörfler out.Print("port %ld info, read %ld, write %ld, code %lx: %ld", 202f28dd36bSAxel Dörfler fID, fReadCount, fWriteCount, fCode, fResult); 203f28dd36bSAxel Dörfler } 204f28dd36bSAxel Dörfler 205f28dd36bSAxel Dörfler private: 206f28dd36bSAxel Dörfler port_id fID; 207f28dd36bSAxel Dörfler int32 fReadCount; 208f28dd36bSAxel Dörfler int32 fWriteCount; 209f28dd36bSAxel Dörfler int32 fCode; 210f28dd36bSAxel Dörfler ssize_t fResult; 211f28dd36bSAxel Dörfler }; 212f28dd36bSAxel Dörfler 213f28dd36bSAxel Dörfler 214f28dd36bSAxel Dörfler class OwnerChange : public AbstractTraceEntry { 215f28dd36bSAxel Dörfler public: 216f28dd36bSAxel Dörfler OwnerChange(port_entry& port, team_id newOwner, status_t status) 217f28dd36bSAxel Dörfler : 218f28dd36bSAxel Dörfler fID(port.id), 219f28dd36bSAxel Dörfler fOldOwner(port.owner), 220f28dd36bSAxel Dörfler fNewOwner(newOwner), 221f28dd36bSAxel Dörfler fStatus(status) 222f28dd36bSAxel Dörfler { 223f28dd36bSAxel Dörfler Initialized(); 224f28dd36bSAxel Dörfler } 225f28dd36bSAxel Dörfler 226f28dd36bSAxel Dörfler virtual void AddDump(TraceOutput& out) 227f28dd36bSAxel Dörfler { 228f28dd36bSAxel Dörfler out.Print("port %ld owner change from %ld to %ld: %s", fID, fOldOwner, 229f28dd36bSAxel Dörfler fNewOwner, strerror(fStatus)); 230f28dd36bSAxel Dörfler } 231f28dd36bSAxel Dörfler 232f28dd36bSAxel Dörfler private: 233f28dd36bSAxel Dörfler port_id fID; 234f28dd36bSAxel Dörfler team_id fOldOwner; 235f28dd36bSAxel Dörfler team_id fNewOwner; 236f28dd36bSAxel Dörfler status_t fStatus; 237f28dd36bSAxel Dörfler }; 238f28dd36bSAxel Dörfler 239f28dd36bSAxel Dörfler } // namespace PortTracing 240f28dd36bSAxel Dörfler 241f28dd36bSAxel Dörfler # define T(x) new(std::nothrow) PortTracing::x; 242f28dd36bSAxel Dörfler #else 243f28dd36bSAxel Dörfler # define T(x) ; 244f28dd36bSAxel Dörfler #endif 245f28dd36bSAxel Dörfler 246f28dd36bSAxel Dörfler 247e8885f20SAxel Dörfler static const size_t kInitialPortBufferSize = 4 * 1024 * 1024; 248f28dd36bSAxel Dörfler static const size_t kTotalSpaceLimit = 64 * 1024 * 1024; 249f28dd36bSAxel Dörfler static const size_t kTeamSpaceLimit = 8 * 1024 * 1024; 250f28dd36bSAxel Dörfler static const size_t kBufferGrowRate = kInitialPortBufferSize; 251f28dd36bSAxel Dörfler 252224aee3fSIngo Weinhold #define MAX_QUEUE_LENGTH 4096 2535f87692cSIngo Weinhold #define PORT_MAX_MESSAGE_SIZE (256 * 1024) 254224aee3fSIngo Weinhold 255224aee3fSIngo Weinhold // sMaxPorts must be power of 2 256224aee3fSIngo Weinhold static int32 sMaxPorts = 4096; 257224aee3fSIngo Weinhold static int32 sUsedPorts = 0; 258224aee3fSIngo Weinhold 259e8885f20SAxel Dörfler static struct port_entry* sPorts; 260e8885f20SAxel Dörfler static area_id sPortArea; 261e8885f20SAxel Dörfler static heap_allocator* sPortAllocator; 262f28dd36bSAxel Dörfler static ConditionVariable sNoSpaceCondition; 263f28dd36bSAxel Dörfler static vint32 sTotalSpaceInUse; 264f28dd36bSAxel Dörfler static vint32 sAreaChangeCounter; 265f28dd36bSAxel Dörfler static vint32 sAllocatingArea; 266224aee3fSIngo Weinhold static bool sPortsActive = false; 267224aee3fSIngo Weinhold static port_id sNextPort = 1; 268224aee3fSIngo Weinhold static int32 sFirstFreeSlot = 1; 269e8885f20SAxel Dörfler static mutex sPortsLock = MUTEX_INITIALIZER("ports list"); 270224aee3fSIngo Weinhold 27151755cf8SAxel Dörfler static PortNotificationService sNotificationService; 27251755cf8SAxel Dörfler 273224aee3fSIngo Weinhold 27451755cf8SAxel Dörfler // #pragma mark - TeamNotificationService 27551755cf8SAxel Dörfler 27651755cf8SAxel Dörfler 27751755cf8SAxel Dörfler PortNotificationService::PortNotificationService() 278e8885f20SAxel Dörfler : 279e8885f20SAxel Dörfler DefaultNotificationService("ports") 28051755cf8SAxel Dörfler { 28151755cf8SAxel Dörfler } 28251755cf8SAxel Dörfler 28351755cf8SAxel Dörfler 28451755cf8SAxel Dörfler void 28551755cf8SAxel Dörfler PortNotificationService::Notify(uint32 opcode, port_id port) 28651755cf8SAxel Dörfler { 28751755cf8SAxel Dörfler char eventBuffer[64]; 28851755cf8SAxel Dörfler KMessage event; 28951755cf8SAxel Dörfler event.SetTo(eventBuffer, sizeof(eventBuffer), PORT_MONITOR); 290efd536ffSIngo Weinhold event.AddInt32("event", opcode); 29151755cf8SAxel Dörfler event.AddInt32("port", port); 29251755cf8SAxel Dörfler 293efd536ffSIngo Weinhold DefaultNotificationService::Notify(event, opcode); 29451755cf8SAxel Dörfler } 29551755cf8SAxel Dörfler 29651755cf8SAxel Dörfler 29751755cf8SAxel Dörfler // #pragma mark - 29851755cf8SAxel Dörfler 29951755cf8SAxel Dörfler 300224aee3fSIngo Weinhold static int 301224aee3fSIngo Weinhold dump_port_list(int argc, char** argv) 302224aee3fSIngo Weinhold { 303224aee3fSIngo Weinhold const char* name = NULL; 304224aee3fSIngo Weinhold team_id owner = -1; 305224aee3fSIngo Weinhold int32 i; 306224aee3fSIngo Weinhold 307224aee3fSIngo Weinhold if (argc > 2) { 308224aee3fSIngo Weinhold if (!strcmp(argv[1], "team") || !strcmp(argv[1], "owner")) 309224aee3fSIngo Weinhold owner = strtoul(argv[2], NULL, 0); 310224aee3fSIngo Weinhold else if (!strcmp(argv[1], "name")) 311224aee3fSIngo Weinhold name = argv[2]; 312224aee3fSIngo Weinhold } else if (argc > 1) 313224aee3fSIngo Weinhold owner = strtoul(argv[1], NULL, 0); 314224aee3fSIngo Weinhold 315e8885f20SAxel Dörfler kprintf("port id cap read-cnt write-cnt total team " 316e8885f20SAxel Dörfler "name\n"); 317224aee3fSIngo Weinhold 318224aee3fSIngo Weinhold for (i = 0; i < sMaxPorts; i++) { 319224aee3fSIngo Weinhold struct port_entry* port = &sPorts[i]; 320224aee3fSIngo Weinhold if (port->id < 0 321224aee3fSIngo Weinhold || (owner != -1 && port->owner != owner) 322e8885f20SAxel Dörfler || (name != NULL && strstr(port->lock.name, name) == NULL)) 323224aee3fSIngo Weinhold continue; 324224aee3fSIngo Weinhold 325e8885f20SAxel Dörfler kprintf("%p %8ld %4ld %9ld %9ld %8ld %6ld %s\n", port, 326e8885f20SAxel Dörfler port->id, port->capacity, port->read_count, port->write_count, 327e8885f20SAxel Dörfler port->total_count, port->owner, port->lock.name); 328224aee3fSIngo Weinhold } 329e8885f20SAxel Dörfler 330224aee3fSIngo Weinhold return 0; 331224aee3fSIngo Weinhold } 332224aee3fSIngo Weinhold 333224aee3fSIngo Weinhold 334224aee3fSIngo Weinhold static void 335224aee3fSIngo Weinhold _dump_port_info(struct port_entry* port) 336224aee3fSIngo Weinhold { 337224aee3fSIngo Weinhold kprintf("PORT: %p\n", port); 3383cad4daeSMarcus Overhagen kprintf(" id: %ld\n", port->id); 339e8885f20SAxel Dörfler kprintf(" name: \"%s\"\n", port->lock.name); 3403cad4daeSMarcus Overhagen kprintf(" owner: %ld\n", port->owner); 341224aee3fSIngo Weinhold kprintf(" capacity: %ld\n", port->capacity); 342e8885f20SAxel Dörfler kprintf(" read_count: %ld\n", port->read_count); 343e8885f20SAxel Dörfler kprintf(" write_count: %ld\n", port->write_count); 344224aee3fSIngo Weinhold kprintf(" total count: %ld\n", port->total_count); 3455aee691eSIngo Weinhold 346f28dd36bSAxel Dörfler if (!port->messages.IsEmpty()) { 347f28dd36bSAxel Dörfler kprintf("messages:\n"); 348f28dd36bSAxel Dörfler 349f28dd36bSAxel Dörfler MessageList::Iterator iterator = port->messages.GetIterator(); 350f28dd36bSAxel Dörfler while (port_message* message = iterator.Next()) { 351f28dd36bSAxel Dörfler kprintf(" %p %08lx %ld\n", message, message->code, message->size); 352f28dd36bSAxel Dörfler } 353f28dd36bSAxel Dörfler } 354f28dd36bSAxel Dörfler 3555aee691eSIngo Weinhold set_debug_variable("_port", (addr_t)port); 3565aee691eSIngo Weinhold set_debug_variable("_portID", port->id); 3575aee691eSIngo Weinhold set_debug_variable("_owner", port->owner); 358224aee3fSIngo Weinhold } 359224aee3fSIngo Weinhold 360224aee3fSIngo Weinhold 361224aee3fSIngo Weinhold static int 362224aee3fSIngo Weinhold dump_port_info(int argc, char** argv) 363224aee3fSIngo Weinhold { 364e8885f20SAxel Dörfler ConditionVariable* condition = NULL; 365f28dd36bSAxel Dörfler const char* name = NULL; 366224aee3fSIngo Weinhold 367224aee3fSIngo Weinhold if (argc < 2) { 368ce637fdaSIngo Weinhold print_debugger_command_usage(argv[0]); 369224aee3fSIngo Weinhold return 0; 370224aee3fSIngo Weinhold } 371224aee3fSIngo Weinhold 372224aee3fSIngo Weinhold if (argc > 2) { 373224aee3fSIngo Weinhold if (!strcmp(argv[1], "address")) { 374f28dd36bSAxel Dörfler _dump_port_info((struct port_entry*)parse_expression(argv[2])); 375224aee3fSIngo Weinhold return 0; 376e8885f20SAxel Dörfler } else if (!strcmp(argv[1], "condition")) 377f28dd36bSAxel Dörfler condition = (ConditionVariable*)parse_expression(argv[2]); 378224aee3fSIngo Weinhold else if (!strcmp(argv[1], "name")) 379224aee3fSIngo Weinhold name = argv[2]; 380f28dd36bSAxel Dörfler } else if (parse_expression(argv[1]) > 0) { 381224aee3fSIngo Weinhold // if the argument looks like a number, treat it as such 382f28dd36bSAxel Dörfler int32 num = parse_expression(argv[1]); 383f28dd36bSAxel Dörfler int32 slot = num % sMaxPorts; 384f28dd36bSAxel Dörfler if (sPorts[slot].id != num) { 385224aee3fSIngo Weinhold kprintf("port %ld (%#lx) doesn't exist!\n", num, num); 386224aee3fSIngo Weinhold return 0; 387224aee3fSIngo Weinhold } 388224aee3fSIngo Weinhold _dump_port_info(&sPorts[slot]); 389224aee3fSIngo Weinhold return 0; 390224aee3fSIngo Weinhold } else 391224aee3fSIngo Weinhold name = argv[1]; 392224aee3fSIngo Weinhold 393224aee3fSIngo Weinhold // walk through the ports list, trying to match name 394f28dd36bSAxel Dörfler for (int32 i = 0; i < sMaxPorts; i++) { 395e8885f20SAxel Dörfler if ((name != NULL && sPorts[i].lock.name != NULL 396e8885f20SAxel Dörfler && !strcmp(name, sPorts[i].lock.name)) 397e8885f20SAxel Dörfler || (condition != NULL && (&sPorts[i].read_condition == condition 398e8885f20SAxel Dörfler || &sPorts[i].write_condition == condition))) { 399224aee3fSIngo Weinhold _dump_port_info(&sPorts[i]); 400224aee3fSIngo Weinhold return 0; 401224aee3fSIngo Weinhold } 402224aee3fSIngo Weinhold } 403224aee3fSIngo Weinhold 404224aee3fSIngo Weinhold return 0; 405224aee3fSIngo Weinhold } 406224aee3fSIngo Weinhold 407224aee3fSIngo Weinhold 408224aee3fSIngo Weinhold static void 409224aee3fSIngo Weinhold notify_port_select_events(int slot, uint16 events) 410224aee3fSIngo Weinhold { 411224aee3fSIngo Weinhold if (sPorts[slot].select_infos) 412224aee3fSIngo Weinhold notify_select_events_list(sPorts[slot].select_infos, events); 413224aee3fSIngo Weinhold } 414224aee3fSIngo Weinhold 415224aee3fSIngo Weinhold 416224aee3fSIngo Weinhold static void 417e8885f20SAxel Dörfler put_port_message(port_message* message) 418224aee3fSIngo Weinhold { 419f28dd36bSAxel Dörfler size_t size = sizeof(port_message) + message->size; 420e8885f20SAxel Dörfler heap_free(sPortAllocator, message); 421f28dd36bSAxel Dörfler 422f28dd36bSAxel Dörfler atomic_add(&sTotalSpaceInUse, -size); 423f28dd36bSAxel Dörfler sNoSpaceCondition.NotifyAll(); 424224aee3fSIngo Weinhold } 425224aee3fSIngo Weinhold 426224aee3fSIngo Weinhold 427f28dd36bSAxel Dörfler static status_t 428f28dd36bSAxel Dörfler get_port_message(int32 code, size_t bufferSize, uint32 flags, bigtime_t timeout, 429f28dd36bSAxel Dörfler port_message** _message) 430224aee3fSIngo Weinhold { 431f28dd36bSAxel Dörfler size_t size = sizeof(port_message) + bufferSize; 432f28dd36bSAxel Dörfler bool limitReached = false; 433f28dd36bSAxel Dörfler 434f28dd36bSAxel Dörfler while (true) { 435f28dd36bSAxel Dörfler if (atomic_add(&sTotalSpaceInUse, size) 436f28dd36bSAxel Dörfler > int32(kTotalSpaceLimit - size)) { 437f28dd36bSAxel Dörfler // TODO: add per team limit 438f28dd36bSAxel Dörfler // We are not allowed to create another heap area, as our 439f28dd36bSAxel Dörfler // space limit has been reached - just wait until we get 440f28dd36bSAxel Dörfler // some free space again. 441f28dd36bSAxel Dörfler limitReached = true; 442f28dd36bSAxel Dörfler 443f28dd36bSAxel Dörfler wait: 444f28dd36bSAxel Dörfler MutexLocker locker(sPortsLock); 445f28dd36bSAxel Dörfler 446f28dd36bSAxel Dörfler atomic_add(&sTotalSpaceInUse, -size); 447f28dd36bSAxel Dörfler 448f28dd36bSAxel Dörfler // TODO: we don't want to wait - but does that also mean we 449f28dd36bSAxel Dörfler // shouldn't wait for the area creation? 450f28dd36bSAxel Dörfler if (limitReached && (flags & B_RELATIVE_TIMEOUT) != 0 451f28dd36bSAxel Dörfler && timeout <= 0) 452f28dd36bSAxel Dörfler return B_WOULD_BLOCK; 453f28dd36bSAxel Dörfler 454f28dd36bSAxel Dörfler ConditionVariableEntry entry; 455f28dd36bSAxel Dörfler sNoSpaceCondition.Add(&entry); 456f28dd36bSAxel Dörfler 457f28dd36bSAxel Dörfler locker.Unlock(); 458f28dd36bSAxel Dörfler 459f28dd36bSAxel Dörfler status_t status = entry.Wait(flags, timeout); 460f28dd36bSAxel Dörfler if (status == B_TIMED_OUT) 461f28dd36bSAxel Dörfler return B_TIMED_OUT; 462f28dd36bSAxel Dörfler 463f28dd36bSAxel Dörfler // just try again 464f28dd36bSAxel Dörfler limitReached = false; 465f28dd36bSAxel Dörfler continue; 466224aee3fSIngo Weinhold } 467224aee3fSIngo Weinhold 468f28dd36bSAxel Dörfler int32 areaChangeCounter = atomic_get(&sAreaChangeCounter); 469f28dd36bSAxel Dörfler 470f28dd36bSAxel Dörfler // Quota is fulfilled, try to allocate the buffer 471f28dd36bSAxel Dörfler 472f28dd36bSAxel Dörfler port_message* message 473f28dd36bSAxel Dörfler = (port_message*)heap_memalign(sPortAllocator, 0, size); 474f28dd36bSAxel Dörfler if (message != NULL) { 475e8885f20SAxel Dörfler message->code = code; 476e8885f20SAxel Dörfler message->size = bufferSize; 477e8885f20SAxel Dörfler 478f28dd36bSAxel Dörfler *_message = message; 479f28dd36bSAxel Dörfler return B_OK; 480f28dd36bSAxel Dörfler } 481f28dd36bSAxel Dörfler 482f28dd36bSAxel Dörfler if (atomic_or(&sAllocatingArea, 1) != 0) { 483f28dd36bSAxel Dörfler // Just wait for someone else to create an area for us 484f28dd36bSAxel Dörfler goto wait; 485f28dd36bSAxel Dörfler } 486f28dd36bSAxel Dörfler 487f28dd36bSAxel Dörfler if (areaChangeCounter != atomic_get(&sAreaChangeCounter)) { 488f28dd36bSAxel Dörfler atomic_add(&sTotalSpaceInUse, -size); 489f28dd36bSAxel Dörfler continue; 490f28dd36bSAxel Dörfler } 491f28dd36bSAxel Dörfler 492f28dd36bSAxel Dörfler // Create a new area for the heap to use 493f28dd36bSAxel Dörfler 494f28dd36bSAxel Dörfler addr_t base; 495f28dd36bSAxel Dörfler area_id area = create_area("port grown buffer", (void**)&base, 496f28dd36bSAxel Dörfler B_ANY_KERNEL_ADDRESS, kBufferGrowRate, B_NO_LOCK, 497f28dd36bSAxel Dörfler B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 498f28dd36bSAxel Dörfler if (area < 0) { 499f28dd36bSAxel Dörfler // it's time to let the userland feel our pain 500f28dd36bSAxel Dörfler sNoSpaceCondition.NotifyAll(); 501f28dd36bSAxel Dörfler return B_NO_MEMORY; 502f28dd36bSAxel Dörfler } 503f28dd36bSAxel Dörfler 504f28dd36bSAxel Dörfler heap_add_area(sPortAllocator, area, base, kBufferGrowRate); 505f28dd36bSAxel Dörfler 506f28dd36bSAxel Dörfler atomic_add(&sAreaChangeCounter, 1); 507f28dd36bSAxel Dörfler sNoSpaceCondition.NotifyAll(); 508f28dd36bSAxel Dörfler atomic_and(&sAllocatingArea, 0); 509f28dd36bSAxel Dörfler } 510224aee3fSIngo Weinhold } 511224aee3fSIngo Weinhold 512224aee3fSIngo Weinhold 513224aee3fSIngo Weinhold /*! You need to own the port's lock when calling this function */ 514224aee3fSIngo Weinhold static bool 515224aee3fSIngo Weinhold is_port_closed(int32 slot) 516224aee3fSIngo Weinhold { 517224aee3fSIngo Weinhold return sPorts[slot].capacity == 0; 518224aee3fSIngo Weinhold } 519224aee3fSIngo Weinhold 520224aee3fSIngo Weinhold 521224aee3fSIngo Weinhold /*! Fills the port_info structure with information from the specified 522224aee3fSIngo Weinhold port. 523224aee3fSIngo Weinhold The port lock must be held when called. 524224aee3fSIngo Weinhold */ 525224aee3fSIngo Weinhold static void 526224aee3fSIngo Weinhold fill_port_info(struct port_entry* port, port_info* info, size_t size) 527224aee3fSIngo Weinhold { 528224aee3fSIngo Weinhold info->port = port->id; 529224aee3fSIngo Weinhold info->team = port->owner; 530224aee3fSIngo Weinhold info->capacity = port->capacity; 531224aee3fSIngo Weinhold 5327d592ec4SAxel Dörfler info->queue_count = port->read_count; 533224aee3fSIngo Weinhold info->total_count = port->total_count; 534224aee3fSIngo Weinhold 535e8885f20SAxel Dörfler strlcpy(info->name, port->lock.name, B_OS_NAME_LENGTH); 536e8885f20SAxel Dörfler } 537e8885f20SAxel Dörfler 538e8885f20SAxel Dörfler 539e8885f20SAxel Dörfler static ssize_t 540e8885f20SAxel Dörfler copy_port_message(port_message* message, int32* _code, void* buffer, 541e8885f20SAxel Dörfler size_t bufferSize, bool userCopy) 542e8885f20SAxel Dörfler { 543e8885f20SAxel Dörfler // check output buffer size 544e8885f20SAxel Dörfler size_t size = min_c(bufferSize, message->size); 545e8885f20SAxel Dörfler 546e8885f20SAxel Dörfler // copy message 547e8885f20SAxel Dörfler if (_code != NULL) 548e8885f20SAxel Dörfler *_code = message->code; 549e8885f20SAxel Dörfler 550e8885f20SAxel Dörfler if (size > 0) { 551e8885f20SAxel Dörfler if (userCopy) { 552e8885f20SAxel Dörfler status_t status = user_memcpy(buffer, message->buffer, size); 553e8885f20SAxel Dörfler if (status != B_OK) 554e8885f20SAxel Dörfler return status; 555e8885f20SAxel Dörfler } else 556e8885f20SAxel Dörfler memcpy(buffer, message->buffer, size); 557e8885f20SAxel Dörfler } 558e8885f20SAxel Dörfler 559e8885f20SAxel Dörfler return size; 560224aee3fSIngo Weinhold } 561224aee3fSIngo Weinhold 562224aee3fSIngo Weinhold 56386a999adSAxel Dörfler static void 56486a999adSAxel Dörfler uninit_port_locked(struct port_entry& port) 56586a999adSAxel Dörfler { 56686a999adSAxel Dörfler int32 id = port.id; 56786a999adSAxel Dörfler 56886a999adSAxel Dörfler // mark port as invalid 56986a999adSAxel Dörfler port.id = -1; 57086a999adSAxel Dörfler free((char*)port.lock.name); 57186a999adSAxel Dörfler port.lock.name = NULL; 57286a999adSAxel Dörfler 57386a999adSAxel Dörfler while (port_message* message = port.messages.RemoveHead()) { 57486a999adSAxel Dörfler put_port_message(message); 57586a999adSAxel Dörfler } 57686a999adSAxel Dörfler 57786a999adSAxel Dörfler notify_port_select_events(id % sMaxPorts, B_EVENT_INVALID); 57886a999adSAxel Dörfler port.select_infos = NULL; 57986a999adSAxel Dörfler 58086a999adSAxel Dörfler // Release the threads that were blocking on this port. 58186a999adSAxel Dörfler // read_port() will see the B_BAD_PORT_ID return value, and act accordingly 58286a999adSAxel Dörfler port.read_condition.NotifyAll(B_BAD_PORT_ID); 58386a999adSAxel Dörfler port.write_condition.NotifyAll(B_BAD_PORT_ID); 58486a999adSAxel Dörfler sNotificationService.Notify(PORT_REMOVED, id); 58586a999adSAxel Dörfler } 58686a999adSAxel Dörfler 58786a999adSAxel Dörfler 588224aee3fSIngo Weinhold // #pragma mark - private kernel API 589224aee3fSIngo Weinhold 590224aee3fSIngo Weinhold 59186a999adSAxel Dörfler /*! This function delets all the ports that are owned by the passed team. 592224aee3fSIngo Weinhold */ 59386a999adSAxel Dörfler void 59486a999adSAxel Dörfler delete_owned_ports(struct team* team) 595224aee3fSIngo Weinhold { 59686a999adSAxel Dörfler TRACE(("delete_owned_ports(owner = %ld)\n", team->id)); 597224aee3fSIngo Weinhold 59886a999adSAxel Dörfler struct list queue; 599224aee3fSIngo Weinhold 60086a999adSAxel Dörfler { 60186a999adSAxel Dörfler InterruptsSpinLocker locker(gTeamSpinlock); 60286a999adSAxel Dörfler list_move_to_list(&team->port_list, &queue); 603224aee3fSIngo Weinhold } 604224aee3fSIngo Weinhold 6058cd9a524SAxel Dörfler int32 firstSlot = sMaxPorts; 6068cd9a524SAxel Dörfler int32 count = 0; 6078cd9a524SAxel Dörfler 60886a999adSAxel Dörfler while (port_entry* port = (port_entry*)list_remove_head_item(&queue)) { 6098cd9a524SAxel Dörfler if (firstSlot > port->id % sMaxPorts) 6108cd9a524SAxel Dörfler firstSlot = port->id % sMaxPorts; 6118cd9a524SAxel Dörfler count++; 6128cd9a524SAxel Dörfler 61386a999adSAxel Dörfler MutexLocker locker(port->lock); 61486a999adSAxel Dörfler uninit_port_locked(*port); 61586a999adSAxel Dörfler } 6168cd9a524SAxel Dörfler 6178cd9a524SAxel Dörfler MutexLocker _(sPortsLock); 6188cd9a524SAxel Dörfler 6198cd9a524SAxel Dörfler // update the first free slot hint in the array 6208cd9a524SAxel Dörfler if (firstSlot < sFirstFreeSlot) 6218cd9a524SAxel Dörfler sFirstFreeSlot = firstSlot; 6228cd9a524SAxel Dörfler 6238cd9a524SAxel Dörfler sUsedPorts -= count; 624224aee3fSIngo Weinhold } 625224aee3fSIngo Weinhold 626224aee3fSIngo Weinhold 627224aee3fSIngo Weinhold int32 628224aee3fSIngo Weinhold port_max_ports(void) 629224aee3fSIngo Weinhold { 630224aee3fSIngo Weinhold return sMaxPorts; 631224aee3fSIngo Weinhold } 632224aee3fSIngo Weinhold 633224aee3fSIngo Weinhold 634224aee3fSIngo Weinhold int32 635224aee3fSIngo Weinhold port_used_ports(void) 636224aee3fSIngo Weinhold { 637224aee3fSIngo Weinhold return sUsedPorts; 638224aee3fSIngo Weinhold } 639224aee3fSIngo Weinhold 640224aee3fSIngo Weinhold 641224aee3fSIngo Weinhold status_t 642224aee3fSIngo Weinhold port_init(kernel_args *args) 643224aee3fSIngo Weinhold { 644224aee3fSIngo Weinhold size_t size = sizeof(struct port_entry) * sMaxPorts; 645224aee3fSIngo Weinhold 646224aee3fSIngo Weinhold // create and initialize ports table 647e8885f20SAxel Dörfler sPortArea = create_area("port_table", 648e8885f20SAxel Dörfler (void**)&sPorts, B_ANY_KERNEL_ADDRESS, size, B_FULL_LOCK, 649e8885f20SAxel Dörfler B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 650224aee3fSIngo Weinhold if (sPortArea < 0) { 651224aee3fSIngo Weinhold panic("unable to allocate kernel port table!\n"); 652224aee3fSIngo Weinhold return sPortArea; 653224aee3fSIngo Weinhold } 654224aee3fSIngo Weinhold 655224aee3fSIngo Weinhold memset(sPorts, 0, size); 656e8885f20SAxel Dörfler for (int32 i = 0; i < sMaxPorts; i++) { 657e8885f20SAxel Dörfler mutex_init(&sPorts[i].lock, NULL); 658224aee3fSIngo Weinhold sPorts[i].id = -1; 659e8885f20SAxel Dörfler sPorts[i].read_condition.Init(&sPorts[i], "port read"); 660e8885f20SAxel Dörfler sPorts[i].write_condition.Init(&sPorts[i], "port write"); 661e8885f20SAxel Dörfler } 662e8885f20SAxel Dörfler 663e8885f20SAxel Dörfler addr_t base; 664e8885f20SAxel Dörfler if (create_area("port heap", (void**)&base, B_ANY_KERNEL_ADDRESS, 665e8885f20SAxel Dörfler kInitialPortBufferSize, B_NO_LOCK, 666e8885f20SAxel Dörfler B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA) < 0) { 667e8885f20SAxel Dörfler panic("unable to allocate port area!\n"); 668e8885f20SAxel Dörfler return B_ERROR; 669e8885f20SAxel Dörfler } 670e8885f20SAxel Dörfler 671e8885f20SAxel Dörfler static const heap_class kBufferHeapClass = {"default", 100, 672e8885f20SAxel Dörfler PORT_MAX_MESSAGE_SIZE + sizeof(port_message), 2 * 1024, 673e8885f20SAxel Dörfler sizeof(port_message), 8, 4, 64}; 674e8885f20SAxel Dörfler sPortAllocator = heap_create_allocator("port buffer", base, 675e8885f20SAxel Dörfler kInitialPortBufferSize, &kBufferHeapClass, true); 676f28dd36bSAxel Dörfler if (sPortAllocator == NULL) { 677f28dd36bSAxel Dörfler panic("unable to create port heap"); 678f28dd36bSAxel Dörfler return B_NO_MEMORY; 679f28dd36bSAxel Dörfler } 680f28dd36bSAxel Dörfler 681f28dd36bSAxel Dörfler sNoSpaceCondition.Init(sPorts, "port space"); 682224aee3fSIngo Weinhold 683224aee3fSIngo Weinhold // add debugger commands 684ce637fdaSIngo Weinhold add_debugger_command_etc("ports", &dump_port_list, 685ce637fdaSIngo Weinhold "Dump a list of all active ports (for team, with name, etc.)", 686ce637fdaSIngo Weinhold "[ ([ \"team\" | \"owner\" ] <team>) | (\"name\" <name>) ]\n" 687ce637fdaSIngo Weinhold "Prints a list of all active ports meeting the given\n" 688ce637fdaSIngo Weinhold "requirement. If no argument is given, all ports are listed.\n" 689ce637fdaSIngo Weinhold " <team> - The team owning the ports.\n" 690ce637fdaSIngo Weinhold " <name> - Part of the name of the ports.\n", 0); 691ce637fdaSIngo Weinhold add_debugger_command_etc("port", &dump_port_info, 692ce637fdaSIngo Weinhold "Dump info about a particular port", 693f28dd36bSAxel Dörfler "(<id> | [ \"address\" ] <address>) | ([ \"name\" ] <name>) " 694f28dd36bSAxel Dörfler "| (\"condition\" <address>)\n" 695ce637fdaSIngo Weinhold "Prints info about the specified port.\n" 696ce637fdaSIngo Weinhold " <address> - Pointer to the port structure.\n" 697ce637fdaSIngo Weinhold " <name> - Name of the port.\n" 698f28dd36bSAxel Dörfler " <condition> - address of the port's read or write condition.\n", 0); 699224aee3fSIngo Weinhold 70051755cf8SAxel Dörfler new(&sNotificationService) PortNotificationService(); 701224aee3fSIngo Weinhold sPortsActive = true; 702224aee3fSIngo Weinhold return B_OK; 703224aee3fSIngo Weinhold } 704224aee3fSIngo Weinhold 705224aee3fSIngo Weinhold 706224aee3fSIngo Weinhold // #pragma mark - public kernel API 707224aee3fSIngo Weinhold 708224aee3fSIngo Weinhold 709224aee3fSIngo Weinhold port_id 710224aee3fSIngo Weinhold create_port(int32 queueLength, const char* name) 711224aee3fSIngo Weinhold { 71251755cf8SAxel Dörfler TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength, 71351755cf8SAxel Dörfler name)); 714224aee3fSIngo Weinhold 715e8885f20SAxel Dörfler if (!sPortsActive) { 716e8885f20SAxel Dörfler panic("ports used too early!\n"); 717224aee3fSIngo Weinhold return B_BAD_PORT_ID; 718e8885f20SAxel Dörfler } 719e8885f20SAxel Dörfler if (queueLength < 1 || queueLength > MAX_QUEUE_LENGTH) 720224aee3fSIngo Weinhold return B_BAD_VALUE; 721224aee3fSIngo Weinhold 72286a999adSAxel Dörfler struct team* team = thread_get_current_thread()->team; 72386a999adSAxel Dörfler if (team == NULL) 72486a999adSAxel Dörfler return B_BAD_TEAM_ID; 72586a999adSAxel Dörfler 726e8885f20SAxel Dörfler MutexLocker locker(sPortsLock); 727e8885f20SAxel Dörfler 728224aee3fSIngo Weinhold // check early on if there are any free port slots to use 729e8885f20SAxel Dörfler if (sUsedPorts >= sMaxPorts) 730e8885f20SAxel Dörfler return B_NO_MORE_PORTS; 731224aee3fSIngo Weinhold 732224aee3fSIngo Weinhold // check & dup name 733e8885f20SAxel Dörfler char* nameBuffer = strdup(name != NULL ? name : "unnamed port"); 734e8885f20SAxel Dörfler if (nameBuffer == NULL) 735e8885f20SAxel Dörfler return B_NO_MEMORY; 736224aee3fSIngo Weinhold 737e8885f20SAxel Dörfler sUsedPorts++; 738224aee3fSIngo Weinhold 739224aee3fSIngo Weinhold // find the first empty spot 740e8885f20SAxel Dörfler for (int32 slot = 0; slot < sMaxPorts; slot++) { 741224aee3fSIngo Weinhold int32 i = (slot + sFirstFreeSlot) % sMaxPorts; 742224aee3fSIngo Weinhold 743224aee3fSIngo Weinhold if (sPorts[i].id == -1) { 744224aee3fSIngo Weinhold // make the port_id be a multiple of the slot it's in 745224aee3fSIngo Weinhold if (i >= sNextPort % sMaxPorts) 746224aee3fSIngo Weinhold sNextPort += i - sNextPort % sMaxPorts; 747224aee3fSIngo Weinhold else 748224aee3fSIngo Weinhold sNextPort += sMaxPorts - (sNextPort % sMaxPorts - i); 749224aee3fSIngo Weinhold sFirstFreeSlot = slot + 1; 750224aee3fSIngo Weinhold 751e8885f20SAxel Dörfler MutexLocker portLocker(sPorts[i].lock); 752224aee3fSIngo Weinhold sPorts[i].id = sNextPort++; 753e8885f20SAxel Dörfler locker.Unlock(); 754224aee3fSIngo Weinhold 755224aee3fSIngo Weinhold sPorts[i].capacity = queueLength; 756e8885f20SAxel Dörfler sPorts[i].owner = team_get_current_team_id(); 757e8885f20SAxel Dörfler sPorts[i].lock.name = nameBuffer; 758e8885f20SAxel Dörfler sPorts[i].read_count = 0; 759e8885f20SAxel Dörfler sPorts[i].write_count = queueLength; 760224aee3fSIngo Weinhold sPorts[i].total_count = 0; 761224aee3fSIngo Weinhold sPorts[i].select_infos = NULL; 762224aee3fSIngo Weinhold 76386a999adSAxel Dörfler { 76486a999adSAxel Dörfler InterruptsSpinLocker teamLocker(gTeamSpinlock); 76586a999adSAxel Dörfler list_add_item(&team->port_list, &sPorts[i].team_link); 76686a999adSAxel Dörfler } 76786a999adSAxel Dörfler 768e8885f20SAxel Dörfler port_id id = sPorts[i].id; 769f28dd36bSAxel Dörfler 770f28dd36bSAxel Dörfler T(Create(sPorts[i])); 771e8885f20SAxel Dörfler portLocker.Unlock(); 772224aee3fSIngo Weinhold 773224aee3fSIngo Weinhold TRACE(("create_port() done: port created %ld\n", id)); 774224aee3fSIngo Weinhold 77551755cf8SAxel Dörfler sNotificationService.Notify(PORT_ADDED, id); 776224aee3fSIngo Weinhold return id; 777224aee3fSIngo Weinhold } 778224aee3fSIngo Weinhold } 779224aee3fSIngo Weinhold 780e8885f20SAxel Dörfler // Still not enough ports... - due to sUsedPorts, this cannot really 781e8885f20SAxel Dörfler // happen anymore. 782e8885f20SAxel Dörfler panic("out of ports, but sUsedPorts is broken"); 783e8885f20SAxel Dörfler return B_NO_MORE_PORTS; 784224aee3fSIngo Weinhold } 785224aee3fSIngo Weinhold 786224aee3fSIngo Weinhold 787224aee3fSIngo Weinhold status_t 788224aee3fSIngo Weinhold close_port(port_id id) 789224aee3fSIngo Weinhold { 790224aee3fSIngo Weinhold TRACE(("close_port(id = %ld)\n", id)); 791224aee3fSIngo Weinhold 792224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 793224aee3fSIngo Weinhold return B_BAD_PORT_ID; 794224aee3fSIngo Weinhold 795e8885f20SAxel Dörfler int32 slot = id % sMaxPorts; 796224aee3fSIngo Weinhold 797224aee3fSIngo Weinhold // walk through the sem list, trying to match name 798e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 799224aee3fSIngo Weinhold 800224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 801224aee3fSIngo Weinhold TRACE(("close_port: invalid port_id %ld\n", id)); 802224aee3fSIngo Weinhold return B_BAD_PORT_ID; 803224aee3fSIngo Weinhold } 804224aee3fSIngo Weinhold 805224aee3fSIngo Weinhold // mark port to disable writing - deleting the semaphores will 806224aee3fSIngo Weinhold // wake up waiting read/writes 807224aee3fSIngo Weinhold sPorts[slot].capacity = 0; 808224aee3fSIngo Weinhold 809224aee3fSIngo Weinhold notify_port_select_events(slot, B_EVENT_INVALID); 810224aee3fSIngo Weinhold sPorts[slot].select_infos = NULL; 811224aee3fSIngo Weinhold 812e8885f20SAxel Dörfler sPorts[slot].read_condition.NotifyAll(false, B_BAD_PORT_ID); 813e8885f20SAxel Dörfler sPorts[slot].write_condition.NotifyAll(false, B_BAD_PORT_ID); 814224aee3fSIngo Weinhold 815e8885f20SAxel Dörfler return B_OK; 816224aee3fSIngo Weinhold } 817224aee3fSIngo Weinhold 818224aee3fSIngo Weinhold 819224aee3fSIngo Weinhold status_t 820224aee3fSIngo Weinhold delete_port(port_id id) 821224aee3fSIngo Weinhold { 822224aee3fSIngo Weinhold TRACE(("delete_port(id = %ld)\n", id)); 823224aee3fSIngo Weinhold 824224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 825224aee3fSIngo Weinhold return B_BAD_PORT_ID; 826224aee3fSIngo Weinhold 827e8885f20SAxel Dörfler int32 slot = id % sMaxPorts; 828224aee3fSIngo Weinhold 829e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 830224aee3fSIngo Weinhold 831224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 832224aee3fSIngo Weinhold TRACE(("delete_port: invalid port_id %ld\n", id)); 833224aee3fSIngo Weinhold return B_BAD_PORT_ID; 834224aee3fSIngo Weinhold } 835224aee3fSIngo Weinhold 836f28dd36bSAxel Dörfler T(Delete(sPorts[slot])); 837f28dd36bSAxel Dörfler 83886a999adSAxel Dörfler { 83986a999adSAxel Dörfler InterruptsSpinLocker teamLocker(gTeamSpinlock); 84086a999adSAxel Dörfler list_remove_link(&sPorts[slot].team_link); 841e8885f20SAxel Dörfler } 842224aee3fSIngo Weinhold 84386a999adSAxel Dörfler uninit_port_locked(sPorts[slot]); 844224aee3fSIngo Weinhold 845e8885f20SAxel Dörfler locker.Unlock(); 846e8885f20SAxel Dörfler 847e8885f20SAxel Dörfler MutexLocker _(sPortsLock); 848e8885f20SAxel Dörfler 849e8885f20SAxel Dörfler // update the first free slot hint in the array 850e8885f20SAxel Dörfler if (slot < sFirstFreeSlot) 851e8885f20SAxel Dörfler sFirstFreeSlot = slot; 852e8885f20SAxel Dörfler 853e8885f20SAxel Dörfler sUsedPorts--; 854224aee3fSIngo Weinhold return B_OK; 855224aee3fSIngo Weinhold } 856224aee3fSIngo Weinhold 857224aee3fSIngo Weinhold 858224aee3fSIngo Weinhold status_t 859224aee3fSIngo Weinhold select_port(int32 id, struct select_info* info, bool kernel) 860224aee3fSIngo Weinhold { 861224aee3fSIngo Weinhold if (id < 0) 862224aee3fSIngo Weinhold return B_BAD_PORT_ID; 863224aee3fSIngo Weinhold 864e8885f20SAxel Dörfler int32 slot = id % sMaxPorts; 865224aee3fSIngo Weinhold 866e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 867224aee3fSIngo Weinhold 868e8885f20SAxel Dörfler if (sPorts[slot].id != id || is_port_closed(slot)) 869e8885f20SAxel Dörfler return B_BAD_PORT_ID; 870e8885f20SAxel Dörfler if (!kernel && sPorts[slot].owner == team_get_kernel_team_id()) { 871224aee3fSIngo Weinhold // kernel port, but call from userland 872e8885f20SAxel Dörfler return B_NOT_ALLOWED; 873e8885f20SAxel Dörfler } 874e8885f20SAxel Dörfler 875224aee3fSIngo Weinhold info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID; 876224aee3fSIngo Weinhold 877224aee3fSIngo Weinhold if (info->selected_events != 0) { 878224aee3fSIngo Weinhold uint16 events = 0; 879224aee3fSIngo Weinhold 880224aee3fSIngo Weinhold info->next = sPorts[slot].select_infos; 881224aee3fSIngo Weinhold sPorts[slot].select_infos = info; 882224aee3fSIngo Weinhold 883224aee3fSIngo Weinhold // check for events 884224aee3fSIngo Weinhold if ((info->selected_events & B_EVENT_READ) != 0 885e8885f20SAxel Dörfler && !sPorts[slot].messages.IsEmpty()) { 886224aee3fSIngo Weinhold events |= B_EVENT_READ; 887224aee3fSIngo Weinhold } 888224aee3fSIngo Weinhold 889e8885f20SAxel Dörfler if (sPorts[slot].write_count > 0) 890224aee3fSIngo Weinhold events |= B_EVENT_WRITE; 891224aee3fSIngo Weinhold 892224aee3fSIngo Weinhold if (events != 0) 893224aee3fSIngo Weinhold notify_select_events(info, events); 894224aee3fSIngo Weinhold } 895224aee3fSIngo Weinhold 896e8885f20SAxel Dörfler return B_OK; 897224aee3fSIngo Weinhold } 898224aee3fSIngo Weinhold 899224aee3fSIngo Weinhold 900224aee3fSIngo Weinhold status_t 901224aee3fSIngo Weinhold deselect_port(int32 id, struct select_info* info, bool kernel) 902224aee3fSIngo Weinhold { 903224aee3fSIngo Weinhold if (id < 0) 904224aee3fSIngo Weinhold return B_BAD_PORT_ID; 905224aee3fSIngo Weinhold if (info->selected_events == 0) 906224aee3fSIngo Weinhold return B_OK; 907224aee3fSIngo Weinhold 908e8885f20SAxel Dörfler int32 slot = id % sMaxPorts; 909224aee3fSIngo Weinhold 910e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 911224aee3fSIngo Weinhold 912224aee3fSIngo Weinhold if (sPorts[slot].id == id) { 913224aee3fSIngo Weinhold select_info** infoLocation = &sPorts[slot].select_infos; 914224aee3fSIngo Weinhold while (*infoLocation != NULL && *infoLocation != info) 915224aee3fSIngo Weinhold infoLocation = &(*infoLocation)->next; 916224aee3fSIngo Weinhold 917224aee3fSIngo Weinhold if (*infoLocation == info) 918224aee3fSIngo Weinhold *infoLocation = info->next; 919224aee3fSIngo Weinhold } 920224aee3fSIngo Weinhold 921224aee3fSIngo Weinhold return B_OK; 922224aee3fSIngo Weinhold } 923224aee3fSIngo Weinhold 924224aee3fSIngo Weinhold 925224aee3fSIngo Weinhold port_id 926224aee3fSIngo Weinhold find_port(const char* name) 927224aee3fSIngo Weinhold { 928224aee3fSIngo Weinhold TRACE(("find_port(name = \"%s\")\n", name)); 929224aee3fSIngo Weinhold 930e8885f20SAxel Dörfler if (!sPortsActive) { 931e8885f20SAxel Dörfler panic("ports used too early!\n"); 932224aee3fSIngo Weinhold return B_NAME_NOT_FOUND; 933e8885f20SAxel Dörfler } 934224aee3fSIngo Weinhold if (name == NULL) 935224aee3fSIngo Weinhold return B_BAD_VALUE; 936224aee3fSIngo Weinhold 937224aee3fSIngo Weinhold // Since we have to check every single port, and we don't 938224aee3fSIngo Weinhold // care if it goes away at any point, we're only grabbing 939224aee3fSIngo Weinhold // the port lock in question, not the port list lock 940224aee3fSIngo Weinhold 941224aee3fSIngo Weinhold // loop over list 942e8885f20SAxel Dörfler for (int32 i = 0; i < sMaxPorts; i++) { 943224aee3fSIngo Weinhold // lock every individual port before comparing 944e8885f20SAxel Dörfler MutexLocker _(sPorts[i].lock); 945224aee3fSIngo Weinhold 946e8885f20SAxel Dörfler if (sPorts[i].id >= 0 && !strcmp(name, sPorts[i].lock.name)) 947e8885f20SAxel Dörfler return sPorts[i].id; 948224aee3fSIngo Weinhold } 949224aee3fSIngo Weinhold 950e8885f20SAxel Dörfler return B_NAME_NOT_FOUND; 951224aee3fSIngo Weinhold } 952224aee3fSIngo Weinhold 953224aee3fSIngo Weinhold 954224aee3fSIngo Weinhold status_t 955224aee3fSIngo Weinhold _get_port_info(port_id id, port_info* info, size_t size) 956224aee3fSIngo Weinhold { 957224aee3fSIngo Weinhold TRACE(("get_port_info(id = %ld)\n", id)); 958224aee3fSIngo Weinhold 959224aee3fSIngo Weinhold if (info == NULL || size != sizeof(port_info)) 960224aee3fSIngo Weinhold return B_BAD_VALUE; 961224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 962224aee3fSIngo Weinhold return B_BAD_PORT_ID; 963224aee3fSIngo Weinhold 964e8885f20SAxel Dörfler int32 slot = id % sMaxPorts; 965224aee3fSIngo Weinhold 966e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 967224aee3fSIngo Weinhold 968224aee3fSIngo Weinhold if (sPorts[slot].id != id || sPorts[slot].capacity == 0) { 969224aee3fSIngo Weinhold TRACE(("get_port_info: invalid port_id %ld\n", id)); 970224aee3fSIngo Weinhold return B_BAD_PORT_ID; 971224aee3fSIngo Weinhold } 972224aee3fSIngo Weinhold 973224aee3fSIngo Weinhold // fill a port_info struct with info 974224aee3fSIngo Weinhold fill_port_info(&sPorts[slot], info, size); 975224aee3fSIngo Weinhold return B_OK; 976224aee3fSIngo Weinhold } 977224aee3fSIngo Weinhold 978224aee3fSIngo Weinhold 979224aee3fSIngo Weinhold status_t 980e8885f20SAxel Dörfler _get_next_port_info(team_id team, int32* _cookie, struct port_info* info, 981e8885f20SAxel Dörfler size_t size) 982224aee3fSIngo Weinhold { 983224aee3fSIngo Weinhold TRACE(("get_next_port_info(team = %ld)\n", team)); 984224aee3fSIngo Weinhold 985e8885f20SAxel Dörfler if (info == NULL || size != sizeof(port_info) || _cookie == NULL 986e8885f20SAxel Dörfler || team < B_OK) 987224aee3fSIngo Weinhold return B_BAD_VALUE; 988224aee3fSIngo Weinhold if (!sPortsActive) 989224aee3fSIngo Weinhold return B_BAD_PORT_ID; 990224aee3fSIngo Weinhold 991e8885f20SAxel Dörfler int32 slot = *_cookie; 992224aee3fSIngo Weinhold if (slot >= sMaxPorts) 993224aee3fSIngo Weinhold return B_BAD_PORT_ID; 994224aee3fSIngo Weinhold 995224aee3fSIngo Weinhold if (team == B_CURRENT_TEAM) 996224aee3fSIngo Weinhold team = team_get_current_team_id(); 997224aee3fSIngo Weinhold 998224aee3fSIngo Weinhold info->port = -1; // used as found flag 999224aee3fSIngo Weinhold 1000224aee3fSIngo Weinhold while (slot < sMaxPorts) { 1001e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 1002e8885f20SAxel Dörfler 1003e8885f20SAxel Dörfler if (sPorts[slot].id != -1 && !is_port_closed(slot) 1004e8885f20SAxel Dörfler && sPorts[slot].owner == team) { 1005224aee3fSIngo Weinhold // found one! 1006224aee3fSIngo Weinhold fill_port_info(&sPorts[slot], info, size); 1007224aee3fSIngo Weinhold slot++; 1008224aee3fSIngo Weinhold break; 1009224aee3fSIngo Weinhold } 1010e8885f20SAxel Dörfler 1011224aee3fSIngo Weinhold slot++; 1012224aee3fSIngo Weinhold } 1013224aee3fSIngo Weinhold 1014224aee3fSIngo Weinhold if (info->port == -1) 1015224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1016224aee3fSIngo Weinhold 1017224aee3fSIngo Weinhold *_cookie = slot; 1018e8885f20SAxel Dörfler return B_OK; 1019224aee3fSIngo Weinhold } 1020224aee3fSIngo Weinhold 1021224aee3fSIngo Weinhold 1022224aee3fSIngo Weinhold ssize_t 1023224aee3fSIngo Weinhold port_buffer_size(port_id id) 1024224aee3fSIngo Weinhold { 1025224aee3fSIngo Weinhold return port_buffer_size_etc(id, 0, 0); 1026224aee3fSIngo Weinhold } 1027224aee3fSIngo Weinhold 1028224aee3fSIngo Weinhold 1029224aee3fSIngo Weinhold ssize_t 1030224aee3fSIngo Weinhold port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout) 1031224aee3fSIngo Weinhold { 10327727e08eSIngo Weinhold port_message_info info; 10337727e08eSIngo Weinhold status_t error = get_port_message_info_etc(id, &info, flags, timeout); 10347727e08eSIngo Weinhold return error != B_OK ? error : info.size; 10357727e08eSIngo Weinhold } 10367727e08eSIngo Weinhold 1037e8885f20SAxel Dörfler 10387727e08eSIngo Weinhold status_t 10397727e08eSIngo Weinhold _get_port_message_info_etc(port_id id, port_message_info* info, 10407727e08eSIngo Weinhold size_t infoSize, uint32 flags, bigtime_t timeout) 10417727e08eSIngo Weinhold { 10427727e08eSIngo Weinhold if (info == NULL || infoSize != sizeof(port_message_info)) 10437727e08eSIngo Weinhold return B_BAD_VALUE; 1044224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 1045224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1046224aee3fSIngo Weinhold 1047f28dd36bSAxel Dörfler flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT 1048f28dd36bSAxel Dörfler | B_ABSOLUTE_TIMEOUT; 1049e8885f20SAxel Dörfler int32 slot = id % sMaxPorts; 1050224aee3fSIngo Weinhold 1051e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 1052224aee3fSIngo Weinhold 1053224aee3fSIngo Weinhold if (sPorts[slot].id != id 1054e8885f20SAxel Dörfler || (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) { 1055f28dd36bSAxel Dörfler T(Info(sPorts[slot], 0, B_BAD_PORT_ID)); 10567d592ec4SAxel Dörfler TRACE(("_get_port_message_info_etc(): %s port %ld\n", 1057224aee3fSIngo Weinhold sPorts[slot].id == id ? "closed" : "invalid", id)); 1058224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1059224aee3fSIngo Weinhold } 1060224aee3fSIngo Weinhold 10617d592ec4SAxel Dörfler while (sPorts[slot].read_count == 0) { 1062e8885f20SAxel Dörfler // We need to wait for a message to appear 1063f28dd36bSAxel Dörfler if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0) 1064f28dd36bSAxel Dörfler return B_WOULD_BLOCK; 1065f28dd36bSAxel Dörfler 1066e8885f20SAxel Dörfler ConditionVariableEntry entry; 1067e8885f20SAxel Dörfler sPorts[slot].read_condition.Add(&entry); 1068224aee3fSIngo Weinhold 1069e8885f20SAxel Dörfler locker.Unlock(); 1070224aee3fSIngo Weinhold 1071224aee3fSIngo Weinhold // block if no message, or, if B_TIMEOUT flag set, block with timeout 1072e8885f20SAxel Dörfler status_t status = entry.Wait(flags, timeout); 1073f28dd36bSAxel Dörfler 1074f28dd36bSAxel Dörfler if (status != B_OK) { 1075f28dd36bSAxel Dörfler T(Info(sPorts[slot], 0, status)); 1076224aee3fSIngo Weinhold return status; 1077f28dd36bSAxel Dörfler } 1078224aee3fSIngo Weinhold 1079e8885f20SAxel Dörfler locker.Lock(); 1080e8885f20SAxel Dörfler } 1081224aee3fSIngo Weinhold 1082224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 1083224aee3fSIngo Weinhold // the port is no longer there 1084224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1085224aee3fSIngo Weinhold } 1086224aee3fSIngo Weinhold 1087224aee3fSIngo Weinhold // determine tail & get the length of the message 1088e8885f20SAxel Dörfler port_message* message = sPorts[slot].messages.Head(); 1089e8885f20SAxel Dörfler if (message == NULL) { 1090224aee3fSIngo Weinhold panic("port %ld: no messages found\n", sPorts[slot].id); 1091e8885f20SAxel Dörfler return B_ERROR; 10927727e08eSIngo Weinhold } 1093224aee3fSIngo Weinhold 1094e8885f20SAxel Dörfler info->size = message->size; 1095e8885f20SAxel Dörfler info->sender = message->sender; 1096e8885f20SAxel Dörfler info->sender_group = message->sender_group; 1097e8885f20SAxel Dörfler info->sender_team = message->sender_team; 1098224aee3fSIngo Weinhold 1099f28dd36bSAxel Dörfler T(Info(sPorts[slot], message->code, B_OK)); 1100f28dd36bSAxel Dörfler 1101e8885f20SAxel Dörfler // notify next one, as we haven't read from the port 1102e8885f20SAxel Dörfler sPorts[slot].read_condition.NotifyOne(); 1103224aee3fSIngo Weinhold 1104e8885f20SAxel Dörfler return B_OK; 1105224aee3fSIngo Weinhold } 1106224aee3fSIngo Weinhold 1107224aee3fSIngo Weinhold 1108224aee3fSIngo Weinhold ssize_t 1109224aee3fSIngo Weinhold port_count(port_id id) 1110224aee3fSIngo Weinhold { 1111224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 1112224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1113224aee3fSIngo Weinhold 1114e8885f20SAxel Dörfler int32 slot = id % sMaxPorts; 1115224aee3fSIngo Weinhold 1116e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 1117224aee3fSIngo Weinhold 1118224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 1119224aee3fSIngo Weinhold TRACE(("port_count: invalid port_id %ld\n", id)); 1120224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1121224aee3fSIngo Weinhold } 1122224aee3fSIngo Weinhold 1123224aee3fSIngo Weinhold // return count of messages 11247d592ec4SAxel Dörfler return sPorts[slot].read_count; 1125224aee3fSIngo Weinhold } 1126224aee3fSIngo Weinhold 1127224aee3fSIngo Weinhold 1128224aee3fSIngo Weinhold ssize_t 1129e8885f20SAxel Dörfler read_port(port_id port, int32* msgCode, void* buffer, size_t bufferSize) 1130224aee3fSIngo Weinhold { 1131e8885f20SAxel Dörfler return read_port_etc(port, msgCode, buffer, bufferSize, 0, 0); 1132224aee3fSIngo Weinhold } 1133224aee3fSIngo Weinhold 1134224aee3fSIngo Weinhold 1135224aee3fSIngo Weinhold ssize_t 1136e8885f20SAxel Dörfler read_port_etc(port_id id, int32* _code, void* buffer, size_t bufferSize, 1137224aee3fSIngo Weinhold uint32 flags, bigtime_t timeout) 1138224aee3fSIngo Weinhold { 1139224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 1140224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1141e8885f20SAxel Dörfler if ((buffer == NULL && bufferSize > 0) || timeout < 0) 1142224aee3fSIngo Weinhold return B_BAD_VALUE; 1143224aee3fSIngo Weinhold 1144e8885f20SAxel Dörfler bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0; 1145e8885f20SAxel Dörfler bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0; 1146e8885f20SAxel Dörfler // TODO: we could allow peeking for user apps now 1147224aee3fSIngo Weinhold 1148e8885f20SAxel Dörfler flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT 1149e8885f20SAxel Dörfler | B_ABSOLUTE_TIMEOUT; 1150e8885f20SAxel Dörfler 1151e8885f20SAxel Dörfler int32 slot = id % sMaxPorts; 1152e8885f20SAxel Dörfler 1153e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 1154224aee3fSIngo Weinhold 1155224aee3fSIngo Weinhold if (sPorts[slot].id != id 1156e8885f20SAxel Dörfler || (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) { 1157f28dd36bSAxel Dörfler T(Read(sPorts[slot], 0, B_BAD_PORT_ID)); 1158224aee3fSIngo Weinhold TRACE(("read_port_etc(): %s port %ld\n", 1159224aee3fSIngo Weinhold sPorts[slot].id == id ? "closed" : "invalid", id)); 1160224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1161224aee3fSIngo Weinhold } 1162224aee3fSIngo Weinhold 11637d592ec4SAxel Dörfler while (sPorts[slot].read_count == 0) { 1164f28dd36bSAxel Dörfler if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0) 1165f28dd36bSAxel Dörfler return B_WOULD_BLOCK; 1166f28dd36bSAxel Dörfler 1167e8885f20SAxel Dörfler // We need to wait for a message to appear 1168e8885f20SAxel Dörfler ConditionVariableEntry entry; 1169e8885f20SAxel Dörfler sPorts[slot].read_condition.Add(&entry); 1170224aee3fSIngo Weinhold 1171e8885f20SAxel Dörfler locker.Unlock(); 1172224aee3fSIngo Weinhold 1173e8885f20SAxel Dörfler // block if no message, or, if B_TIMEOUT flag set, block with timeout 1174e8885f20SAxel Dörfler status_t status = entry.Wait(flags, timeout); 1175224aee3fSIngo Weinhold 1176e8885f20SAxel Dörfler locker.Lock(); 1177224aee3fSIngo Weinhold 1178e8885f20SAxel Dörfler if (sPorts[slot].id != id) { 1179e8885f20SAxel Dörfler // the port is no longer there 1180f28dd36bSAxel Dörfler T(Read(sPorts[slot], 0, B_BAD_PORT_ID)); 1181224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1182224aee3fSIngo Weinhold } 1183224aee3fSIngo Weinhold 1184*c3bc71d6SIngo Weinhold if (status != B_OK) { 1185*c3bc71d6SIngo Weinhold T(Read(sPorts[slot], 0, status)); 1186e8885f20SAxel Dörfler sPorts[slot].read_count++; 1187*c3bc71d6SIngo Weinhold return status; 1188e8885f20SAxel Dörfler } 11897d592ec4SAxel Dörfler } 1190224aee3fSIngo Weinhold 1191e8885f20SAxel Dörfler // determine tail & get the length of the message 1192e8885f20SAxel Dörfler port_message* message = sPorts[slot].messages.Head(); 1193e8885f20SAxel Dörfler if (message == NULL) { 1194e8885f20SAxel Dörfler panic("port %ld: no messages found\n", sPorts[slot].id); 1195e8885f20SAxel Dörfler return B_ERROR; 1196224aee3fSIngo Weinhold } 1197224aee3fSIngo Weinhold 1198b4ec7b8eSIngo Weinhold if (peekOnly) { 1199e8885f20SAxel Dörfler size_t size = copy_port_message(message, _code, buffer, bufferSize, 1200e8885f20SAxel Dörfler userCopy); 1201e8885f20SAxel Dörfler 1202f28dd36bSAxel Dörfler T(Read(sPorts[slot], message->code, size)); 1203f28dd36bSAxel Dörfler 1204e8885f20SAxel Dörfler sPorts[slot].read_condition.NotifyOne(); 1205b4ec7b8eSIngo Weinhold // we only peeked, but didn't grab the message 1206b4ec7b8eSIngo Weinhold return size; 1207b4ec7b8eSIngo Weinhold } 1208b4ec7b8eSIngo Weinhold 1209e8885f20SAxel Dörfler sPorts[slot].messages.RemoveHead(); 1210224aee3fSIngo Weinhold sPorts[slot].total_count++; 1211e8885f20SAxel Dörfler sPorts[slot].write_count++; 12127d592ec4SAxel Dörfler sPorts[slot].read_count--; 1213224aee3fSIngo Weinhold 1214224aee3fSIngo Weinhold notify_port_select_events(slot, B_EVENT_WRITE); 1215e8885f20SAxel Dörfler sPorts[slot].write_condition.NotifyOne(); 1216224aee3fSIngo Weinhold // make one spot in queue available again for write 1217224aee3fSIngo Weinhold 1218e8885f20SAxel Dörfler locker.Unlock(); 1219e8885f20SAxel Dörfler 1220e8885f20SAxel Dörfler size_t size = copy_port_message(message, _code, buffer, bufferSize, 1221e8885f20SAxel Dörfler userCopy); 1222f28dd36bSAxel Dörfler T(Read(sPorts[slot], message->code, size)); 1223e8885f20SAxel Dörfler 1224e8885f20SAxel Dörfler put_port_message(message); 1225224aee3fSIngo Weinhold return size; 1226224aee3fSIngo Weinhold } 1227224aee3fSIngo Weinhold 1228224aee3fSIngo Weinhold 1229224aee3fSIngo Weinhold status_t 1230e8885f20SAxel Dörfler write_port(port_id id, int32 msgCode, const void* buffer, size_t bufferSize) 1231224aee3fSIngo Weinhold { 1232e8885f20SAxel Dörfler iovec vec = { (void*)buffer, bufferSize }; 1233224aee3fSIngo Weinhold 1234224aee3fSIngo Weinhold return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0); 1235224aee3fSIngo Weinhold } 1236224aee3fSIngo Weinhold 1237224aee3fSIngo Weinhold 1238224aee3fSIngo Weinhold status_t 1239e8885f20SAxel Dörfler write_port_etc(port_id id, int32 msgCode, const void* buffer, 1240224aee3fSIngo Weinhold size_t bufferSize, uint32 flags, bigtime_t timeout) 1241224aee3fSIngo Weinhold { 1242e8885f20SAxel Dörfler iovec vec = { (void*)buffer, bufferSize }; 1243224aee3fSIngo Weinhold 1244224aee3fSIngo Weinhold return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout); 1245224aee3fSIngo Weinhold } 1246224aee3fSIngo Weinhold 1247224aee3fSIngo Weinhold 1248224aee3fSIngo Weinhold status_t 1249224aee3fSIngo Weinhold writev_port_etc(port_id id, int32 msgCode, const iovec* msgVecs, 1250e8885f20SAxel Dörfler size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout) 1251224aee3fSIngo Weinhold { 1252224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 1253224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1254224aee3fSIngo Weinhold if (bufferSize > PORT_MAX_MESSAGE_SIZE) 1255224aee3fSIngo Weinhold return B_BAD_VALUE; 1256224aee3fSIngo Weinhold 1257e8885f20SAxel Dörfler // mask irrelevant flags (for acquire_sem() usage) 1258e8885f20SAxel Dörfler flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT 1259e8885f20SAxel Dörfler | B_ABSOLUTE_TIMEOUT; 1260f28dd36bSAxel Dörfler if ((flags & B_RELATIVE_TIMEOUT) != 0 1261f28dd36bSAxel Dörfler && timeout != B_INFINITE_TIMEOUT && timeout > 0) { 1262f28dd36bSAxel Dörfler // Make the timeout absolute, since we have more than one step where 1263f28dd36bSAxel Dörfler // we might have to wait 1264f28dd36bSAxel Dörfler flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT; 1265f28dd36bSAxel Dörfler timeout += system_time(); 1266f28dd36bSAxel Dörfler } 1267f28dd36bSAxel Dörfler 1268e8885f20SAxel Dörfler bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0; 1269e8885f20SAxel Dörfler 1270e8885f20SAxel Dörfler int32 slot = id % sMaxPorts; 1271f28dd36bSAxel Dörfler status_t status; 12721c61ec1aSIngo Weinhold port_message* message = NULL; 1273e8885f20SAxel Dörfler 1274e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 1275224aee3fSIngo Weinhold 1276224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 1277224aee3fSIngo Weinhold TRACE(("write_port_etc: invalid port_id %ld\n", id)); 1278224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1279224aee3fSIngo Weinhold } 1280224aee3fSIngo Weinhold if (is_port_closed(slot)) { 1281224aee3fSIngo Weinhold TRACE(("write_port_etc: port %ld closed\n", id)); 1282224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1283224aee3fSIngo Weinhold } 1284224aee3fSIngo Weinhold 1285f28dd36bSAxel Dörfler if (sPorts[slot].write_count <= 0) { 1286f28dd36bSAxel Dörfler if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0) 1287f28dd36bSAxel Dörfler return B_WOULD_BLOCK; 1288f28dd36bSAxel Dörfler 1289f28dd36bSAxel Dörfler sPorts[slot].write_count--; 1290f28dd36bSAxel Dörfler 1291e8885f20SAxel Dörfler // We need to block in order to wait for a free message slot 1292e8885f20SAxel Dörfler ConditionVariableEntry entry; 1293e8885f20SAxel Dörfler sPorts[slot].write_condition.Add(&entry); 1294224aee3fSIngo Weinhold 1295e8885f20SAxel Dörfler locker.Unlock(); 1296224aee3fSIngo Weinhold 1297f28dd36bSAxel Dörfler status = entry.Wait(flags, timeout); 1298224aee3fSIngo Weinhold 1299e8885f20SAxel Dörfler locker.Lock(); 1300e8885f20SAxel Dörfler 13013ffeff07SIngo Weinhold if (sPorts[slot].id != id || is_port_closed(slot)) { 1302e8885f20SAxel Dörfler // the port is no longer there 1303f28dd36bSAxel Dörfler T(Write(sPorts[slot], 0, 0, B_BAD_PORT_ID)); 1304224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1305224aee3fSIngo Weinhold } 1306224aee3fSIngo Weinhold 1307*c3bc71d6SIngo Weinhold if (status != B_OK) 1308f28dd36bSAxel Dörfler goto error; 1309f28dd36bSAxel Dörfler } else 1310f28dd36bSAxel Dörfler sPorts[slot].write_count--; 1311e8885f20SAxel Dörfler 1312f28dd36bSAxel Dörfler status = get_port_message(msgCode, bufferSize, flags, timeout, 1313f28dd36bSAxel Dörfler &message); 1314f28dd36bSAxel Dörfler if (status != B_OK) 1315f28dd36bSAxel Dörfler goto error; 1316224aee3fSIngo Weinhold 13177727e08eSIngo Weinhold // sender credentials 1318e8885f20SAxel Dörfler message->sender = geteuid(); 1319e8885f20SAxel Dörfler message->sender_group = getegid(); 1320e8885f20SAxel Dörfler message->sender_team = team_get_current_team_id(); 13217727e08eSIngo Weinhold 1322224aee3fSIngo Weinhold if (bufferSize > 0) { 1323224aee3fSIngo Weinhold uint32 i; 1324224aee3fSIngo Weinhold if (userCopy) { 1325224aee3fSIngo Weinhold // copy from user memory 1326224aee3fSIngo Weinhold for (i = 0; i < vecCount; i++) { 1327224aee3fSIngo Weinhold size_t bytes = msgVecs[i].iov_len; 1328224aee3fSIngo Weinhold if (bytes > bufferSize) 1329224aee3fSIngo Weinhold bytes = bufferSize; 1330224aee3fSIngo Weinhold 1331e8885f20SAxel Dörfler status_t status = user_memcpy(message->buffer, 1332e8885f20SAxel Dörfler msgVecs[i].iov_base, bytes); 1333e8885f20SAxel Dörfler if (status != B_OK) { 1334e8885f20SAxel Dörfler put_port_message(message); 1335f28dd36bSAxel Dörfler goto error; 133661de73e2SIngo Weinhold } 1337224aee3fSIngo Weinhold 1338224aee3fSIngo Weinhold bufferSize -= bytes; 1339224aee3fSIngo Weinhold if (bufferSize == 0) 1340224aee3fSIngo Weinhold break; 1341224aee3fSIngo Weinhold } 1342224aee3fSIngo Weinhold } else { 1343224aee3fSIngo Weinhold // copy from kernel memory 1344224aee3fSIngo Weinhold for (i = 0; i < vecCount; i++) { 1345224aee3fSIngo Weinhold size_t bytes = msgVecs[i].iov_len; 1346224aee3fSIngo Weinhold if (bytes > bufferSize) 1347224aee3fSIngo Weinhold bytes = bufferSize; 1348224aee3fSIngo Weinhold 1349e8885f20SAxel Dörfler memcpy(message->buffer, msgVecs[i].iov_base, bytes); 1350224aee3fSIngo Weinhold 1351224aee3fSIngo Weinhold bufferSize -= bytes; 1352224aee3fSIngo Weinhold if (bufferSize == 0) 1353224aee3fSIngo Weinhold break; 1354224aee3fSIngo Weinhold } 1355224aee3fSIngo Weinhold } 1356224aee3fSIngo Weinhold } 1357224aee3fSIngo Weinhold 1358e8885f20SAxel Dörfler sPorts[slot].messages.Add(message); 1359e8885f20SAxel Dörfler sPorts[slot].read_count++; 1360224aee3fSIngo Weinhold 1361f28dd36bSAxel Dörfler T(Write(sPorts[slot], message->code, message->size, B_OK)); 1362f28dd36bSAxel Dörfler 1363224aee3fSIngo Weinhold notify_port_select_events(slot, B_EVENT_READ); 1364e8885f20SAxel Dörfler sPorts[slot].read_condition.NotifyOne(); 1365e8885f20SAxel Dörfler return B_OK; 1366f28dd36bSAxel Dörfler 1367f28dd36bSAxel Dörfler error: 1368f28dd36bSAxel Dörfler // Give up our slot in the queue again, and let someone else 1369f28dd36bSAxel Dörfler // try and fail 1370f28dd36bSAxel Dörfler T(Write(sPorts[slot], 0, 0, status)); 1371f28dd36bSAxel Dörfler sPorts[slot].write_count++; 1372f28dd36bSAxel Dörfler notify_port_select_events(slot, B_EVENT_WRITE); 1373f28dd36bSAxel Dörfler sPorts[slot].write_condition.NotifyOne(); 1374f28dd36bSAxel Dörfler 1375f28dd36bSAxel Dörfler return status; 1376224aee3fSIngo Weinhold } 1377224aee3fSIngo Weinhold 1378224aee3fSIngo Weinhold 1379224aee3fSIngo Weinhold status_t 138025028839SAxel Dörfler set_port_owner(port_id id, team_id newTeamID) 1381224aee3fSIngo Weinhold { 138225028839SAxel Dörfler TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, newTeamID)); 1383224aee3fSIngo Weinhold 1384e8885f20SAxel Dörfler if (id < 0) 1385224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1386224aee3fSIngo Weinhold 1387e8885f20SAxel Dörfler int32 slot = id % sMaxPorts; 1388224aee3fSIngo Weinhold 1389e8885f20SAxel Dörfler MutexLocker locker(sPorts[slot].lock); 1390224aee3fSIngo Weinhold 1391224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 1392224aee3fSIngo Weinhold TRACE(("set_port_owner: invalid port_id %ld\n", id)); 1393224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1394224aee3fSIngo Weinhold } 139525028839SAxel Dörfler 139625028839SAxel Dörfler InterruptsSpinLocker teamLocker(gTeamSpinlock); 139725028839SAxel Dörfler 139825028839SAxel Dörfler struct team* team = team_get_team_struct_locked(newTeamID); 139925028839SAxel Dörfler if (team == NULL) { 140025028839SAxel Dörfler T(OwnerChange(sPorts[slot], newTeamID, B_BAD_TEAM_ID)); 1401e8885f20SAxel Dörfler return B_BAD_TEAM_ID; 1402f28dd36bSAxel Dörfler } 1403f28dd36bSAxel Dörfler 1404224aee3fSIngo Weinhold // transfer ownership to other team 140525028839SAxel Dörfler list_remove_link(&sPorts[slot].team_link); 140625028839SAxel Dörfler list_add_item(&team->port_list, &sPorts[slot].team_link); 140725028839SAxel Dörfler sPorts[slot].owner = newTeamID; 1408224aee3fSIngo Weinhold 140925028839SAxel Dörfler T(OwnerChange(sPorts[slot], newTeamID, B_OK)); 1410e8885f20SAxel Dörfler return B_OK; 1411224aee3fSIngo Weinhold } 1412224aee3fSIngo Weinhold 1413224aee3fSIngo Weinhold 1414224aee3fSIngo Weinhold // #pragma mark - syscalls 1415224aee3fSIngo Weinhold 1416224aee3fSIngo Weinhold 1417224aee3fSIngo Weinhold port_id 1418224aee3fSIngo Weinhold _user_create_port(int32 queueLength, const char *userName) 1419224aee3fSIngo Weinhold { 1420224aee3fSIngo Weinhold char name[B_OS_NAME_LENGTH]; 1421224aee3fSIngo Weinhold 1422224aee3fSIngo Weinhold if (userName == NULL) 1423224aee3fSIngo Weinhold return create_port(queueLength, NULL); 1424224aee3fSIngo Weinhold 1425224aee3fSIngo Weinhold if (!IS_USER_ADDRESS(userName) 1426224aee3fSIngo Weinhold || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) 1427224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1428224aee3fSIngo Weinhold 1429224aee3fSIngo Weinhold return create_port(queueLength, name); 1430224aee3fSIngo Weinhold } 1431224aee3fSIngo Weinhold 1432224aee3fSIngo Weinhold 1433224aee3fSIngo Weinhold status_t 1434224aee3fSIngo Weinhold _user_close_port(port_id id) 1435224aee3fSIngo Weinhold { 1436224aee3fSIngo Weinhold return close_port(id); 1437224aee3fSIngo Weinhold } 1438224aee3fSIngo Weinhold 1439224aee3fSIngo Weinhold 1440224aee3fSIngo Weinhold status_t 1441224aee3fSIngo Weinhold _user_delete_port(port_id id) 1442224aee3fSIngo Weinhold { 1443224aee3fSIngo Weinhold return delete_port(id); 1444224aee3fSIngo Weinhold } 1445224aee3fSIngo Weinhold 1446224aee3fSIngo Weinhold 1447224aee3fSIngo Weinhold port_id 1448224aee3fSIngo Weinhold _user_find_port(const char *userName) 1449224aee3fSIngo Weinhold { 1450224aee3fSIngo Weinhold char name[B_OS_NAME_LENGTH]; 1451224aee3fSIngo Weinhold 1452224aee3fSIngo Weinhold if (userName == NULL) 1453224aee3fSIngo Weinhold return B_BAD_VALUE; 1454224aee3fSIngo Weinhold if (!IS_USER_ADDRESS(userName) 1455224aee3fSIngo Weinhold || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) 1456224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1457224aee3fSIngo Weinhold 1458224aee3fSIngo Weinhold return find_port(name); 1459224aee3fSIngo Weinhold } 1460224aee3fSIngo Weinhold 1461224aee3fSIngo Weinhold 1462224aee3fSIngo Weinhold status_t 1463224aee3fSIngo Weinhold _user_get_port_info(port_id id, struct port_info *userInfo) 1464224aee3fSIngo Weinhold { 1465224aee3fSIngo Weinhold struct port_info info; 1466224aee3fSIngo Weinhold status_t status; 1467224aee3fSIngo Weinhold 1468224aee3fSIngo Weinhold if (userInfo == NULL) 1469224aee3fSIngo Weinhold return B_BAD_VALUE; 1470224aee3fSIngo Weinhold if (!IS_USER_ADDRESS(userInfo)) 1471224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1472224aee3fSIngo Weinhold 1473224aee3fSIngo Weinhold status = get_port_info(id, &info); 1474224aee3fSIngo Weinhold 1475224aee3fSIngo Weinhold // copy back to user space 14764048494cSIngo Weinhold if (status == B_OK 14774048494cSIngo Weinhold && user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK) 1478224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1479224aee3fSIngo Weinhold 1480224aee3fSIngo Weinhold return status; 1481224aee3fSIngo Weinhold } 1482224aee3fSIngo Weinhold 1483224aee3fSIngo Weinhold 1484224aee3fSIngo Weinhold status_t 14854048494cSIngo Weinhold _user_get_next_port_info(team_id team, int32 *userCookie, 14864048494cSIngo Weinhold struct port_info *userInfo) 1487224aee3fSIngo Weinhold { 1488224aee3fSIngo Weinhold struct port_info info; 1489224aee3fSIngo Weinhold status_t status; 1490224aee3fSIngo Weinhold int32 cookie; 1491224aee3fSIngo Weinhold 1492224aee3fSIngo Weinhold if (userCookie == NULL || userInfo == NULL) 1493224aee3fSIngo Weinhold return B_BAD_VALUE; 1494224aee3fSIngo Weinhold if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo) 1495224aee3fSIngo Weinhold || user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK) 1496224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1497224aee3fSIngo Weinhold 1498224aee3fSIngo Weinhold status = get_next_port_info(team, &cookie, &info); 1499224aee3fSIngo Weinhold 1500224aee3fSIngo Weinhold // copy back to user space 1501224aee3fSIngo Weinhold if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK 15024048494cSIngo Weinhold || (status == B_OK && user_memcpy(userInfo, &info, 15034048494cSIngo Weinhold sizeof(struct port_info)) < B_OK)) 1504224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1505224aee3fSIngo Weinhold 1506224aee3fSIngo Weinhold return status; 1507224aee3fSIngo Weinhold } 1508224aee3fSIngo Weinhold 1509224aee3fSIngo Weinhold 1510224aee3fSIngo Weinhold ssize_t 1511224aee3fSIngo Weinhold _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout) 1512224aee3fSIngo Weinhold { 15134048494cSIngo Weinhold syscall_restart_handle_timeout_pre(flags, timeout); 15144048494cSIngo Weinhold 15154048494cSIngo Weinhold status_t status = port_buffer_size_etc(port, flags | B_CAN_INTERRUPT, 15164048494cSIngo Weinhold timeout); 15174048494cSIngo Weinhold 15184048494cSIngo Weinhold return syscall_restart_handle_timeout_post(status, timeout); 1519224aee3fSIngo Weinhold } 1520224aee3fSIngo Weinhold 1521224aee3fSIngo Weinhold 1522224aee3fSIngo Weinhold ssize_t 1523224aee3fSIngo Weinhold _user_port_count(port_id port) 1524224aee3fSIngo Weinhold { 1525224aee3fSIngo Weinhold return port_count(port); 1526224aee3fSIngo Weinhold } 1527224aee3fSIngo Weinhold 1528224aee3fSIngo Weinhold 1529224aee3fSIngo Weinhold status_t 1530224aee3fSIngo Weinhold _user_set_port_owner(port_id port, team_id team) 1531224aee3fSIngo Weinhold { 1532224aee3fSIngo Weinhold return set_port_owner(port, team); 1533224aee3fSIngo Weinhold } 1534224aee3fSIngo Weinhold 1535224aee3fSIngo Weinhold 1536224aee3fSIngo Weinhold ssize_t 1537224aee3fSIngo Weinhold _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer, 1538224aee3fSIngo Weinhold size_t bufferSize, uint32 flags, bigtime_t timeout) 1539224aee3fSIngo Weinhold { 1540224aee3fSIngo Weinhold int32 messageCode; 1541224aee3fSIngo Weinhold ssize_t bytesRead; 1542224aee3fSIngo Weinhold 15434048494cSIngo Weinhold syscall_restart_handle_timeout_pre(flags, timeout); 15444048494cSIngo Weinhold 1545224aee3fSIngo Weinhold if (userBuffer == NULL && bufferSize != 0) 1546224aee3fSIngo Weinhold return B_BAD_VALUE; 1547224aee3fSIngo Weinhold if ((userCode != NULL && !IS_USER_ADDRESS(userCode)) 1548224aee3fSIngo Weinhold || (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))) 1549224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1550224aee3fSIngo Weinhold 1551224aee3fSIngo Weinhold bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize, 1552224aee3fSIngo Weinhold flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout); 1553224aee3fSIngo Weinhold 1554224aee3fSIngo Weinhold if (bytesRead >= 0 && userCode != NULL 1555224aee3fSIngo Weinhold && user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK) 1556224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1557224aee3fSIngo Weinhold 15584048494cSIngo Weinhold return syscall_restart_handle_timeout_post(bytesRead, timeout); 1559224aee3fSIngo Weinhold } 1560224aee3fSIngo Weinhold 1561224aee3fSIngo Weinhold 1562224aee3fSIngo Weinhold status_t 1563224aee3fSIngo Weinhold _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer, 1564224aee3fSIngo Weinhold size_t bufferSize, uint32 flags, bigtime_t timeout) 1565224aee3fSIngo Weinhold { 1566224aee3fSIngo Weinhold iovec vec = { (void *)userBuffer, bufferSize }; 1567224aee3fSIngo Weinhold 15684048494cSIngo Weinhold syscall_restart_handle_timeout_pre(flags, timeout); 15694048494cSIngo Weinhold 1570224aee3fSIngo Weinhold if (userBuffer == NULL && bufferSize != 0) 1571224aee3fSIngo Weinhold return B_BAD_VALUE; 1572224aee3fSIngo Weinhold if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)) 1573224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1574224aee3fSIngo Weinhold 15754048494cSIngo Weinhold status_t status = writev_port_etc(port, messageCode, &vec, 1, bufferSize, 1576224aee3fSIngo Weinhold flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout); 15774048494cSIngo Weinhold 15784048494cSIngo Weinhold return syscall_restart_handle_timeout_post(status, timeout); 1579224aee3fSIngo Weinhold } 1580224aee3fSIngo Weinhold 1581224aee3fSIngo Weinhold 1582224aee3fSIngo Weinhold status_t 1583224aee3fSIngo Weinhold _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs, 1584224aee3fSIngo Weinhold size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout) 1585224aee3fSIngo Weinhold { 15864048494cSIngo Weinhold syscall_restart_handle_timeout_pre(flags, timeout); 1587224aee3fSIngo Weinhold 1588224aee3fSIngo Weinhold if (userVecs == NULL && bufferSize != 0) 1589224aee3fSIngo Weinhold return B_BAD_VALUE; 1590224aee3fSIngo Weinhold if (userVecs != NULL && !IS_USER_ADDRESS(userVecs)) 1591224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1592224aee3fSIngo Weinhold 15934048494cSIngo Weinhold iovec *vecs = NULL; 1594224aee3fSIngo Weinhold if (userVecs && vecCount != 0) { 1595224aee3fSIngo Weinhold vecs = (iovec*)malloc(sizeof(iovec) * vecCount); 1596224aee3fSIngo Weinhold if (vecs == NULL) 1597224aee3fSIngo Weinhold return B_NO_MEMORY; 1598224aee3fSIngo Weinhold 1599224aee3fSIngo Weinhold if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) { 1600224aee3fSIngo Weinhold free(vecs); 1601224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1602224aee3fSIngo Weinhold } 1603224aee3fSIngo Weinhold } 16044048494cSIngo Weinhold 16054048494cSIngo Weinhold status_t status = writev_port_etc(port, messageCode, vecs, vecCount, 16064048494cSIngo Weinhold bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, 16074048494cSIngo Weinhold timeout); 1608224aee3fSIngo Weinhold 1609224aee3fSIngo Weinhold free(vecs); 16104048494cSIngo Weinhold return syscall_restart_handle_timeout_post(status, timeout); 1611224aee3fSIngo Weinhold } 16127727e08eSIngo Weinhold 16137727e08eSIngo Weinhold 16147727e08eSIngo Weinhold status_t 16157727e08eSIngo Weinhold _user_get_port_message_info_etc(port_id port, port_message_info *userInfo, 16167727e08eSIngo Weinhold size_t infoSize, uint32 flags, bigtime_t timeout) 16177727e08eSIngo Weinhold { 16187727e08eSIngo Weinhold if (userInfo == NULL || infoSize != sizeof(port_message_info)) 16197727e08eSIngo Weinhold return B_BAD_VALUE; 16207727e08eSIngo Weinhold 16217727e08eSIngo Weinhold syscall_restart_handle_timeout_pre(flags, timeout); 16227727e08eSIngo Weinhold 16237727e08eSIngo Weinhold port_message_info info; 16247727e08eSIngo Weinhold status_t error = _get_port_message_info_etc(port, &info, sizeof(info), 16257727e08eSIngo Weinhold flags | B_CAN_INTERRUPT, timeout); 16267727e08eSIngo Weinhold 16277727e08eSIngo Weinhold // copy info to userland 16287727e08eSIngo Weinhold if (error == B_OK && (!IS_USER_ADDRESS(userInfo) 16297727e08eSIngo Weinhold || user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) { 16307727e08eSIngo Weinhold error = B_BAD_ADDRESS; 16317727e08eSIngo Weinhold } 16327727e08eSIngo Weinhold 16337727e08eSIngo Weinhold return syscall_restart_handle_timeout_post(error, timeout); 16347727e08eSIngo Weinhold } 1635