1224aee3fSIngo Weinhold /* 2224aee3fSIngo Weinhold * Copyright 2002-2007, 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 9224aee3fSIngo Weinhold /*! Ports for IPC */ 10224aee3fSIngo Weinhold 11224aee3fSIngo Weinhold 12224aee3fSIngo Weinhold #include <OS.h> 13224aee3fSIngo Weinhold 14224aee3fSIngo Weinhold #include <port.h> 15224aee3fSIngo Weinhold #include <kernel.h> 16224aee3fSIngo Weinhold #include <sem.h> 17224aee3fSIngo Weinhold #include <team.h> 18224aee3fSIngo Weinhold #include <util/list.h> 19224aee3fSIngo Weinhold #include <arch/int.h> 20224aee3fSIngo Weinhold #include <cbuf.h> 21224aee3fSIngo Weinhold #include <wait_for_objects.h> 22224aee3fSIngo Weinhold 23224aee3fSIngo Weinhold #include <iovec.h> 24224aee3fSIngo Weinhold #include <string.h> 25224aee3fSIngo Weinhold #include <stdlib.h> 26224aee3fSIngo Weinhold #include <ctype.h> 27224aee3fSIngo Weinhold 28224aee3fSIngo Weinhold 29224aee3fSIngo Weinhold //#define TRACE_PORTS 30224aee3fSIngo Weinhold #ifdef TRACE_PORTS 31224aee3fSIngo Weinhold # define TRACE(x) dprintf x 32224aee3fSIngo Weinhold #else 33224aee3fSIngo Weinhold # define TRACE(x) 34224aee3fSIngo Weinhold #endif 35224aee3fSIngo Weinhold 36224aee3fSIngo Weinhold 37224aee3fSIngo Weinhold typedef struct port_msg { 38224aee3fSIngo Weinhold list_link link; 39224aee3fSIngo Weinhold int32 code; 40224aee3fSIngo Weinhold cbuf *buffer_chain; 41224aee3fSIngo Weinhold size_t size; 42224aee3fSIngo Weinhold } port_msg; 43224aee3fSIngo Weinhold 44224aee3fSIngo Weinhold struct port_entry { 45224aee3fSIngo Weinhold port_id id; 46224aee3fSIngo Weinhold team_id owner; 47224aee3fSIngo Weinhold int32 capacity; 48224aee3fSIngo Weinhold spinlock lock; 49224aee3fSIngo Weinhold const char *name; 50224aee3fSIngo Weinhold sem_id read_sem; 51224aee3fSIngo Weinhold sem_id write_sem; 52224aee3fSIngo Weinhold int32 total_count; // messages read from port since creation 53224aee3fSIngo Weinhold select_info *select_infos; 54224aee3fSIngo Weinhold struct list msg_queue; 55224aee3fSIngo Weinhold }; 56224aee3fSIngo Weinhold 57224aee3fSIngo Weinhold 58224aee3fSIngo Weinhold #define MAX_QUEUE_LENGTH 4096 59224aee3fSIngo Weinhold #define PORT_MAX_MESSAGE_SIZE 65536 60224aee3fSIngo Weinhold 61224aee3fSIngo Weinhold // sMaxPorts must be power of 2 62224aee3fSIngo Weinhold static int32 sMaxPorts = 4096; 63224aee3fSIngo Weinhold static int32 sUsedPorts = 0; 64224aee3fSIngo Weinhold 65224aee3fSIngo Weinhold static struct port_entry *sPorts = NULL; 66224aee3fSIngo Weinhold static area_id sPortArea = 0; 67224aee3fSIngo Weinhold static bool sPortsActive = false; 68224aee3fSIngo Weinhold static port_id sNextPort = 1; 69224aee3fSIngo Weinhold static int32 sFirstFreeSlot = 1; 70224aee3fSIngo Weinhold 71224aee3fSIngo Weinhold static spinlock sPortSpinlock = 0; 72224aee3fSIngo Weinhold 73224aee3fSIngo Weinhold #define GRAB_PORT_LIST_LOCK() acquire_spinlock(&sPortSpinlock) 74224aee3fSIngo Weinhold #define RELEASE_PORT_LIST_LOCK() release_spinlock(&sPortSpinlock) 75224aee3fSIngo Weinhold #define GRAB_PORT_LOCK(s) acquire_spinlock(&(s).lock) 76224aee3fSIngo Weinhold #define RELEASE_PORT_LOCK(s) release_spinlock(&(s).lock) 77224aee3fSIngo Weinhold 78224aee3fSIngo Weinhold 79224aee3fSIngo Weinhold static int 80224aee3fSIngo Weinhold dump_port_list(int argc, char **argv) 81224aee3fSIngo Weinhold { 82224aee3fSIngo Weinhold const char *name = NULL; 83224aee3fSIngo Weinhold team_id owner = -1; 84224aee3fSIngo Weinhold int32 i; 85224aee3fSIngo Weinhold 86224aee3fSIngo Weinhold if (argc > 2) { 87224aee3fSIngo Weinhold if (!strcmp(argv[1], "team") || !strcmp(argv[1], "owner")) 88224aee3fSIngo Weinhold owner = strtoul(argv[2], NULL, 0); 89224aee3fSIngo Weinhold else if (!strcmp(argv[1], "name")) 90224aee3fSIngo Weinhold name = argv[2]; 91224aee3fSIngo Weinhold } else if (argc > 1) 92224aee3fSIngo Weinhold owner = strtoul(argv[1], NULL, 0); 93224aee3fSIngo Weinhold 94224aee3fSIngo Weinhold kprintf("port id cap r-sem w-sem team name\n"); 95224aee3fSIngo Weinhold 96224aee3fSIngo Weinhold for (i = 0; i < sMaxPorts; i++) { 97224aee3fSIngo Weinhold struct port_entry *port = &sPorts[i]; 98224aee3fSIngo Weinhold if (port->id < 0 99224aee3fSIngo Weinhold || (owner != -1 && port->owner != owner) 100224aee3fSIngo Weinhold || (name != NULL && strstr(port->name, name) == NULL)) 101224aee3fSIngo Weinhold continue; 102224aee3fSIngo Weinhold 103224aee3fSIngo Weinhold kprintf("%p %6ld %4ld %6ld %6ld %6ld %s\n", port, port->id, 104224aee3fSIngo Weinhold port->capacity, port->read_sem, port->write_sem, port->owner, 105224aee3fSIngo Weinhold port->name); 106224aee3fSIngo Weinhold } 107224aee3fSIngo Weinhold return 0; 108224aee3fSIngo Weinhold } 109224aee3fSIngo Weinhold 110224aee3fSIngo Weinhold 111224aee3fSIngo Weinhold static void 112224aee3fSIngo Weinhold _dump_port_info(struct port_entry *port) 113224aee3fSIngo Weinhold { 114224aee3fSIngo Weinhold int32 count; 115224aee3fSIngo Weinhold 116224aee3fSIngo Weinhold kprintf("PORT: %p\n", port); 117224aee3fSIngo Weinhold kprintf(" id: %#lx\n", port->id); 118224aee3fSIngo Weinhold kprintf(" name: \"%s\"\n", port->name); 119224aee3fSIngo Weinhold kprintf(" owner: %#lx\n", port->owner); 120224aee3fSIngo Weinhold kprintf(" capacity: %ld\n", port->capacity); 121224aee3fSIngo Weinhold kprintf(" read_sem: %#lx\n", port->read_sem); 122224aee3fSIngo Weinhold kprintf(" write_sem: %#lx\n", port->write_sem); 123224aee3fSIngo Weinhold get_sem_count(port->read_sem, &count); 124224aee3fSIngo Weinhold kprintf(" read_sem count: %ld\n", count); 125224aee3fSIngo Weinhold get_sem_count(port->write_sem, &count); 126224aee3fSIngo Weinhold kprintf(" write_sem count: %ld\n", count); 127224aee3fSIngo Weinhold kprintf(" total count: %ld\n", port->total_count); 128*5aee691eSIngo Weinhold 129*5aee691eSIngo Weinhold set_debug_variable("_port", (addr_t)port); 130*5aee691eSIngo Weinhold set_debug_variable("_portID", port->id); 131*5aee691eSIngo Weinhold set_debug_variable("_owner", port->owner); 132*5aee691eSIngo Weinhold set_debug_variable("_readSem", port->read_sem); 133*5aee691eSIngo Weinhold set_debug_variable("_writeSem", port->write_sem); 134224aee3fSIngo Weinhold } 135224aee3fSIngo Weinhold 136224aee3fSIngo Weinhold 137224aee3fSIngo Weinhold static int 138224aee3fSIngo Weinhold dump_port_info(int argc, char **argv) 139224aee3fSIngo Weinhold { 140224aee3fSIngo Weinhold const char *name = NULL; 141224aee3fSIngo Weinhold sem_id sem = -1; 142224aee3fSIngo Weinhold int i; 143224aee3fSIngo Weinhold 144224aee3fSIngo Weinhold if (argc < 2) { 145ce637fdaSIngo Weinhold print_debugger_command_usage(argv[0]); 146224aee3fSIngo Weinhold return 0; 147224aee3fSIngo Weinhold } 148224aee3fSIngo Weinhold 149224aee3fSIngo Weinhold if (argc > 2) { 150224aee3fSIngo Weinhold if (!strcmp(argv[1], "address")) { 151224aee3fSIngo Weinhold _dump_port_info((struct port_entry *)strtoul(argv[2], NULL, 0)); 152224aee3fSIngo Weinhold return 0; 153224aee3fSIngo Weinhold } else if (!strcmp(argv[1], "sem")) 154224aee3fSIngo Weinhold sem = strtoul(argv[2], NULL, 0); 155224aee3fSIngo Weinhold else if (!strcmp(argv[1], "name")) 156224aee3fSIngo Weinhold name = argv[2]; 157224aee3fSIngo Weinhold } else if (isdigit(argv[1][0])) { 158224aee3fSIngo Weinhold // if the argument looks like a number, treat it as such 159224aee3fSIngo Weinhold uint32 num = strtoul(argv[1], NULL, 0); 160224aee3fSIngo Weinhold uint32 slot = num % sMaxPorts; 161224aee3fSIngo Weinhold if (sPorts[slot].id != (int)num) { 162224aee3fSIngo Weinhold kprintf("port %ld (%#lx) doesn't exist!\n", num, num); 163224aee3fSIngo Weinhold return 0; 164224aee3fSIngo Weinhold } 165224aee3fSIngo Weinhold _dump_port_info(&sPorts[slot]); 166224aee3fSIngo Weinhold return 0; 167224aee3fSIngo Weinhold } else 168224aee3fSIngo Weinhold name = argv[1]; 169224aee3fSIngo Weinhold 170224aee3fSIngo Weinhold // walk through the ports list, trying to match name 171224aee3fSIngo Weinhold for (i = 0; i < sMaxPorts; i++) { 172224aee3fSIngo Weinhold if ((name != NULL && sPorts[i].name != NULL 173224aee3fSIngo Weinhold && !strcmp(name, sPorts[i].name)) 174224aee3fSIngo Weinhold || (sem != -1 && (sPorts[i].read_sem == sem 175224aee3fSIngo Weinhold || sPorts[i].write_sem == sem))) { 176224aee3fSIngo Weinhold _dump_port_info(&sPorts[i]); 177224aee3fSIngo Weinhold return 0; 178224aee3fSIngo Weinhold } 179224aee3fSIngo Weinhold } 180224aee3fSIngo Weinhold 181224aee3fSIngo Weinhold return 0; 182224aee3fSIngo Weinhold } 183224aee3fSIngo Weinhold 184224aee3fSIngo Weinhold 185224aee3fSIngo Weinhold static void 186224aee3fSIngo Weinhold notify_port_select_events(int slot, uint16 events) 187224aee3fSIngo Weinhold { 188224aee3fSIngo Weinhold if (sPorts[slot].select_infos) 189224aee3fSIngo Weinhold notify_select_events_list(sPorts[slot].select_infos, events); 190224aee3fSIngo Weinhold } 191224aee3fSIngo Weinhold 192224aee3fSIngo Weinhold 193224aee3fSIngo Weinhold static void 194224aee3fSIngo Weinhold put_port_msg(port_msg *msg) 195224aee3fSIngo Weinhold { 196224aee3fSIngo Weinhold cbuf_free_chain(msg->buffer_chain); 197224aee3fSIngo Weinhold free(msg); 198224aee3fSIngo Weinhold } 199224aee3fSIngo Weinhold 200224aee3fSIngo Weinhold 201224aee3fSIngo Weinhold static port_msg * 202224aee3fSIngo Weinhold get_port_msg(int32 code, size_t bufferSize) 203224aee3fSIngo Weinhold { 204224aee3fSIngo Weinhold // ToDo: investigate preallocation of port_msgs (or use a slab allocator) 205224aee3fSIngo Weinhold cbuf *bufferChain = NULL; 206224aee3fSIngo Weinhold 207224aee3fSIngo Weinhold port_msg *msg = (port_msg *)malloc(sizeof(port_msg)); 208224aee3fSIngo Weinhold if (msg == NULL) 209224aee3fSIngo Weinhold return NULL; 210224aee3fSIngo Weinhold 211224aee3fSIngo Weinhold if (bufferSize > 0) { 212224aee3fSIngo Weinhold bufferChain = cbuf_get_chain(bufferSize); 213224aee3fSIngo Weinhold if (bufferChain == NULL) { 214224aee3fSIngo Weinhold free(msg); 215224aee3fSIngo Weinhold return NULL; 216224aee3fSIngo Weinhold } 217224aee3fSIngo Weinhold } 218224aee3fSIngo Weinhold 219224aee3fSIngo Weinhold msg->code = code; 220224aee3fSIngo Weinhold msg->buffer_chain = bufferChain; 221224aee3fSIngo Weinhold msg->size = bufferSize; 222224aee3fSIngo Weinhold return msg; 223224aee3fSIngo Weinhold } 224224aee3fSIngo Weinhold 225224aee3fSIngo Weinhold 226224aee3fSIngo Weinhold /*! You need to own the port's lock when calling this function */ 227224aee3fSIngo Weinhold static bool 228224aee3fSIngo Weinhold is_port_closed(int32 slot) 229224aee3fSIngo Weinhold { 230224aee3fSIngo Weinhold return sPorts[slot].capacity == 0; 231224aee3fSIngo Weinhold } 232224aee3fSIngo Weinhold 233224aee3fSIngo Weinhold 234224aee3fSIngo Weinhold /*! Fills the port_info structure with information from the specified 235224aee3fSIngo Weinhold port. 236224aee3fSIngo Weinhold The port lock must be held when called. 237224aee3fSIngo Weinhold */ 238224aee3fSIngo Weinhold static void 239224aee3fSIngo Weinhold fill_port_info(struct port_entry *port, port_info *info, size_t size) 240224aee3fSIngo Weinhold { 241224aee3fSIngo Weinhold int32 count; 242224aee3fSIngo Weinhold 243224aee3fSIngo Weinhold info->port = port->id; 244224aee3fSIngo Weinhold info->team = port->owner; 245224aee3fSIngo Weinhold info->capacity = port->capacity; 246224aee3fSIngo Weinhold 247224aee3fSIngo Weinhold get_sem_count(port->read_sem, &count); 248224aee3fSIngo Weinhold if (count < 0) 249224aee3fSIngo Weinhold count = 0; 250224aee3fSIngo Weinhold 251224aee3fSIngo Weinhold info->queue_count = count; 252224aee3fSIngo Weinhold info->total_count = port->total_count; 253224aee3fSIngo Weinhold 254224aee3fSIngo Weinhold strlcpy(info->name, port->name, B_OS_NAME_LENGTH); 255224aee3fSIngo Weinhold } 256224aee3fSIngo Weinhold 257224aee3fSIngo Weinhold 258224aee3fSIngo Weinhold // #pragma mark - private kernel API 259224aee3fSIngo Weinhold 260224aee3fSIngo Weinhold 261224aee3fSIngo Weinhold /*! This function cycles through the ports table, deleting all 262224aee3fSIngo Weinhold the ports that are owned by the passed team_id 263224aee3fSIngo Weinhold */ 264224aee3fSIngo Weinhold int 265224aee3fSIngo Weinhold delete_owned_ports(team_id owner) 266224aee3fSIngo Weinhold { 267224aee3fSIngo Weinhold // ToDo: investigate maintaining a list of ports in the team 268224aee3fSIngo Weinhold // to make this simpler and more efficient. 269224aee3fSIngo Weinhold cpu_status state; 270224aee3fSIngo Weinhold int i; 271224aee3fSIngo Weinhold int count = 0; 272224aee3fSIngo Weinhold 273224aee3fSIngo Weinhold TRACE(("delete_owned_ports(owner = %ld)\n", owner)); 274224aee3fSIngo Weinhold 275224aee3fSIngo Weinhold if (!sPortsActive) 276224aee3fSIngo Weinhold return B_BAD_PORT_ID; 277224aee3fSIngo Weinhold 278224aee3fSIngo Weinhold state = disable_interrupts(); 279224aee3fSIngo Weinhold GRAB_PORT_LIST_LOCK(); 280224aee3fSIngo Weinhold 281224aee3fSIngo Weinhold for (i = 0; i < sMaxPorts; i++) { 282224aee3fSIngo Weinhold if (sPorts[i].id != -1 && sPorts[i].owner == owner) { 283224aee3fSIngo Weinhold port_id id = sPorts[i].id; 284224aee3fSIngo Weinhold 285224aee3fSIngo Weinhold RELEASE_PORT_LIST_LOCK(); 286224aee3fSIngo Weinhold restore_interrupts(state); 287224aee3fSIngo Weinhold 288224aee3fSIngo Weinhold delete_port(id); 289224aee3fSIngo Weinhold count++; 290224aee3fSIngo Weinhold 291224aee3fSIngo Weinhold state = disable_interrupts(); 292224aee3fSIngo Weinhold GRAB_PORT_LIST_LOCK(); 293224aee3fSIngo Weinhold } 294224aee3fSIngo Weinhold } 295224aee3fSIngo Weinhold 296224aee3fSIngo Weinhold RELEASE_PORT_LIST_LOCK(); 297224aee3fSIngo Weinhold restore_interrupts(state); 298224aee3fSIngo Weinhold 299224aee3fSIngo Weinhold return count; 300224aee3fSIngo Weinhold } 301224aee3fSIngo Weinhold 302224aee3fSIngo Weinhold 303224aee3fSIngo Weinhold int32 304224aee3fSIngo Weinhold port_max_ports(void) 305224aee3fSIngo Weinhold { 306224aee3fSIngo Weinhold return sMaxPorts; 307224aee3fSIngo Weinhold } 308224aee3fSIngo Weinhold 309224aee3fSIngo Weinhold 310224aee3fSIngo Weinhold int32 311224aee3fSIngo Weinhold port_used_ports(void) 312224aee3fSIngo Weinhold { 313224aee3fSIngo Weinhold return sUsedPorts; 314224aee3fSIngo Weinhold } 315224aee3fSIngo Weinhold 316224aee3fSIngo Weinhold 317224aee3fSIngo Weinhold status_t 318224aee3fSIngo Weinhold port_init(kernel_args *args) 319224aee3fSIngo Weinhold { 320224aee3fSIngo Weinhold size_t size = sizeof(struct port_entry) * sMaxPorts; 321224aee3fSIngo Weinhold int32 i; 322224aee3fSIngo Weinhold 323224aee3fSIngo Weinhold // create and initialize ports table 324224aee3fSIngo Weinhold sPortArea = create_area("port_table", (void **)&sPorts, B_ANY_KERNEL_ADDRESS, 325224aee3fSIngo Weinhold size, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 326224aee3fSIngo Weinhold if (sPortArea < 0) { 327224aee3fSIngo Weinhold panic("unable to allocate kernel port table!\n"); 328224aee3fSIngo Weinhold return sPortArea; 329224aee3fSIngo Weinhold } 330224aee3fSIngo Weinhold 331224aee3fSIngo Weinhold // ToDo: investigate preallocating a list of port_msgs to 332224aee3fSIngo Weinhold // speed up actual message sending/receiving, a slab allocator 333224aee3fSIngo Weinhold // might do it as well, though :-) 334224aee3fSIngo Weinhold 335224aee3fSIngo Weinhold memset(sPorts, 0, size); 336224aee3fSIngo Weinhold for (i = 0; i < sMaxPorts; i++) 337224aee3fSIngo Weinhold sPorts[i].id = -1; 338224aee3fSIngo Weinhold 339224aee3fSIngo Weinhold // add debugger commands 340ce637fdaSIngo Weinhold add_debugger_command_etc("ports", &dump_port_list, 341ce637fdaSIngo Weinhold "Dump a list of all active ports (for team, with name, etc.)", 342ce637fdaSIngo Weinhold "[ ([ \"team\" | \"owner\" ] <team>) | (\"name\" <name>) ]\n" 343ce637fdaSIngo Weinhold "Prints a list of all active ports meeting the given\n" 344ce637fdaSIngo Weinhold "requirement. If no argument is given, all ports are listed.\n" 345ce637fdaSIngo Weinhold " <team> - The team owning the ports.\n" 346ce637fdaSIngo Weinhold " <name> - Part of the name of the ports.\n", 0); 347ce637fdaSIngo Weinhold add_debugger_command_etc("port", &dump_port_info, 348ce637fdaSIngo Weinhold "Dump info about a particular port", 349ce637fdaSIngo Weinhold "([ \"address\" ] <address>) | ([ \"name\" ] <name>) " 350ce637fdaSIngo Weinhold "| (\"sem\" <sem>)\n" 351ce637fdaSIngo Weinhold "Prints info about the specified port.\n" 352ce637fdaSIngo Weinhold " <address> - Pointer to the port structure.\n" 353ce637fdaSIngo Weinhold " <name> - Name of the port.\n" 354ce637fdaSIngo Weinhold " <sem> - ID of the port's read or write semaphore.\n", 0); 355224aee3fSIngo Weinhold 356224aee3fSIngo Weinhold sPortsActive = true; 357224aee3fSIngo Weinhold return B_OK; 358224aee3fSIngo Weinhold } 359224aee3fSIngo Weinhold 360224aee3fSIngo Weinhold 361224aee3fSIngo Weinhold // #pragma mark - public kernel API 362224aee3fSIngo Weinhold 363224aee3fSIngo Weinhold 364224aee3fSIngo Weinhold port_id 365224aee3fSIngo Weinhold create_port(int32 queueLength, const char *name) 366224aee3fSIngo Weinhold { 367224aee3fSIngo Weinhold cpu_status state; 368224aee3fSIngo Weinhold char nameBuffer[B_OS_NAME_LENGTH]; 369224aee3fSIngo Weinhold sem_id readSem, writeSem; 370224aee3fSIngo Weinhold status_t status; 371224aee3fSIngo Weinhold team_id owner; 372224aee3fSIngo Weinhold int32 slot; 373224aee3fSIngo Weinhold 374224aee3fSIngo Weinhold TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength, name)); 375224aee3fSIngo Weinhold 376224aee3fSIngo Weinhold if (!sPortsActive) 377224aee3fSIngo Weinhold return B_BAD_PORT_ID; 378224aee3fSIngo Weinhold 379224aee3fSIngo Weinhold // check queue length 380224aee3fSIngo Weinhold if (queueLength < 1 381224aee3fSIngo Weinhold || queueLength > MAX_QUEUE_LENGTH) 382224aee3fSIngo Weinhold return B_BAD_VALUE; 383224aee3fSIngo Weinhold 384224aee3fSIngo Weinhold // check early on if there are any free port slots to use 385224aee3fSIngo Weinhold if (atomic_add(&sUsedPorts, 1) >= sMaxPorts) { 386224aee3fSIngo Weinhold status = B_NO_MORE_PORTS; 387224aee3fSIngo Weinhold goto err1; 388224aee3fSIngo Weinhold } 389224aee3fSIngo Weinhold 390224aee3fSIngo Weinhold // check & dup name 391224aee3fSIngo Weinhold if (name == NULL) 392224aee3fSIngo Weinhold name = "unnamed port"; 393224aee3fSIngo Weinhold 394224aee3fSIngo Weinhold // ToDo: we could save the memory and use the semaphore name only instead 395224aee3fSIngo Weinhold strlcpy(nameBuffer, name, B_OS_NAME_LENGTH); 396224aee3fSIngo Weinhold name = strdup(nameBuffer); 397224aee3fSIngo Weinhold if (name == NULL) { 398224aee3fSIngo Weinhold status = B_NO_MEMORY; 399224aee3fSIngo Weinhold goto err1; 400224aee3fSIngo Weinhold } 401224aee3fSIngo Weinhold 402224aee3fSIngo Weinhold // create read sem with owner set to -1 403224aee3fSIngo Weinhold // ToDo: should be B_SYSTEM_TEAM 404224aee3fSIngo Weinhold readSem = create_sem_etc(0, name, -1); 405224aee3fSIngo Weinhold if (readSem < B_OK) { 406224aee3fSIngo Weinhold status = readSem; 407224aee3fSIngo Weinhold goto err2; 408224aee3fSIngo Weinhold } 409224aee3fSIngo Weinhold 410224aee3fSIngo Weinhold // create write sem 411224aee3fSIngo Weinhold writeSem = create_sem_etc(queueLength, name, -1); 412224aee3fSIngo Weinhold if (writeSem < B_OK) { 413224aee3fSIngo Weinhold status = writeSem; 414224aee3fSIngo Weinhold goto err3; 415224aee3fSIngo Weinhold } 416224aee3fSIngo Weinhold 417224aee3fSIngo Weinhold owner = team_get_current_team_id(); 418224aee3fSIngo Weinhold 419224aee3fSIngo Weinhold state = disable_interrupts(); 420224aee3fSIngo Weinhold GRAB_PORT_LIST_LOCK(); 421224aee3fSIngo Weinhold 422224aee3fSIngo Weinhold // find the first empty spot 423224aee3fSIngo Weinhold for (slot = 0; slot < sMaxPorts; slot++) { 424224aee3fSIngo Weinhold int32 i = (slot + sFirstFreeSlot) % sMaxPorts; 425224aee3fSIngo Weinhold 426224aee3fSIngo Weinhold if (sPorts[i].id == -1) { 427224aee3fSIngo Weinhold port_id id; 428224aee3fSIngo Weinhold 429224aee3fSIngo Weinhold // make the port_id be a multiple of the slot it's in 430224aee3fSIngo Weinhold if (i >= sNextPort % sMaxPorts) 431224aee3fSIngo Weinhold sNextPort += i - sNextPort % sMaxPorts; 432224aee3fSIngo Weinhold else 433224aee3fSIngo Weinhold sNextPort += sMaxPorts - (sNextPort % sMaxPorts - i); 434224aee3fSIngo Weinhold sFirstFreeSlot = slot + 1; 435224aee3fSIngo Weinhold 436224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[i]); 437224aee3fSIngo Weinhold sPorts[i].id = sNextPort++; 438224aee3fSIngo Weinhold RELEASE_PORT_LIST_LOCK(); 439224aee3fSIngo Weinhold 440224aee3fSIngo Weinhold sPorts[i].capacity = queueLength; 441224aee3fSIngo Weinhold sPorts[i].owner = owner; 442224aee3fSIngo Weinhold sPorts[i].name = name; 443224aee3fSIngo Weinhold 444224aee3fSIngo Weinhold sPorts[i].read_sem = readSem; 445224aee3fSIngo Weinhold sPorts[i].write_sem = writeSem; 446224aee3fSIngo Weinhold 447224aee3fSIngo Weinhold list_init(&sPorts[i].msg_queue); 448224aee3fSIngo Weinhold sPorts[i].total_count = 0; 449224aee3fSIngo Weinhold sPorts[i].select_infos = NULL; 450224aee3fSIngo Weinhold id = sPorts[i].id; 451224aee3fSIngo Weinhold 452224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[i]); 453224aee3fSIngo Weinhold restore_interrupts(state); 454224aee3fSIngo Weinhold 455224aee3fSIngo Weinhold TRACE(("create_port() done: port created %ld\n", id)); 456224aee3fSIngo Weinhold 457224aee3fSIngo Weinhold return id; 458224aee3fSIngo Weinhold } 459224aee3fSIngo Weinhold } 460224aee3fSIngo Weinhold 461224aee3fSIngo Weinhold // not enough ports... 462224aee3fSIngo Weinhold 463224aee3fSIngo Weinhold // ToDo: due to sUsedPorts, this cannot happen anymore - as 464224aee3fSIngo Weinhold // long as sMaxPorts stays constant over the kernel run 465224aee3fSIngo Weinhold // time (which it should be). IOW we could simply panic() 466224aee3fSIngo Weinhold // here. 467224aee3fSIngo Weinhold 468224aee3fSIngo Weinhold RELEASE_PORT_LIST_LOCK(); 469224aee3fSIngo Weinhold restore_interrupts(state); 470224aee3fSIngo Weinhold 471224aee3fSIngo Weinhold status = B_NO_MORE_PORTS; 472224aee3fSIngo Weinhold 473224aee3fSIngo Weinhold delete_sem(writeSem); 474224aee3fSIngo Weinhold err3: 475224aee3fSIngo Weinhold delete_sem(readSem); 476224aee3fSIngo Weinhold err2: 477224aee3fSIngo Weinhold free((char *)name); 478224aee3fSIngo Weinhold err1: 479224aee3fSIngo Weinhold atomic_add(&sUsedPorts, -1); 480224aee3fSIngo Weinhold 481224aee3fSIngo Weinhold return status; 482224aee3fSIngo Weinhold } 483224aee3fSIngo Weinhold 484224aee3fSIngo Weinhold 485224aee3fSIngo Weinhold status_t 486224aee3fSIngo Weinhold close_port(port_id id) 487224aee3fSIngo Weinhold { 488224aee3fSIngo Weinhold sem_id readSem, writeSem; 489224aee3fSIngo Weinhold cpu_status state; 490224aee3fSIngo Weinhold int32 slot; 491224aee3fSIngo Weinhold 492224aee3fSIngo Weinhold TRACE(("close_port(id = %ld)\n", id)); 493224aee3fSIngo Weinhold 494224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 495224aee3fSIngo Weinhold return B_BAD_PORT_ID; 496224aee3fSIngo Weinhold 497224aee3fSIngo Weinhold slot = id % sMaxPorts; 498224aee3fSIngo Weinhold 499224aee3fSIngo Weinhold // walk through the sem list, trying to match name 500224aee3fSIngo Weinhold state = disable_interrupts(); 501224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 502224aee3fSIngo Weinhold 503224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 504224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 505224aee3fSIngo Weinhold restore_interrupts(state); 506224aee3fSIngo Weinhold TRACE(("close_port: invalid port_id %ld\n", id)); 507224aee3fSIngo Weinhold return B_BAD_PORT_ID; 508224aee3fSIngo Weinhold } 509224aee3fSIngo Weinhold 510224aee3fSIngo Weinhold // mark port to disable writing - deleting the semaphores will 511224aee3fSIngo Weinhold // wake up waiting read/writes 512224aee3fSIngo Weinhold sPorts[slot].capacity = 0; 513224aee3fSIngo Weinhold readSem = sPorts[slot].read_sem; 514224aee3fSIngo Weinhold writeSem = sPorts[slot].write_sem; 515224aee3fSIngo Weinhold 516224aee3fSIngo Weinhold notify_port_select_events(slot, B_EVENT_INVALID); 517224aee3fSIngo Weinhold sPorts[slot].select_infos = NULL; 518224aee3fSIngo Weinhold 519224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 520224aee3fSIngo Weinhold restore_interrupts(state); 521224aee3fSIngo Weinhold 522224aee3fSIngo Weinhold delete_sem(readSem); 523224aee3fSIngo Weinhold delete_sem(writeSem); 524224aee3fSIngo Weinhold 525224aee3fSIngo Weinhold return B_NO_ERROR; 526224aee3fSIngo Weinhold } 527224aee3fSIngo Weinhold 528224aee3fSIngo Weinhold 529224aee3fSIngo Weinhold status_t 530224aee3fSIngo Weinhold delete_port(port_id id) 531224aee3fSIngo Weinhold { 532224aee3fSIngo Weinhold cpu_status state; 533224aee3fSIngo Weinhold sem_id readSem, writeSem; 534224aee3fSIngo Weinhold const char *name; 535224aee3fSIngo Weinhold struct list list; 536224aee3fSIngo Weinhold port_msg *msg; 537224aee3fSIngo Weinhold int32 slot; 538224aee3fSIngo Weinhold 539224aee3fSIngo Weinhold TRACE(("delete_port(id = %ld)\n", id)); 540224aee3fSIngo Weinhold 541224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 542224aee3fSIngo Weinhold return B_BAD_PORT_ID; 543224aee3fSIngo Weinhold 544224aee3fSIngo Weinhold slot = id % sMaxPorts; 545224aee3fSIngo Weinhold 546224aee3fSIngo Weinhold state = disable_interrupts(); 547224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 548224aee3fSIngo Weinhold 549224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 550224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 551224aee3fSIngo Weinhold restore_interrupts(state); 552224aee3fSIngo Weinhold 553224aee3fSIngo Weinhold TRACE(("delete_port: invalid port_id %ld\n", id)); 554224aee3fSIngo Weinhold return B_BAD_PORT_ID; 555224aee3fSIngo Weinhold } 556224aee3fSIngo Weinhold 557224aee3fSIngo Weinhold /* mark port as invalid */ 558224aee3fSIngo Weinhold sPorts[slot].id = -1; 559224aee3fSIngo Weinhold name = sPorts[slot].name; 560224aee3fSIngo Weinhold readSem = sPorts[slot].read_sem; 561224aee3fSIngo Weinhold writeSem = sPorts[slot].write_sem; 562224aee3fSIngo Weinhold sPorts[slot].name = NULL; 563224aee3fSIngo Weinhold list_move_to_list(&sPorts[slot].msg_queue, &list); 564224aee3fSIngo Weinhold 565224aee3fSIngo Weinhold notify_port_select_events(slot, B_EVENT_INVALID); 566224aee3fSIngo Weinhold sPorts[slot].select_infos = NULL; 567224aee3fSIngo Weinhold 568224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 569224aee3fSIngo Weinhold 570224aee3fSIngo Weinhold // update the first free slot hint in the array 571224aee3fSIngo Weinhold GRAB_PORT_LIST_LOCK(); 572224aee3fSIngo Weinhold if (slot < sFirstFreeSlot) 573224aee3fSIngo Weinhold sFirstFreeSlot = slot; 574224aee3fSIngo Weinhold RELEASE_PORT_LIST_LOCK(); 575224aee3fSIngo Weinhold 576224aee3fSIngo Weinhold restore_interrupts(state); 577224aee3fSIngo Weinhold 578224aee3fSIngo Weinhold atomic_add(&sUsedPorts, -1); 579224aee3fSIngo Weinhold 580224aee3fSIngo Weinhold // free the queue 581224aee3fSIngo Weinhold while ((msg = (port_msg *)list_remove_head_item(&list)) != NULL) { 582224aee3fSIngo Weinhold put_port_msg(msg); 583224aee3fSIngo Weinhold } 584224aee3fSIngo Weinhold 585224aee3fSIngo Weinhold free((char *)name); 586224aee3fSIngo Weinhold 587224aee3fSIngo Weinhold // release the threads that were blocking on this port by deleting the sem 588224aee3fSIngo Weinhold // read_port() will see the B_BAD_SEM_ID acq_sem() return value, and act accordingly 589224aee3fSIngo Weinhold delete_sem(readSem); 590224aee3fSIngo Weinhold delete_sem(writeSem); 591224aee3fSIngo Weinhold 592224aee3fSIngo Weinhold return B_OK; 593224aee3fSIngo Weinhold } 594224aee3fSIngo Weinhold 595224aee3fSIngo Weinhold 596224aee3fSIngo Weinhold status_t 597224aee3fSIngo Weinhold select_port(int32 id, struct select_info *info, bool kernel) 598224aee3fSIngo Weinhold { 599224aee3fSIngo Weinhold cpu_status state; 600224aee3fSIngo Weinhold int32 slot; 601224aee3fSIngo Weinhold status_t error = B_OK; 602224aee3fSIngo Weinhold 603224aee3fSIngo Weinhold if (id < 0) 604224aee3fSIngo Weinhold return B_BAD_PORT_ID; 605224aee3fSIngo Weinhold 606224aee3fSIngo Weinhold slot = id % sMaxPorts; 607224aee3fSIngo Weinhold 608224aee3fSIngo Weinhold state = disable_interrupts(); 609224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 610224aee3fSIngo Weinhold 611224aee3fSIngo Weinhold if (sPorts[slot].id != id || is_port_closed(slot)) { 612224aee3fSIngo Weinhold // bad port ID 613224aee3fSIngo Weinhold error = B_BAD_SEM_ID; 614224aee3fSIngo Weinhold } else if (!kernel && sPorts[slot].owner == team_get_kernel_team_id()) { 615224aee3fSIngo Weinhold // kernel port, but call from userland 616224aee3fSIngo Weinhold error = B_NOT_ALLOWED; 617224aee3fSIngo Weinhold } else { 618224aee3fSIngo Weinhold info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID; 619224aee3fSIngo Weinhold 620224aee3fSIngo Weinhold if (info->selected_events != 0) { 621224aee3fSIngo Weinhold uint16 events = 0; 622224aee3fSIngo Weinhold int32 writeCount = 0; 623224aee3fSIngo Weinhold 624224aee3fSIngo Weinhold info->next = sPorts[slot].select_infos; 625224aee3fSIngo Weinhold sPorts[slot].select_infos = info; 626224aee3fSIngo Weinhold 627224aee3fSIngo Weinhold // check for events 628224aee3fSIngo Weinhold if ((info->selected_events & B_EVENT_READ) != 0 629224aee3fSIngo Weinhold && !list_is_empty(&sPorts[slot].msg_queue)) { 630224aee3fSIngo Weinhold events |= B_EVENT_READ; 631224aee3fSIngo Weinhold } 632224aee3fSIngo Weinhold 633224aee3fSIngo Weinhold if (get_sem_count(sPorts[slot].write_sem, &writeCount) == B_OK 634224aee3fSIngo Weinhold && writeCount > 0) { 635224aee3fSIngo Weinhold events |= B_EVENT_WRITE; 636224aee3fSIngo Weinhold } 637224aee3fSIngo Weinhold 638224aee3fSIngo Weinhold if (events != 0) 639224aee3fSIngo Weinhold notify_select_events(info, events); 640224aee3fSIngo Weinhold } 641224aee3fSIngo Weinhold } 642224aee3fSIngo Weinhold 643224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 644224aee3fSIngo Weinhold restore_interrupts(state); 645224aee3fSIngo Weinhold 646224aee3fSIngo Weinhold return error; 647224aee3fSIngo Weinhold } 648224aee3fSIngo Weinhold 649224aee3fSIngo Weinhold 650224aee3fSIngo Weinhold status_t 651224aee3fSIngo Weinhold deselect_port(int32 id, struct select_info *info, bool kernel) 652224aee3fSIngo Weinhold { 653224aee3fSIngo Weinhold cpu_status state; 654224aee3fSIngo Weinhold int32 slot; 655224aee3fSIngo Weinhold 656224aee3fSIngo Weinhold if (id < 0) 657224aee3fSIngo Weinhold return B_BAD_PORT_ID; 658224aee3fSIngo Weinhold 659224aee3fSIngo Weinhold if (info->selected_events == 0) 660224aee3fSIngo Weinhold return B_OK; 661224aee3fSIngo Weinhold 662224aee3fSIngo Weinhold slot = id % sMaxPorts; 663224aee3fSIngo Weinhold 664224aee3fSIngo Weinhold state = disable_interrupts(); 665224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 666224aee3fSIngo Weinhold 667224aee3fSIngo Weinhold if (sPorts[slot].id == id) { 668224aee3fSIngo Weinhold select_info** infoLocation = &sPorts[slot].select_infos; 669224aee3fSIngo Weinhold while (*infoLocation != NULL && *infoLocation != info) 670224aee3fSIngo Weinhold infoLocation = &(*infoLocation)->next; 671224aee3fSIngo Weinhold 672224aee3fSIngo Weinhold if (*infoLocation == info) 673224aee3fSIngo Weinhold *infoLocation = info->next; 674224aee3fSIngo Weinhold } 675224aee3fSIngo Weinhold 676224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 677224aee3fSIngo Weinhold restore_interrupts(state); 678224aee3fSIngo Weinhold 679224aee3fSIngo Weinhold return B_OK; 680224aee3fSIngo Weinhold } 681224aee3fSIngo Weinhold 682224aee3fSIngo Weinhold 683224aee3fSIngo Weinhold port_id 684224aee3fSIngo Weinhold find_port(const char *name) 685224aee3fSIngo Weinhold { 686224aee3fSIngo Weinhold port_id portFound = B_NAME_NOT_FOUND; 687224aee3fSIngo Weinhold cpu_status state; 688224aee3fSIngo Weinhold int32 i; 689224aee3fSIngo Weinhold 690224aee3fSIngo Weinhold TRACE(("find_port(name = \"%s\")\n", name)); 691224aee3fSIngo Weinhold 692224aee3fSIngo Weinhold if (!sPortsActive) 693224aee3fSIngo Weinhold return B_NAME_NOT_FOUND; 694224aee3fSIngo Weinhold if (name == NULL) 695224aee3fSIngo Weinhold return B_BAD_VALUE; 696224aee3fSIngo Weinhold 697224aee3fSIngo Weinhold // Since we have to check every single port, and we don't 698224aee3fSIngo Weinhold // care if it goes away at any point, we're only grabbing 699224aee3fSIngo Weinhold // the port lock in question, not the port list lock 700224aee3fSIngo Weinhold 701224aee3fSIngo Weinhold // loop over list 702224aee3fSIngo Weinhold for (i = 0; i < sMaxPorts && portFound < B_OK; i++) { 703224aee3fSIngo Weinhold // lock every individual port before comparing 704224aee3fSIngo Weinhold state = disable_interrupts(); 705224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[i]); 706224aee3fSIngo Weinhold 707224aee3fSIngo Weinhold if (sPorts[i].id >= 0 && !strcmp(name, sPorts[i].name)) 708224aee3fSIngo Weinhold portFound = sPorts[i].id; 709224aee3fSIngo Weinhold 710224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[i]); 711224aee3fSIngo Weinhold restore_interrupts(state); 712224aee3fSIngo Weinhold } 713224aee3fSIngo Weinhold 714224aee3fSIngo Weinhold return portFound; 715224aee3fSIngo Weinhold } 716224aee3fSIngo Weinhold 717224aee3fSIngo Weinhold 718224aee3fSIngo Weinhold status_t 719224aee3fSIngo Weinhold _get_port_info(port_id id, port_info *info, size_t size) 720224aee3fSIngo Weinhold { 721224aee3fSIngo Weinhold cpu_status state; 722224aee3fSIngo Weinhold int slot; 723224aee3fSIngo Weinhold 724224aee3fSIngo Weinhold TRACE(("get_port_info(id = %ld)\n", id)); 725224aee3fSIngo Weinhold 726224aee3fSIngo Weinhold if (info == NULL || size != sizeof(port_info)) 727224aee3fSIngo Weinhold return B_BAD_VALUE; 728224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 729224aee3fSIngo Weinhold return B_BAD_PORT_ID; 730224aee3fSIngo Weinhold 731224aee3fSIngo Weinhold slot = id % sMaxPorts; 732224aee3fSIngo Weinhold 733224aee3fSIngo Weinhold state = disable_interrupts(); 734224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 735224aee3fSIngo Weinhold 736224aee3fSIngo Weinhold if (sPorts[slot].id != id || sPorts[slot].capacity == 0) { 737224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 738224aee3fSIngo Weinhold restore_interrupts(state); 739224aee3fSIngo Weinhold TRACE(("get_port_info: invalid port_id %ld\n", id)); 740224aee3fSIngo Weinhold return B_BAD_PORT_ID; 741224aee3fSIngo Weinhold } 742224aee3fSIngo Weinhold 743224aee3fSIngo Weinhold // fill a port_info struct with info 744224aee3fSIngo Weinhold fill_port_info(&sPorts[slot], info, size); 745224aee3fSIngo Weinhold 746224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 747224aee3fSIngo Weinhold restore_interrupts(state); 748224aee3fSIngo Weinhold 749224aee3fSIngo Weinhold return B_OK; 750224aee3fSIngo Weinhold } 751224aee3fSIngo Weinhold 752224aee3fSIngo Weinhold 753224aee3fSIngo Weinhold status_t 754224aee3fSIngo Weinhold _get_next_port_info(team_id team, int32 *_cookie, struct port_info *info, size_t size) 755224aee3fSIngo Weinhold { 756224aee3fSIngo Weinhold cpu_status state; 757224aee3fSIngo Weinhold int slot; 758224aee3fSIngo Weinhold 759224aee3fSIngo Weinhold TRACE(("get_next_port_info(team = %ld)\n", team)); 760224aee3fSIngo Weinhold 761224aee3fSIngo Weinhold if (info == NULL || size != sizeof(port_info) || _cookie == NULL || team < B_OK) 762224aee3fSIngo Weinhold return B_BAD_VALUE; 763224aee3fSIngo Weinhold if (!sPortsActive) 764224aee3fSIngo Weinhold return B_BAD_PORT_ID; 765224aee3fSIngo Weinhold 766224aee3fSIngo Weinhold slot = *_cookie; 767224aee3fSIngo Weinhold if (slot >= sMaxPorts) 768224aee3fSIngo Weinhold return B_BAD_PORT_ID; 769224aee3fSIngo Weinhold 770224aee3fSIngo Weinhold if (team == B_CURRENT_TEAM) 771224aee3fSIngo Weinhold team = team_get_current_team_id(); 772224aee3fSIngo Weinhold 773224aee3fSIngo Weinhold info->port = -1; // used as found flag 774224aee3fSIngo Weinhold 775224aee3fSIngo Weinhold // spinlock 776224aee3fSIngo Weinhold state = disable_interrupts(); 777224aee3fSIngo Weinhold GRAB_PORT_LIST_LOCK(); 778224aee3fSIngo Weinhold 779224aee3fSIngo Weinhold while (slot < sMaxPorts) { 780224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 781224aee3fSIngo Weinhold if (sPorts[slot].id != -1 && sPorts[slot].capacity != 0 && sPorts[slot].owner == team) { 782224aee3fSIngo Weinhold // found one! 783224aee3fSIngo Weinhold fill_port_info(&sPorts[slot], info, size); 784224aee3fSIngo Weinhold 785224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 786224aee3fSIngo Weinhold slot++; 787224aee3fSIngo Weinhold break; 788224aee3fSIngo Weinhold } 789224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 790224aee3fSIngo Weinhold slot++; 791224aee3fSIngo Weinhold } 792224aee3fSIngo Weinhold RELEASE_PORT_LIST_LOCK(); 793224aee3fSIngo Weinhold restore_interrupts(state); 794224aee3fSIngo Weinhold 795224aee3fSIngo Weinhold if (info->port == -1) 796224aee3fSIngo Weinhold return B_BAD_PORT_ID; 797224aee3fSIngo Weinhold 798224aee3fSIngo Weinhold *_cookie = slot; 799224aee3fSIngo Weinhold return B_NO_ERROR; 800224aee3fSIngo Weinhold } 801224aee3fSIngo Weinhold 802224aee3fSIngo Weinhold 803224aee3fSIngo Weinhold ssize_t 804224aee3fSIngo Weinhold port_buffer_size(port_id id) 805224aee3fSIngo Weinhold { 806224aee3fSIngo Weinhold return port_buffer_size_etc(id, 0, 0); 807224aee3fSIngo Weinhold } 808224aee3fSIngo Weinhold 809224aee3fSIngo Weinhold 810224aee3fSIngo Weinhold ssize_t 811224aee3fSIngo Weinhold port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout) 812224aee3fSIngo Weinhold { 813224aee3fSIngo Weinhold cpu_status state; 814224aee3fSIngo Weinhold sem_id cachedSem; 815224aee3fSIngo Weinhold status_t status; 816224aee3fSIngo Weinhold port_msg *msg; 817224aee3fSIngo Weinhold ssize_t size; 818224aee3fSIngo Weinhold int32 slot; 819224aee3fSIngo Weinhold 820224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 821224aee3fSIngo Weinhold return B_BAD_PORT_ID; 822224aee3fSIngo Weinhold 823224aee3fSIngo Weinhold slot = id % sMaxPorts; 824224aee3fSIngo Weinhold 825224aee3fSIngo Weinhold state = disable_interrupts(); 826224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 827224aee3fSIngo Weinhold 828224aee3fSIngo Weinhold if (sPorts[slot].id != id 829224aee3fSIngo Weinhold || (is_port_closed(slot) && list_is_empty(&sPorts[slot].msg_queue))) { 830224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 831224aee3fSIngo Weinhold restore_interrupts(state); 832224aee3fSIngo Weinhold TRACE(("port_buffer_size_etc(): %s port %ld\n", 833224aee3fSIngo Weinhold sPorts[slot].id == id ? "closed" : "invalid", id)); 834224aee3fSIngo Weinhold return B_BAD_PORT_ID; 835224aee3fSIngo Weinhold } 836224aee3fSIngo Weinhold 837224aee3fSIngo Weinhold cachedSem = sPorts[slot].read_sem; 838224aee3fSIngo Weinhold 839224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 840224aee3fSIngo Weinhold restore_interrupts(state); 841224aee3fSIngo Weinhold 842224aee3fSIngo Weinhold // block if no message, or, if B_TIMEOUT flag set, block with timeout 843224aee3fSIngo Weinhold 844224aee3fSIngo Weinhold status = acquire_sem_etc(cachedSem, 1, flags, timeout); 845224aee3fSIngo Weinhold if (status != B_OK && status != B_BAD_SEM_ID) 846224aee3fSIngo Weinhold return status; 847224aee3fSIngo Weinhold 848224aee3fSIngo Weinhold // in case of B_BAD_SEM_ID, the port might have been closed but not yet 849224aee3fSIngo Weinhold // deleted, ie. there could still be messages waiting for us 850224aee3fSIngo Weinhold 851224aee3fSIngo Weinhold state = disable_interrupts(); 852224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 853224aee3fSIngo Weinhold 854224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 855224aee3fSIngo Weinhold // the port is no longer there 856224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 857224aee3fSIngo Weinhold restore_interrupts(state); 858224aee3fSIngo Weinhold return B_BAD_PORT_ID; 859224aee3fSIngo Weinhold } 860224aee3fSIngo Weinhold 861224aee3fSIngo Weinhold // determine tail & get the length of the message 862224aee3fSIngo Weinhold msg = (port_msg*)list_get_first_item(&sPorts[slot].msg_queue); 863224aee3fSIngo Weinhold if (msg == NULL) { 864224aee3fSIngo Weinhold if (status == B_OK) 865224aee3fSIngo Weinhold panic("port %ld: no messages found\n", sPorts[slot].id); 866224aee3fSIngo Weinhold 867224aee3fSIngo Weinhold size = B_BAD_PORT_ID; 868224aee3fSIngo Weinhold } else 869224aee3fSIngo Weinhold size = msg->size; 870224aee3fSIngo Weinhold 871224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 872224aee3fSIngo Weinhold restore_interrupts(state); 873224aee3fSIngo Weinhold 874224aee3fSIngo Weinhold // restore read_sem, as we haven't read from the port 875224aee3fSIngo Weinhold release_sem(cachedSem); 876224aee3fSIngo Weinhold 877224aee3fSIngo Weinhold // return length of item at end of queue 878224aee3fSIngo Weinhold return size; 879224aee3fSIngo Weinhold } 880224aee3fSIngo Weinhold 881224aee3fSIngo Weinhold 882224aee3fSIngo Weinhold ssize_t 883224aee3fSIngo Weinhold port_count(port_id id) 884224aee3fSIngo Weinhold { 885224aee3fSIngo Weinhold cpu_status state; 886224aee3fSIngo Weinhold int32 count = 0; 887224aee3fSIngo Weinhold int32 slot; 888224aee3fSIngo Weinhold 889224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 890224aee3fSIngo Weinhold return B_BAD_PORT_ID; 891224aee3fSIngo Weinhold 892224aee3fSIngo Weinhold slot = id % sMaxPorts; 893224aee3fSIngo Weinhold 894224aee3fSIngo Weinhold state = disable_interrupts(); 895224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 896224aee3fSIngo Weinhold 897224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 898224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 899224aee3fSIngo Weinhold restore_interrupts(state); 900224aee3fSIngo Weinhold TRACE(("port_count: invalid port_id %ld\n", id)); 901224aee3fSIngo Weinhold return B_BAD_PORT_ID; 902224aee3fSIngo Weinhold } 903224aee3fSIngo Weinhold 904224aee3fSIngo Weinhold if (get_sem_count(sPorts[slot].read_sem, &count) == B_OK) { 905224aee3fSIngo Weinhold // do not return negative numbers 906224aee3fSIngo Weinhold if (count < 0) 907224aee3fSIngo Weinhold count = 0; 908224aee3fSIngo Weinhold } else { 909224aee3fSIngo Weinhold // the port might have been closed - we need to actually count the messages 910224aee3fSIngo Weinhold void *message = NULL; 911224aee3fSIngo Weinhold while ((message = list_get_next_item(&sPorts[slot].msg_queue, message)) != NULL) { 912224aee3fSIngo Weinhold count++; 913224aee3fSIngo Weinhold } 914224aee3fSIngo Weinhold } 915224aee3fSIngo Weinhold 916224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 917224aee3fSIngo Weinhold restore_interrupts(state); 918224aee3fSIngo Weinhold 919224aee3fSIngo Weinhold // return count of messages 920224aee3fSIngo Weinhold return count; 921224aee3fSIngo Weinhold } 922224aee3fSIngo Weinhold 923224aee3fSIngo Weinhold 924224aee3fSIngo Weinhold ssize_t 925224aee3fSIngo Weinhold read_port(port_id port, int32 *msgCode, void *msgBuffer, size_t bufferSize) 926224aee3fSIngo Weinhold { 927224aee3fSIngo Weinhold return read_port_etc(port, msgCode, msgBuffer, bufferSize, 0, 0); 928224aee3fSIngo Weinhold } 929224aee3fSIngo Weinhold 930224aee3fSIngo Weinhold 931224aee3fSIngo Weinhold ssize_t 932224aee3fSIngo Weinhold read_port_etc(port_id id, int32 *_msgCode, void *msgBuffer, size_t bufferSize, 933224aee3fSIngo Weinhold uint32 flags, bigtime_t timeout) 934224aee3fSIngo Weinhold { 935224aee3fSIngo Weinhold cpu_status state; 936224aee3fSIngo Weinhold sem_id cachedSem; 937224aee3fSIngo Weinhold status_t status; 938224aee3fSIngo Weinhold bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0; 939224aee3fSIngo Weinhold port_msg *msg; 940224aee3fSIngo Weinhold size_t size; 941224aee3fSIngo Weinhold int slot; 942224aee3fSIngo Weinhold 943224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 944224aee3fSIngo Weinhold return B_BAD_PORT_ID; 945224aee3fSIngo Weinhold 946224aee3fSIngo Weinhold if ((msgBuffer == NULL && bufferSize > 0) 947224aee3fSIngo Weinhold || timeout < 0) 948224aee3fSIngo Weinhold return B_BAD_VALUE; 949224aee3fSIngo Weinhold 950224aee3fSIngo Weinhold flags = flags & (B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT 951224aee3fSIngo Weinhold | B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT); 952224aee3fSIngo Weinhold slot = id % sMaxPorts; 953224aee3fSIngo Weinhold 954224aee3fSIngo Weinhold state = disable_interrupts(); 955224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 956224aee3fSIngo Weinhold 957224aee3fSIngo Weinhold if (sPorts[slot].id != id 958224aee3fSIngo Weinhold || (is_port_closed(slot) && list_is_empty(&sPorts[slot].msg_queue))) { 959224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 960224aee3fSIngo Weinhold restore_interrupts(state); 961224aee3fSIngo Weinhold TRACE(("read_port_etc(): %s port %ld\n", 962224aee3fSIngo Weinhold sPorts[slot].id == id ? "closed" : "invalid", id)); 963224aee3fSIngo Weinhold return B_BAD_PORT_ID; 964224aee3fSIngo Weinhold } 965224aee3fSIngo Weinhold // store sem_id in local variable 966224aee3fSIngo Weinhold cachedSem = sPorts[slot].read_sem; 967224aee3fSIngo Weinhold 968224aee3fSIngo Weinhold // unlock port && enable ints/ 969224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 970224aee3fSIngo Weinhold restore_interrupts(state); 971224aee3fSIngo Weinhold 972224aee3fSIngo Weinhold status = acquire_sem_etc(cachedSem, 1, flags, timeout); 973224aee3fSIngo Weinhold // get 1 entry from the queue, block if needed 974224aee3fSIngo Weinhold 975224aee3fSIngo Weinhold if (status != B_OK && status != B_BAD_SEM_ID) 976224aee3fSIngo Weinhold return status; 977224aee3fSIngo Weinhold 978224aee3fSIngo Weinhold // in case of B_BAD_SEM_ID, the port might have been closed but not yet 979224aee3fSIngo Weinhold // deleted, ie. there could still be messages waiting for us 980224aee3fSIngo Weinhold 981224aee3fSIngo Weinhold state = disable_interrupts(); 982224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 983224aee3fSIngo Weinhold 984224aee3fSIngo Weinhold // first, let's check if the port is still alive 985224aee3fSIngo Weinhold if (sPorts[slot].id == -1) { 986224aee3fSIngo Weinhold // the port has been deleted in the meantime 987224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 988224aee3fSIngo Weinhold restore_interrupts(state); 989224aee3fSIngo Weinhold return B_BAD_PORT_ID; 990224aee3fSIngo Weinhold } 991224aee3fSIngo Weinhold 992224aee3fSIngo Weinhold msg = (port_msg*)list_get_first_item(&sPorts[slot].msg_queue); 993224aee3fSIngo Weinhold if (msg == NULL) { 994224aee3fSIngo Weinhold if (status == B_OK) 995224aee3fSIngo Weinhold panic("port %ld: no messages found", sPorts[slot].id); 996224aee3fSIngo Weinhold 997224aee3fSIngo Weinhold // the port has obviously been closed, but no messages are left anymore 998224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 999224aee3fSIngo Weinhold restore_interrupts(state); 1000224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1001224aee3fSIngo Weinhold } 1002224aee3fSIngo Weinhold 1003224aee3fSIngo Weinhold list_remove_link(msg); 1004224aee3fSIngo Weinhold 1005224aee3fSIngo Weinhold sPorts[slot].total_count++; 1006224aee3fSIngo Weinhold 1007224aee3fSIngo Weinhold notify_port_select_events(slot, B_EVENT_WRITE); 1008224aee3fSIngo Weinhold 1009224aee3fSIngo Weinhold cachedSem = sPorts[slot].write_sem; 1010224aee3fSIngo Weinhold 1011224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 1012224aee3fSIngo Weinhold restore_interrupts(state); 1013224aee3fSIngo Weinhold 1014224aee3fSIngo Weinhold // check output buffer size 1015224aee3fSIngo Weinhold size = min_c(bufferSize, msg->size); 1016224aee3fSIngo Weinhold 1017224aee3fSIngo Weinhold // copy message 1018224aee3fSIngo Weinhold if (_msgCode != NULL) 1019224aee3fSIngo Weinhold *_msgCode = msg->code; 1020224aee3fSIngo Weinhold if (size > 0) { 1021224aee3fSIngo Weinhold if (userCopy) { 1022224aee3fSIngo Weinhold if ((status = cbuf_user_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size) < B_OK)) { 1023224aee3fSIngo Weinhold // leave the port intact, for other threads that might not crash 1024224aee3fSIngo Weinhold put_port_msg(msg); 1025224aee3fSIngo Weinhold release_sem(cachedSem); 1026224aee3fSIngo Weinhold return status; 1027224aee3fSIngo Weinhold } 1028224aee3fSIngo Weinhold } else 1029224aee3fSIngo Weinhold cbuf_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size); 1030224aee3fSIngo Weinhold } 1031224aee3fSIngo Weinhold put_port_msg(msg); 1032224aee3fSIngo Weinhold 1033224aee3fSIngo Weinhold // make one spot in queue available again for write 1034224aee3fSIngo Weinhold release_sem(cachedSem); 1035224aee3fSIngo Weinhold // ToDo: we might think about setting B_NO_RESCHEDULE here 1036224aee3fSIngo Weinhold // from time to time (always?) 1037224aee3fSIngo Weinhold 1038224aee3fSIngo Weinhold return size; 1039224aee3fSIngo Weinhold } 1040224aee3fSIngo Weinhold 1041224aee3fSIngo Weinhold 1042224aee3fSIngo Weinhold status_t 1043224aee3fSIngo Weinhold write_port(port_id id, int32 msgCode, const void *msgBuffer, size_t bufferSize) 1044224aee3fSIngo Weinhold { 1045224aee3fSIngo Weinhold iovec vec = { (void *)msgBuffer, bufferSize }; 1046224aee3fSIngo Weinhold 1047224aee3fSIngo Weinhold return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0); 1048224aee3fSIngo Weinhold } 1049224aee3fSIngo Weinhold 1050224aee3fSIngo Weinhold 1051224aee3fSIngo Weinhold status_t 1052224aee3fSIngo Weinhold write_port_etc(port_id id, int32 msgCode, const void *msgBuffer, 1053224aee3fSIngo Weinhold size_t bufferSize, uint32 flags, bigtime_t timeout) 1054224aee3fSIngo Weinhold { 1055224aee3fSIngo Weinhold iovec vec = { (void *)msgBuffer, bufferSize }; 1056224aee3fSIngo Weinhold 1057224aee3fSIngo Weinhold return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout); 1058224aee3fSIngo Weinhold } 1059224aee3fSIngo Weinhold 1060224aee3fSIngo Weinhold 1061224aee3fSIngo Weinhold status_t 1062224aee3fSIngo Weinhold writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs, 1063224aee3fSIngo Weinhold size_t vecCount, size_t bufferSize, uint32 flags, 1064224aee3fSIngo Weinhold bigtime_t timeout) 1065224aee3fSIngo Weinhold { 1066224aee3fSIngo Weinhold cpu_status state; 1067224aee3fSIngo Weinhold sem_id cachedSem; 1068224aee3fSIngo Weinhold status_t status; 1069224aee3fSIngo Weinhold port_msg *msg; 1070224aee3fSIngo Weinhold bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0; 1071224aee3fSIngo Weinhold int slot; 1072224aee3fSIngo Weinhold 1073224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 1074224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1075224aee3fSIngo Weinhold 1076224aee3fSIngo Weinhold // mask irrelevant flags (for acquire_sem() usage) 1077224aee3fSIngo Weinhold flags = flags & (B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT 1078224aee3fSIngo Weinhold | B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT); 1079224aee3fSIngo Weinhold slot = id % sMaxPorts; 1080224aee3fSIngo Weinhold 1081224aee3fSIngo Weinhold if (bufferSize > PORT_MAX_MESSAGE_SIZE) 1082224aee3fSIngo Weinhold return B_BAD_VALUE; 1083224aee3fSIngo Weinhold 1084224aee3fSIngo Weinhold state = disable_interrupts(); 1085224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 1086224aee3fSIngo Weinhold 1087224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 1088224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 1089224aee3fSIngo Weinhold restore_interrupts(state); 1090224aee3fSIngo Weinhold TRACE(("write_port_etc: invalid port_id %ld\n", id)); 1091224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1092224aee3fSIngo Weinhold } 1093224aee3fSIngo Weinhold 1094224aee3fSIngo Weinhold if (is_port_closed(slot)) { 1095224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 1096224aee3fSIngo Weinhold restore_interrupts(state); 1097224aee3fSIngo Weinhold TRACE(("write_port_etc: port %ld closed\n", id)); 1098224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1099224aee3fSIngo Weinhold } 1100224aee3fSIngo Weinhold 1101224aee3fSIngo Weinhold // store sem_id in local variable 1102224aee3fSIngo Weinhold cachedSem = sPorts[slot].write_sem; 1103224aee3fSIngo Weinhold 1104224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 1105224aee3fSIngo Weinhold restore_interrupts(state); 1106224aee3fSIngo Weinhold 1107224aee3fSIngo Weinhold status = acquire_sem_etc(cachedSem, 1, flags, timeout); 1108224aee3fSIngo Weinhold // get 1 entry from the queue, block if needed 1109224aee3fSIngo Weinhold 1110224aee3fSIngo Weinhold if (status == B_BAD_SEM_ID) { 1111224aee3fSIngo Weinhold // somebody deleted or closed the port 1112224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1113224aee3fSIngo Weinhold } 1114224aee3fSIngo Weinhold if (status != B_OK) 1115224aee3fSIngo Weinhold return status; 1116224aee3fSIngo Weinhold 1117224aee3fSIngo Weinhold msg = get_port_msg(msgCode, bufferSize); 1118224aee3fSIngo Weinhold if (msg == NULL) 1119224aee3fSIngo Weinhold return B_NO_MEMORY; 1120224aee3fSIngo Weinhold 1121224aee3fSIngo Weinhold if (bufferSize > 0) { 1122224aee3fSIngo Weinhold uint32 i; 1123224aee3fSIngo Weinhold if (userCopy) { 1124224aee3fSIngo Weinhold // copy from user memory 1125224aee3fSIngo Weinhold for (i = 0; i < vecCount; i++) { 1126224aee3fSIngo Weinhold size_t bytes = msgVecs[i].iov_len; 1127224aee3fSIngo Weinhold if (bytes > bufferSize) 1128224aee3fSIngo Weinhold bytes = bufferSize; 1129224aee3fSIngo Weinhold 1130224aee3fSIngo Weinhold if ((status = cbuf_user_memcpy_to_chain(msg->buffer_chain, 1131224aee3fSIngo Weinhold 0, msgVecs[i].iov_base, bytes)) < B_OK) 1132224aee3fSIngo Weinhold return status; 1133224aee3fSIngo Weinhold 1134224aee3fSIngo Weinhold bufferSize -= bytes; 1135224aee3fSIngo Weinhold if (bufferSize == 0) 1136224aee3fSIngo Weinhold break; 1137224aee3fSIngo Weinhold } 1138224aee3fSIngo Weinhold } else { 1139224aee3fSIngo Weinhold // copy from kernel memory 1140224aee3fSIngo Weinhold for (i = 0; i < vecCount; i++) { 1141224aee3fSIngo Weinhold size_t bytes = msgVecs[i].iov_len; 1142224aee3fSIngo Weinhold if (bytes > bufferSize) 1143224aee3fSIngo Weinhold bytes = bufferSize; 1144224aee3fSIngo Weinhold 1145224aee3fSIngo Weinhold if ((status = cbuf_memcpy_to_chain(msg->buffer_chain, 1146224aee3fSIngo Weinhold 0, msgVecs[i].iov_base, bytes)) < 0) 1147224aee3fSIngo Weinhold return status; 1148224aee3fSIngo Weinhold 1149224aee3fSIngo Weinhold bufferSize -= bytes; 1150224aee3fSIngo Weinhold if (bufferSize == 0) 1151224aee3fSIngo Weinhold break; 1152224aee3fSIngo Weinhold } 1153224aee3fSIngo Weinhold } 1154224aee3fSIngo Weinhold } 1155224aee3fSIngo Weinhold 1156224aee3fSIngo Weinhold // attach message to queue 1157224aee3fSIngo Weinhold state = disable_interrupts(); 1158224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 1159224aee3fSIngo Weinhold 1160224aee3fSIngo Weinhold // first, let's check if the port is still alive 1161224aee3fSIngo Weinhold if (sPorts[slot].id == -1) { 1162224aee3fSIngo Weinhold // the port has been deleted in the meantime 1163224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 1164224aee3fSIngo Weinhold restore_interrupts(state); 1165224aee3fSIngo Weinhold 1166224aee3fSIngo Weinhold put_port_msg(msg); 1167224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1168224aee3fSIngo Weinhold } 1169224aee3fSIngo Weinhold 1170224aee3fSIngo Weinhold list_add_item(&sPorts[slot].msg_queue, msg); 1171224aee3fSIngo Weinhold 1172224aee3fSIngo Weinhold notify_port_select_events(slot, B_EVENT_READ); 1173224aee3fSIngo Weinhold 1174224aee3fSIngo Weinhold // store sem_id in local variable 1175224aee3fSIngo Weinhold cachedSem = sPorts[slot].read_sem; 1176224aee3fSIngo Weinhold 1177224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 1178224aee3fSIngo Weinhold restore_interrupts(state); 1179224aee3fSIngo Weinhold 1180224aee3fSIngo Weinhold // release sem, allowing read (might reschedule) 1181224aee3fSIngo Weinhold release_sem(cachedSem); 1182224aee3fSIngo Weinhold 1183224aee3fSIngo Weinhold return B_NO_ERROR; 1184224aee3fSIngo Weinhold } 1185224aee3fSIngo Weinhold 1186224aee3fSIngo Weinhold 1187224aee3fSIngo Weinhold status_t 1188224aee3fSIngo Weinhold set_port_owner(port_id id, team_id team) 1189224aee3fSIngo Weinhold { 1190224aee3fSIngo Weinhold cpu_status state; 1191224aee3fSIngo Weinhold int slot; 1192224aee3fSIngo Weinhold // ToDo: Shouldn't we at least check, whether the team exists? 1193224aee3fSIngo Weinhold 1194224aee3fSIngo Weinhold TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, team)); 1195224aee3fSIngo Weinhold 1196224aee3fSIngo Weinhold if (!sPortsActive || id < 0) 1197224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1198224aee3fSIngo Weinhold 1199224aee3fSIngo Weinhold slot = id % sMaxPorts; 1200224aee3fSIngo Weinhold 1201224aee3fSIngo Weinhold state = disable_interrupts(); 1202224aee3fSIngo Weinhold GRAB_PORT_LOCK(sPorts[slot]); 1203224aee3fSIngo Weinhold 1204224aee3fSIngo Weinhold if (sPorts[slot].id != id) { 1205224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 1206224aee3fSIngo Weinhold restore_interrupts(state); 1207224aee3fSIngo Weinhold TRACE(("set_port_owner: invalid port_id %ld\n", id)); 1208224aee3fSIngo Weinhold return B_BAD_PORT_ID; 1209224aee3fSIngo Weinhold } 1210224aee3fSIngo Weinhold 1211224aee3fSIngo Weinhold // transfer ownership to other team 1212224aee3fSIngo Weinhold sPorts[slot].owner = team; 1213224aee3fSIngo Weinhold 1214224aee3fSIngo Weinhold // unlock port 1215224aee3fSIngo Weinhold RELEASE_PORT_LOCK(sPorts[slot]); 1216224aee3fSIngo Weinhold restore_interrupts(state); 1217224aee3fSIngo Weinhold 1218224aee3fSIngo Weinhold return B_NO_ERROR; 1219224aee3fSIngo Weinhold } 1220224aee3fSIngo Weinhold 1221224aee3fSIngo Weinhold 1222224aee3fSIngo Weinhold // #pragma mark - syscalls 1223224aee3fSIngo Weinhold 1224224aee3fSIngo Weinhold 1225224aee3fSIngo Weinhold port_id 1226224aee3fSIngo Weinhold _user_create_port(int32 queueLength, const char *userName) 1227224aee3fSIngo Weinhold { 1228224aee3fSIngo Weinhold char name[B_OS_NAME_LENGTH]; 1229224aee3fSIngo Weinhold 1230224aee3fSIngo Weinhold if (userName == NULL) 1231224aee3fSIngo Weinhold return create_port(queueLength, NULL); 1232224aee3fSIngo Weinhold 1233224aee3fSIngo Weinhold if (!IS_USER_ADDRESS(userName) 1234224aee3fSIngo Weinhold || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) 1235224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1236224aee3fSIngo Weinhold 1237224aee3fSIngo Weinhold return create_port(queueLength, name); 1238224aee3fSIngo Weinhold } 1239224aee3fSIngo Weinhold 1240224aee3fSIngo Weinhold 1241224aee3fSIngo Weinhold status_t 1242224aee3fSIngo Weinhold _user_close_port(port_id id) 1243224aee3fSIngo Weinhold { 1244224aee3fSIngo Weinhold return close_port(id); 1245224aee3fSIngo Weinhold } 1246224aee3fSIngo Weinhold 1247224aee3fSIngo Weinhold 1248224aee3fSIngo Weinhold status_t 1249224aee3fSIngo Weinhold _user_delete_port(port_id id) 1250224aee3fSIngo Weinhold { 1251224aee3fSIngo Weinhold return delete_port(id); 1252224aee3fSIngo Weinhold } 1253224aee3fSIngo Weinhold 1254224aee3fSIngo Weinhold 1255224aee3fSIngo Weinhold port_id 1256224aee3fSIngo Weinhold _user_find_port(const char *userName) 1257224aee3fSIngo Weinhold { 1258224aee3fSIngo Weinhold char name[B_OS_NAME_LENGTH]; 1259224aee3fSIngo Weinhold 1260224aee3fSIngo Weinhold if (userName == NULL) 1261224aee3fSIngo Weinhold return B_BAD_VALUE; 1262224aee3fSIngo Weinhold if (!IS_USER_ADDRESS(userName) 1263224aee3fSIngo Weinhold || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) 1264224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1265224aee3fSIngo Weinhold 1266224aee3fSIngo Weinhold return find_port(name); 1267224aee3fSIngo Weinhold } 1268224aee3fSIngo Weinhold 1269224aee3fSIngo Weinhold 1270224aee3fSIngo Weinhold status_t 1271224aee3fSIngo Weinhold _user_get_port_info(port_id id, struct port_info *userInfo) 1272224aee3fSIngo Weinhold { 1273224aee3fSIngo Weinhold struct port_info info; 1274224aee3fSIngo Weinhold status_t status; 1275224aee3fSIngo Weinhold 1276224aee3fSIngo Weinhold if (userInfo == NULL) 1277224aee3fSIngo Weinhold return B_BAD_VALUE; 1278224aee3fSIngo Weinhold if (!IS_USER_ADDRESS(userInfo)) 1279224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1280224aee3fSIngo Weinhold 1281224aee3fSIngo Weinhold status = get_port_info(id, &info); 1282224aee3fSIngo Weinhold 1283224aee3fSIngo Weinhold // copy back to user space 1284224aee3fSIngo Weinhold if (status == B_OK && user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK) 1285224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1286224aee3fSIngo Weinhold 1287224aee3fSIngo Weinhold return status; 1288224aee3fSIngo Weinhold } 1289224aee3fSIngo Weinhold 1290224aee3fSIngo Weinhold 1291224aee3fSIngo Weinhold status_t 1292224aee3fSIngo Weinhold _user_get_next_port_info(team_id team, int32 *userCookie, struct port_info *userInfo) 1293224aee3fSIngo Weinhold { 1294224aee3fSIngo Weinhold struct port_info info; 1295224aee3fSIngo Weinhold status_t status; 1296224aee3fSIngo Weinhold int32 cookie; 1297224aee3fSIngo Weinhold 1298224aee3fSIngo Weinhold if (userCookie == NULL || userInfo == NULL) 1299224aee3fSIngo Weinhold return B_BAD_VALUE; 1300224aee3fSIngo Weinhold if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo) 1301224aee3fSIngo Weinhold || user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK) 1302224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1303224aee3fSIngo Weinhold 1304224aee3fSIngo Weinhold status = get_next_port_info(team, &cookie, &info); 1305224aee3fSIngo Weinhold 1306224aee3fSIngo Weinhold // copy back to user space 1307224aee3fSIngo Weinhold if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK 1308224aee3fSIngo Weinhold || (status == B_OK && user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK)) 1309224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1310224aee3fSIngo Weinhold 1311224aee3fSIngo Weinhold return status; 1312224aee3fSIngo Weinhold } 1313224aee3fSIngo Weinhold 1314224aee3fSIngo Weinhold 1315224aee3fSIngo Weinhold ssize_t 1316224aee3fSIngo Weinhold _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout) 1317224aee3fSIngo Weinhold { 1318224aee3fSIngo Weinhold return port_buffer_size_etc(port, flags | B_CAN_INTERRUPT, timeout); 1319224aee3fSIngo Weinhold } 1320224aee3fSIngo Weinhold 1321224aee3fSIngo Weinhold 1322224aee3fSIngo Weinhold ssize_t 1323224aee3fSIngo Weinhold _user_port_count(port_id port) 1324224aee3fSIngo Weinhold { 1325224aee3fSIngo Weinhold return port_count(port); 1326224aee3fSIngo Weinhold } 1327224aee3fSIngo Weinhold 1328224aee3fSIngo Weinhold 1329224aee3fSIngo Weinhold status_t 1330224aee3fSIngo Weinhold _user_set_port_owner(port_id port, team_id team) 1331224aee3fSIngo Weinhold { 1332224aee3fSIngo Weinhold return set_port_owner(port, team); 1333224aee3fSIngo Weinhold } 1334224aee3fSIngo Weinhold 1335224aee3fSIngo Weinhold 1336224aee3fSIngo Weinhold ssize_t 1337224aee3fSIngo Weinhold _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer, 1338224aee3fSIngo Weinhold size_t bufferSize, uint32 flags, bigtime_t timeout) 1339224aee3fSIngo Weinhold { 1340224aee3fSIngo Weinhold int32 messageCode; 1341224aee3fSIngo Weinhold ssize_t bytesRead; 1342224aee3fSIngo Weinhold 1343224aee3fSIngo Weinhold if (userBuffer == NULL && bufferSize != 0) 1344224aee3fSIngo Weinhold return B_BAD_VALUE; 1345224aee3fSIngo Weinhold if ((userCode != NULL && !IS_USER_ADDRESS(userCode)) 1346224aee3fSIngo Weinhold || (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))) 1347224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1348224aee3fSIngo Weinhold 1349224aee3fSIngo Weinhold bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize, 1350224aee3fSIngo Weinhold flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout); 1351224aee3fSIngo Weinhold 1352224aee3fSIngo Weinhold if (bytesRead >= 0 && userCode != NULL 1353224aee3fSIngo Weinhold && user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK) 1354224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1355224aee3fSIngo Weinhold 1356224aee3fSIngo Weinhold return bytesRead; 1357224aee3fSIngo Weinhold } 1358224aee3fSIngo Weinhold 1359224aee3fSIngo Weinhold 1360224aee3fSIngo Weinhold status_t 1361224aee3fSIngo Weinhold _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer, 1362224aee3fSIngo Weinhold size_t bufferSize, uint32 flags, bigtime_t timeout) 1363224aee3fSIngo Weinhold { 1364224aee3fSIngo Weinhold iovec vec = { (void *)userBuffer, bufferSize }; 1365224aee3fSIngo Weinhold 1366224aee3fSIngo Weinhold if (userBuffer == NULL && bufferSize != 0) 1367224aee3fSIngo Weinhold return B_BAD_VALUE; 1368224aee3fSIngo Weinhold if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)) 1369224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1370224aee3fSIngo Weinhold 1371224aee3fSIngo Weinhold return writev_port_etc(port, messageCode, &vec, 1, bufferSize, 1372224aee3fSIngo Weinhold flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout); 1373224aee3fSIngo Weinhold } 1374224aee3fSIngo Weinhold 1375224aee3fSIngo Weinhold 1376224aee3fSIngo Weinhold status_t 1377224aee3fSIngo Weinhold _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs, 1378224aee3fSIngo Weinhold size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout) 1379224aee3fSIngo Weinhold { 1380224aee3fSIngo Weinhold iovec *vecs = NULL; 1381224aee3fSIngo Weinhold status_t status; 1382224aee3fSIngo Weinhold 1383224aee3fSIngo Weinhold if (userVecs == NULL && bufferSize != 0) 1384224aee3fSIngo Weinhold return B_BAD_VALUE; 1385224aee3fSIngo Weinhold if (userVecs != NULL && !IS_USER_ADDRESS(userVecs)) 1386224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1387224aee3fSIngo Weinhold 1388224aee3fSIngo Weinhold if (userVecs && vecCount != 0) { 1389224aee3fSIngo Weinhold vecs = (iovec*)malloc(sizeof(iovec) * vecCount); 1390224aee3fSIngo Weinhold if (vecs == NULL) 1391224aee3fSIngo Weinhold return B_NO_MEMORY; 1392224aee3fSIngo Weinhold 1393224aee3fSIngo Weinhold if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) { 1394224aee3fSIngo Weinhold free(vecs); 1395224aee3fSIngo Weinhold return B_BAD_ADDRESS; 1396224aee3fSIngo Weinhold } 1397224aee3fSIngo Weinhold } 1398224aee3fSIngo Weinhold status = writev_port_etc(port, messageCode, vecs, vecCount, bufferSize, 1399224aee3fSIngo Weinhold flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout); 1400224aee3fSIngo Weinhold 1401224aee3fSIngo Weinhold free(vecs); 1402224aee3fSIngo Weinhold return status; 1403224aee3fSIngo Weinhold } 1404