1 /* 2 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001, Mark-Jan Bastian. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 /*! Ports for IPC */ 10 11 #include <port.h> 12 13 #include <ctype.h> 14 #include <iovec.h> 15 #include <stdlib.h> 16 #include <string.h> 17 18 #include <OS.h> 19 20 #include <arch/int.h> 21 #include <cbuf.h> 22 #include <kernel.h> 23 #include <Notifications.h> 24 #include <sem.h> 25 #include <syscall_restart.h> 26 #include <team.h> 27 #include <util/AutoLock.h> 28 #include <util/list.h> 29 #include <wait_for_objects.h> 30 31 32 //#define TRACE_PORTS 33 #ifdef TRACE_PORTS 34 # define TRACE(x) dprintf x 35 #else 36 # define TRACE(x) 37 #endif 38 39 40 typedef struct port_msg { 41 list_link link; 42 int32 code; 43 cbuf *buffer_chain; 44 size_t size; 45 uid_t sender; 46 gid_t sender_group; 47 team_id sender_team; 48 } port_msg; 49 50 struct port_entry { 51 port_id id; 52 team_id owner; 53 int32 capacity; 54 spinlock lock; 55 const char *name; 56 sem_id read_sem; 57 sem_id write_sem; 58 int32 total_count; // messages read from port since creation 59 select_info *select_infos; 60 struct list msg_queue; 61 }; 62 63 class PortNotificationService : public DefaultNotificationService { 64 public: 65 PortNotificationService(); 66 67 void Notify(uint32 opcode, port_id team); 68 69 protected: 70 virtual status_t _ToFlags(const KMessage& eventSpecifier, 71 uint32& flags); 72 }; 73 74 #define MAX_QUEUE_LENGTH 4096 75 #define PORT_MAX_MESSAGE_SIZE (256 * 1024) 76 77 // sMaxPorts must be power of 2 78 static int32 sMaxPorts = 4096; 79 static int32 sUsedPorts = 0; 80 81 static struct port_entry *sPorts = NULL; 82 static area_id sPortArea = 0; 83 static bool sPortsActive = false; 84 static port_id sNextPort = 1; 85 static int32 sFirstFreeSlot = 1; 86 87 static PortNotificationService sNotificationService; 88 89 static spinlock sPortSpinlock = B_SPINLOCK_INITIALIZER; 90 91 #define GRAB_PORT_LIST_LOCK() acquire_spinlock(&sPortSpinlock) 92 #define RELEASE_PORT_LIST_LOCK() release_spinlock(&sPortSpinlock) 93 #define GRAB_PORT_LOCK(s) acquire_spinlock(&(s).lock) 94 #define RELEASE_PORT_LOCK(s) release_spinlock(&(s).lock) 95 96 97 // #pragma mark - TeamNotificationService 98 99 100 PortNotificationService::PortNotificationService() 101 : DefaultNotificationService("ports") 102 { 103 } 104 105 106 void 107 PortNotificationService::Notify(uint32 opcode, port_id port) 108 { 109 char eventBuffer[64]; 110 KMessage event; 111 event.SetTo(eventBuffer, sizeof(eventBuffer), PORT_MONITOR); 112 event.AddInt32("opcode", opcode); 113 event.AddInt32("port", port); 114 115 DefaultNotificationService::Notify(event, ~0U); 116 } 117 118 119 status_t 120 PortNotificationService::_ToFlags(const KMessage& eventSpecifier, uint32& flags) 121 { 122 flags = ~0U; 123 return B_OK; 124 } 125 126 127 // #pragma mark - 128 129 130 static int 131 dump_port_list(int argc, char **argv) 132 { 133 const char *name = NULL; 134 team_id owner = -1; 135 int32 i; 136 137 if (argc > 2) { 138 if (!strcmp(argv[1], "team") || !strcmp(argv[1], "owner")) 139 owner = strtoul(argv[2], NULL, 0); 140 else if (!strcmp(argv[1], "name")) 141 name = argv[2]; 142 } else if (argc > 1) 143 owner = strtoul(argv[1], NULL, 0); 144 145 kprintf("port id cap r-sem r-cnt w-sem w-cnt total team name\n"); 146 147 for (i = 0; i < sMaxPorts; i++) { 148 struct port_entry *port = &sPorts[i]; 149 if (port->id < 0 150 || (owner != -1 && port->owner != owner) 151 || (name != NULL && strstr(port->name, name) == NULL)) 152 continue; 153 154 int32 readCount, writeCount; 155 get_sem_count(port->read_sem, &readCount); 156 get_sem_count(port->write_sem, &writeCount); 157 kprintf("%p %8ld %4ld %6ld %6ld %6ld %6ld %8ld %6ld %s\n", port, 158 port->id, port->capacity, port->read_sem, readCount, 159 port->write_sem, writeCount, port->total_count, port->owner, 160 port->name); 161 } 162 return 0; 163 } 164 165 166 static void 167 _dump_port_info(struct port_entry *port) 168 { 169 int32 count; 170 171 kprintf("PORT: %p\n", port); 172 kprintf(" id: %ld\n", port->id); 173 kprintf(" name: \"%s\"\n", port->name); 174 kprintf(" owner: %ld\n", port->owner); 175 kprintf(" capacity: %ld\n", port->capacity); 176 kprintf(" read_sem: %ld\n", port->read_sem); 177 kprintf(" write_sem: %ld\n", port->write_sem); 178 get_sem_count(port->read_sem, &count); 179 kprintf(" read_sem count: %ld\n", count); 180 get_sem_count(port->write_sem, &count); 181 kprintf(" write_sem count: %ld\n", count); 182 kprintf(" total count: %ld\n", port->total_count); 183 184 set_debug_variable("_port", (addr_t)port); 185 set_debug_variable("_portID", port->id); 186 set_debug_variable("_owner", port->owner); 187 set_debug_variable("_readSem", port->read_sem); 188 set_debug_variable("_writeSem", port->write_sem); 189 } 190 191 192 static int 193 dump_port_info(int argc, char **argv) 194 { 195 const char *name = NULL; 196 sem_id sem = -1; 197 int i; 198 199 if (argc < 2) { 200 print_debugger_command_usage(argv[0]); 201 return 0; 202 } 203 204 if (argc > 2) { 205 if (!strcmp(argv[1], "address")) { 206 _dump_port_info((struct port_entry *)strtoul(argv[2], NULL, 0)); 207 return 0; 208 } else if (!strcmp(argv[1], "sem")) 209 sem = strtoul(argv[2], NULL, 0); 210 else if (!strcmp(argv[1], "name")) 211 name = argv[2]; 212 } else if (isdigit(argv[1][0])) { 213 // if the argument looks like a number, treat it as such 214 uint32 num = strtoul(argv[1], NULL, 0); 215 uint32 slot = num % sMaxPorts; 216 if (sPorts[slot].id != (int)num) { 217 kprintf("port %ld (%#lx) doesn't exist!\n", num, num); 218 return 0; 219 } 220 _dump_port_info(&sPorts[slot]); 221 return 0; 222 } else 223 name = argv[1]; 224 225 // walk through the ports list, trying to match name 226 for (i = 0; i < sMaxPorts; i++) { 227 if ((name != NULL && sPorts[i].name != NULL 228 && !strcmp(name, sPorts[i].name)) 229 || (sem != -1 && (sPorts[i].read_sem == sem 230 || sPorts[i].write_sem == sem))) { 231 _dump_port_info(&sPorts[i]); 232 return 0; 233 } 234 } 235 236 return 0; 237 } 238 239 240 static void 241 notify_port_select_events(int slot, uint16 events) 242 { 243 if (sPorts[slot].select_infos) 244 notify_select_events_list(sPorts[slot].select_infos, events); 245 } 246 247 248 static void 249 put_port_msg(port_msg *msg) 250 { 251 cbuf_free_chain(msg->buffer_chain); 252 free(msg); 253 } 254 255 256 static port_msg * 257 get_port_msg(int32 code, size_t bufferSize) 258 { 259 // ToDo: investigate preallocation of port_msgs (or use a slab allocator) 260 cbuf *bufferChain = NULL; 261 262 port_msg *msg = (port_msg *)malloc(sizeof(port_msg)); 263 if (msg == NULL) 264 return NULL; 265 266 if (bufferSize > 0) { 267 bufferChain = cbuf_get_chain(bufferSize); 268 if (bufferChain == NULL) { 269 free(msg); 270 return NULL; 271 } 272 } 273 274 msg->code = code; 275 msg->buffer_chain = bufferChain; 276 msg->size = bufferSize; 277 return msg; 278 } 279 280 281 /*! You need to own the port's lock when calling this function */ 282 static bool 283 is_port_closed(int32 slot) 284 { 285 return sPorts[slot].capacity == 0; 286 } 287 288 289 /*! Fills the port_info structure with information from the specified 290 port. 291 The port lock must be held when called. 292 */ 293 static void 294 fill_port_info(struct port_entry *port, port_info *info, size_t size) 295 { 296 int32 count; 297 298 info->port = port->id; 299 info->team = port->owner; 300 info->capacity = port->capacity; 301 302 get_sem_count(port->read_sem, &count); 303 if (count < 0) 304 count = 0; 305 306 info->queue_count = count; 307 info->total_count = port->total_count; 308 309 strlcpy(info->name, port->name, B_OS_NAME_LENGTH); 310 } 311 312 313 // #pragma mark - private kernel API 314 315 316 /*! This function cycles through the ports table, deleting all 317 the ports that are owned by the passed team_id 318 */ 319 int 320 delete_owned_ports(team_id owner) 321 { 322 // ToDo: investigate maintaining a list of ports in the team 323 // to make this simpler and more efficient. 324 cpu_status state; 325 int i; 326 int count = 0; 327 328 TRACE(("delete_owned_ports(owner = %ld)\n", owner)); 329 330 if (!sPortsActive) 331 return B_BAD_PORT_ID; 332 333 state = disable_interrupts(); 334 GRAB_PORT_LIST_LOCK(); 335 336 for (i = 0; i < sMaxPorts; i++) { 337 if (sPorts[i].id != -1 && sPorts[i].owner == owner) { 338 port_id id = sPorts[i].id; 339 340 RELEASE_PORT_LIST_LOCK(); 341 restore_interrupts(state); 342 343 delete_port(id); 344 count++; 345 346 state = disable_interrupts(); 347 GRAB_PORT_LIST_LOCK(); 348 } 349 } 350 351 RELEASE_PORT_LIST_LOCK(); 352 restore_interrupts(state); 353 354 return count; 355 } 356 357 358 int32 359 port_max_ports(void) 360 { 361 return sMaxPorts; 362 } 363 364 365 int32 366 port_used_ports(void) 367 { 368 return sUsedPorts; 369 } 370 371 372 status_t 373 port_init(kernel_args *args) 374 { 375 size_t size = sizeof(struct port_entry) * sMaxPorts; 376 int32 i; 377 378 // create and initialize ports table 379 sPortArea = create_area("port_table", (void **)&sPorts, B_ANY_KERNEL_ADDRESS, 380 size, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 381 if (sPortArea < 0) { 382 panic("unable to allocate kernel port table!\n"); 383 return sPortArea; 384 } 385 386 // ToDo: investigate preallocating a list of port_msgs to 387 // speed up actual message sending/receiving, a slab allocator 388 // might do it as well, though :-) 389 390 memset(sPorts, 0, size); 391 for (i = 0; i < sMaxPorts; i++) 392 sPorts[i].id = -1; 393 394 // add debugger commands 395 add_debugger_command_etc("ports", &dump_port_list, 396 "Dump a list of all active ports (for team, with name, etc.)", 397 "[ ([ \"team\" | \"owner\" ] <team>) | (\"name\" <name>) ]\n" 398 "Prints a list of all active ports meeting the given\n" 399 "requirement. If no argument is given, all ports are listed.\n" 400 " <team> - The team owning the ports.\n" 401 " <name> - Part of the name of the ports.\n", 0); 402 add_debugger_command_etc("port", &dump_port_info, 403 "Dump info about a particular port", 404 "([ \"address\" ] <address>) | ([ \"name\" ] <name>) " 405 "| (\"sem\" <sem>)\n" 406 "Prints info about the specified port.\n" 407 " <address> - Pointer to the port structure.\n" 408 " <name> - Name of the port.\n" 409 " <sem> - ID of the port's read or write semaphore.\n", 0); 410 411 new(&sNotificationService) PortNotificationService(); 412 sPortsActive = true; 413 return B_OK; 414 } 415 416 417 // #pragma mark - public kernel API 418 419 420 port_id 421 create_port(int32 queueLength, const char *name) 422 { 423 cpu_status state; 424 char nameBuffer[B_OS_NAME_LENGTH]; 425 sem_id readSem, writeSem; 426 status_t status; 427 team_id owner; 428 int32 slot; 429 430 TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength, 431 name)); 432 433 if (!sPortsActive) 434 return B_BAD_PORT_ID; 435 436 // check queue length 437 if (queueLength < 1 438 || queueLength > MAX_QUEUE_LENGTH) 439 return B_BAD_VALUE; 440 441 // check early on if there are any free port slots to use 442 if (atomic_add(&sUsedPorts, 1) >= sMaxPorts) { 443 status = B_NO_MORE_PORTS; 444 goto err1; 445 } 446 447 // check & dup name 448 if (name == NULL) 449 name = "unnamed port"; 450 451 // ToDo: we could save the memory and use the semaphore name only instead 452 strlcpy(nameBuffer, name, B_OS_NAME_LENGTH); 453 name = strdup(nameBuffer); 454 if (name == NULL) { 455 status = B_NO_MEMORY; 456 goto err1; 457 } 458 459 // create read sem with owner set to -1 460 // ToDo: should be B_SYSTEM_TEAM 461 readSem = create_sem_etc(0, name, -1); 462 if (readSem < B_OK) { 463 status = readSem; 464 goto err2; 465 } 466 467 // create write sem 468 writeSem = create_sem_etc(queueLength, name, -1); 469 if (writeSem < B_OK) { 470 status = writeSem; 471 goto err3; 472 } 473 474 owner = team_get_current_team_id(); 475 476 state = disable_interrupts(); 477 GRAB_PORT_LIST_LOCK(); 478 479 // find the first empty spot 480 for (slot = 0; slot < sMaxPorts; slot++) { 481 int32 i = (slot + sFirstFreeSlot) % sMaxPorts; 482 483 if (sPorts[i].id == -1) { 484 port_id id; 485 486 // make the port_id be a multiple of the slot it's in 487 if (i >= sNextPort % sMaxPorts) 488 sNextPort += i - sNextPort % sMaxPorts; 489 else 490 sNextPort += sMaxPorts - (sNextPort % sMaxPorts - i); 491 sFirstFreeSlot = slot + 1; 492 493 GRAB_PORT_LOCK(sPorts[i]); 494 sPorts[i].id = sNextPort++; 495 RELEASE_PORT_LIST_LOCK(); 496 497 sPorts[i].capacity = queueLength; 498 sPorts[i].owner = owner; 499 sPorts[i].name = name; 500 501 sPorts[i].read_sem = readSem; 502 sPorts[i].write_sem = writeSem; 503 504 list_init(&sPorts[i].msg_queue); 505 sPorts[i].total_count = 0; 506 sPorts[i].select_infos = NULL; 507 id = sPorts[i].id; 508 509 RELEASE_PORT_LOCK(sPorts[i]); 510 restore_interrupts(state); 511 512 TRACE(("create_port() done: port created %ld\n", id)); 513 514 sNotificationService.Notify(PORT_ADDED, id); 515 return id; 516 } 517 } 518 519 // not enough ports... 520 521 // TODO: due to sUsedPorts, this cannot happen anymore - as 522 // long as sMaxPorts stays constant over the kernel run 523 // time (which it should be). IOW we could simply panic() 524 // here. 525 526 RELEASE_PORT_LIST_LOCK(); 527 restore_interrupts(state); 528 529 status = B_NO_MORE_PORTS; 530 531 delete_sem(writeSem); 532 err3: 533 delete_sem(readSem); 534 err2: 535 free((char *)name); 536 err1: 537 atomic_add(&sUsedPorts, -1); 538 539 return status; 540 } 541 542 543 status_t 544 close_port(port_id id) 545 { 546 sem_id readSem, writeSem; 547 cpu_status state; 548 int32 slot; 549 550 TRACE(("close_port(id = %ld)\n", id)); 551 552 if (!sPortsActive || id < 0) 553 return B_BAD_PORT_ID; 554 555 slot = id % sMaxPorts; 556 557 // walk through the sem list, trying to match name 558 state = disable_interrupts(); 559 GRAB_PORT_LOCK(sPorts[slot]); 560 561 if (sPorts[slot].id != id) { 562 RELEASE_PORT_LOCK(sPorts[slot]); 563 restore_interrupts(state); 564 TRACE(("close_port: invalid port_id %ld\n", id)); 565 return B_BAD_PORT_ID; 566 } 567 568 // mark port to disable writing - deleting the semaphores will 569 // wake up waiting read/writes 570 sPorts[slot].capacity = 0; 571 readSem = sPorts[slot].read_sem; 572 writeSem = sPorts[slot].write_sem; 573 574 notify_port_select_events(slot, B_EVENT_INVALID); 575 sPorts[slot].select_infos = NULL; 576 577 RELEASE_PORT_LOCK(sPorts[slot]); 578 restore_interrupts(state); 579 580 delete_sem(readSem); 581 delete_sem(writeSem); 582 583 return B_NO_ERROR; 584 } 585 586 587 status_t 588 delete_port(port_id id) 589 { 590 cpu_status state; 591 sem_id readSem, writeSem; 592 const char *name; 593 struct list list; 594 port_msg *msg; 595 int32 slot; 596 597 TRACE(("delete_port(id = %ld)\n", id)); 598 599 if (!sPortsActive || id < 0) 600 return B_BAD_PORT_ID; 601 602 slot = id % sMaxPorts; 603 604 state = disable_interrupts(); 605 GRAB_PORT_LOCK(sPorts[slot]); 606 607 if (sPorts[slot].id != id) { 608 RELEASE_PORT_LOCK(sPorts[slot]); 609 restore_interrupts(state); 610 611 TRACE(("delete_port: invalid port_id %ld\n", id)); 612 return B_BAD_PORT_ID; 613 } 614 615 /* mark port as invalid */ 616 sPorts[slot].id = -1; 617 name = sPorts[slot].name; 618 readSem = sPorts[slot].read_sem; 619 writeSem = sPorts[slot].write_sem; 620 sPorts[slot].name = NULL; 621 list_move_to_list(&sPorts[slot].msg_queue, &list); 622 623 notify_port_select_events(slot, B_EVENT_INVALID); 624 sPorts[slot].select_infos = NULL; 625 626 RELEASE_PORT_LOCK(sPorts[slot]); 627 628 // update the first free slot hint in the array 629 GRAB_PORT_LIST_LOCK(); 630 if (slot < sFirstFreeSlot) 631 sFirstFreeSlot = slot; 632 RELEASE_PORT_LIST_LOCK(); 633 634 restore_interrupts(state); 635 636 atomic_add(&sUsedPorts, -1); 637 638 // free the queue 639 while ((msg = (port_msg *)list_remove_head_item(&list)) != NULL) { 640 put_port_msg(msg); 641 } 642 643 free((char *)name); 644 645 // release the threads that were blocking on this port by deleting the sem 646 // read_port() will see the B_BAD_SEM_ID acq_sem() return value, and act accordingly 647 delete_sem(readSem); 648 delete_sem(writeSem); 649 sNotificationService.Notify(PORT_REMOVED, id); 650 651 return B_OK; 652 } 653 654 655 status_t 656 select_port(int32 id, struct select_info *info, bool kernel) 657 { 658 cpu_status state; 659 int32 slot; 660 status_t error = B_OK; 661 662 if (id < 0) 663 return B_BAD_PORT_ID; 664 665 slot = id % sMaxPorts; 666 667 state = disable_interrupts(); 668 GRAB_PORT_LOCK(sPorts[slot]); 669 670 if (sPorts[slot].id != id || is_port_closed(slot)) { 671 // bad port ID 672 error = B_BAD_SEM_ID; 673 } else if (!kernel && sPorts[slot].owner == team_get_kernel_team_id()) { 674 // kernel port, but call from userland 675 error = B_NOT_ALLOWED; 676 } else { 677 info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID; 678 679 if (info->selected_events != 0) { 680 uint16 events = 0; 681 int32 writeCount = 0; 682 683 info->next = sPorts[slot].select_infos; 684 sPorts[slot].select_infos = info; 685 686 // check for events 687 if ((info->selected_events & B_EVENT_READ) != 0 688 && !list_is_empty(&sPorts[slot].msg_queue)) { 689 events |= B_EVENT_READ; 690 } 691 692 if (get_sem_count(sPorts[slot].write_sem, &writeCount) == B_OK 693 && writeCount > 0) { 694 events |= B_EVENT_WRITE; 695 } 696 697 if (events != 0) 698 notify_select_events(info, events); 699 } 700 } 701 702 RELEASE_PORT_LOCK(sPorts[slot]); 703 restore_interrupts(state); 704 705 return error; 706 } 707 708 709 status_t 710 deselect_port(int32 id, struct select_info *info, bool kernel) 711 { 712 cpu_status state; 713 int32 slot; 714 715 if (id < 0) 716 return B_BAD_PORT_ID; 717 718 if (info->selected_events == 0) 719 return B_OK; 720 721 slot = id % sMaxPorts; 722 723 state = disable_interrupts(); 724 GRAB_PORT_LOCK(sPorts[slot]); 725 726 if (sPorts[slot].id == id) { 727 select_info** infoLocation = &sPorts[slot].select_infos; 728 while (*infoLocation != NULL && *infoLocation != info) 729 infoLocation = &(*infoLocation)->next; 730 731 if (*infoLocation == info) 732 *infoLocation = info->next; 733 } 734 735 RELEASE_PORT_LOCK(sPorts[slot]); 736 restore_interrupts(state); 737 738 return B_OK; 739 } 740 741 742 port_id 743 find_port(const char *name) 744 { 745 port_id portFound = B_NAME_NOT_FOUND; 746 cpu_status state; 747 int32 i; 748 749 TRACE(("find_port(name = \"%s\")\n", name)); 750 751 if (!sPortsActive) 752 return B_NAME_NOT_FOUND; 753 if (name == NULL) 754 return B_BAD_VALUE; 755 756 // Since we have to check every single port, and we don't 757 // care if it goes away at any point, we're only grabbing 758 // the port lock in question, not the port list lock 759 760 // loop over list 761 for (i = 0; i < sMaxPorts && portFound < B_OK; i++) { 762 // lock every individual port before comparing 763 state = disable_interrupts(); 764 GRAB_PORT_LOCK(sPorts[i]); 765 766 if (sPorts[i].id >= 0 && !strcmp(name, sPorts[i].name)) 767 portFound = sPorts[i].id; 768 769 RELEASE_PORT_LOCK(sPorts[i]); 770 restore_interrupts(state); 771 } 772 773 return portFound; 774 } 775 776 777 status_t 778 _get_port_info(port_id id, port_info *info, size_t size) 779 { 780 cpu_status state; 781 int slot; 782 783 TRACE(("get_port_info(id = %ld)\n", id)); 784 785 if (info == NULL || size != sizeof(port_info)) 786 return B_BAD_VALUE; 787 if (!sPortsActive || id < 0) 788 return B_BAD_PORT_ID; 789 790 slot = id % sMaxPorts; 791 792 state = disable_interrupts(); 793 GRAB_PORT_LOCK(sPorts[slot]); 794 795 if (sPorts[slot].id != id || sPorts[slot].capacity == 0) { 796 RELEASE_PORT_LOCK(sPorts[slot]); 797 restore_interrupts(state); 798 TRACE(("get_port_info: invalid port_id %ld\n", id)); 799 return B_BAD_PORT_ID; 800 } 801 802 // fill a port_info struct with info 803 fill_port_info(&sPorts[slot], info, size); 804 805 RELEASE_PORT_LOCK(sPorts[slot]); 806 restore_interrupts(state); 807 808 return B_OK; 809 } 810 811 812 status_t 813 _get_next_port_info(team_id team, int32 *_cookie, struct port_info *info, size_t size) 814 { 815 cpu_status state; 816 int slot; 817 818 TRACE(("get_next_port_info(team = %ld)\n", team)); 819 820 if (info == NULL || size != sizeof(port_info) || _cookie == NULL || team < B_OK) 821 return B_BAD_VALUE; 822 if (!sPortsActive) 823 return B_BAD_PORT_ID; 824 825 slot = *_cookie; 826 if (slot >= sMaxPorts) 827 return B_BAD_PORT_ID; 828 829 if (team == B_CURRENT_TEAM) 830 team = team_get_current_team_id(); 831 832 info->port = -1; // used as found flag 833 834 // spinlock 835 state = disable_interrupts(); 836 GRAB_PORT_LIST_LOCK(); 837 838 while (slot < sMaxPorts) { 839 GRAB_PORT_LOCK(sPorts[slot]); 840 if (sPorts[slot].id != -1 && sPorts[slot].capacity != 0 && sPorts[slot].owner == team) { 841 // found one! 842 fill_port_info(&sPorts[slot], info, size); 843 844 RELEASE_PORT_LOCK(sPorts[slot]); 845 slot++; 846 break; 847 } 848 RELEASE_PORT_LOCK(sPorts[slot]); 849 slot++; 850 } 851 RELEASE_PORT_LIST_LOCK(); 852 restore_interrupts(state); 853 854 if (info->port == -1) 855 return B_BAD_PORT_ID; 856 857 *_cookie = slot; 858 return B_NO_ERROR; 859 } 860 861 862 ssize_t 863 port_buffer_size(port_id id) 864 { 865 return port_buffer_size_etc(id, 0, 0); 866 } 867 868 869 ssize_t 870 port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout) 871 { 872 port_message_info info; 873 status_t error = get_port_message_info_etc(id, &info, flags, timeout); 874 return error != B_OK ? error : info.size; 875 } 876 877 status_t 878 _get_port_message_info_etc(port_id id, port_message_info *info, 879 size_t infoSize, uint32 flags, bigtime_t timeout) 880 { 881 if (info == NULL || infoSize != sizeof(port_message_info)) 882 return B_BAD_VALUE; 883 884 cpu_status state; 885 sem_id cachedSem; 886 status_t status; 887 port_msg *msg; 888 int32 slot; 889 890 if (!sPortsActive || id < 0) 891 return B_BAD_PORT_ID; 892 893 slot = id % sMaxPorts; 894 895 state = disable_interrupts(); 896 GRAB_PORT_LOCK(sPorts[slot]); 897 898 if (sPorts[slot].id != id 899 || (is_port_closed(slot) && list_is_empty(&sPorts[slot].msg_queue))) { 900 RELEASE_PORT_LOCK(sPorts[slot]); 901 restore_interrupts(state); 902 TRACE(("port_buffer_size_etc(): %s port %ld\n", 903 sPorts[slot].id == id ? "closed" : "invalid", id)); 904 return B_BAD_PORT_ID; 905 } 906 907 cachedSem = sPorts[slot].read_sem; 908 909 RELEASE_PORT_LOCK(sPorts[slot]); 910 restore_interrupts(state); 911 912 // block if no message, or, if B_TIMEOUT flag set, block with timeout 913 914 status = acquire_sem_etc(cachedSem, 1, flags, timeout); 915 if (status != B_OK && status != B_BAD_SEM_ID) 916 return status; 917 918 // in case of B_BAD_SEM_ID, the port might have been closed but not yet 919 // deleted, ie. there could still be messages waiting for us 920 921 state = disable_interrupts(); 922 GRAB_PORT_LOCK(sPorts[slot]); 923 924 if (sPorts[slot].id != id) { 925 // the port is no longer there 926 RELEASE_PORT_LOCK(sPorts[slot]); 927 restore_interrupts(state); 928 return B_BAD_PORT_ID; 929 } 930 931 // determine tail & get the length of the message 932 status_t error = B_OK; 933 msg = (port_msg*)list_get_first_item(&sPorts[slot].msg_queue); 934 if (msg == NULL) { 935 if (status == B_OK) 936 panic("port %ld: no messages found\n", sPorts[slot].id); 937 938 error = B_BAD_PORT_ID; 939 } else { 940 info->size = msg->size; 941 info->sender = msg->sender; 942 info->sender_group = msg->sender_group; 943 info->sender_team = msg->sender_team; 944 } 945 946 RELEASE_PORT_LOCK(sPorts[slot]); 947 restore_interrupts(state); 948 949 // restore read_sem, as we haven't read from the port 950 release_sem(cachedSem); 951 952 // return length of item at end of queue 953 return error; 954 } 955 956 957 ssize_t 958 port_count(port_id id) 959 { 960 cpu_status state; 961 int32 count = 0; 962 int32 slot; 963 964 if (!sPortsActive || id < 0) 965 return B_BAD_PORT_ID; 966 967 slot = id % sMaxPorts; 968 969 state = disable_interrupts(); 970 GRAB_PORT_LOCK(sPorts[slot]); 971 972 if (sPorts[slot].id != id) { 973 RELEASE_PORT_LOCK(sPorts[slot]); 974 restore_interrupts(state); 975 TRACE(("port_count: invalid port_id %ld\n", id)); 976 return B_BAD_PORT_ID; 977 } 978 979 if (get_sem_count(sPorts[slot].read_sem, &count) == B_OK) { 980 // do not return negative numbers 981 if (count < 0) 982 count = 0; 983 } else { 984 // the port might have been closed - we need to actually count the messages 985 void *message = NULL; 986 while ((message = list_get_next_item(&sPorts[slot].msg_queue, message)) != NULL) { 987 count++; 988 } 989 } 990 991 RELEASE_PORT_LOCK(sPorts[slot]); 992 restore_interrupts(state); 993 994 // return count of messages 995 return count; 996 } 997 998 999 ssize_t 1000 read_port(port_id port, int32 *msgCode, void *msgBuffer, size_t bufferSize) 1001 { 1002 return read_port_etc(port, msgCode, msgBuffer, bufferSize, 0, 0); 1003 } 1004 1005 1006 ssize_t 1007 read_port_etc(port_id id, int32 *_msgCode, void *msgBuffer, size_t bufferSize, 1008 uint32 flags, bigtime_t timeout) 1009 { 1010 cpu_status state; 1011 sem_id cachedSem; 1012 status_t status; 1013 bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0; 1014 bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0; 1015 port_msg *msg; 1016 size_t size; 1017 int slot; 1018 1019 if (!sPortsActive || id < 0) 1020 return B_BAD_PORT_ID; 1021 1022 if ((msgBuffer == NULL && bufferSize > 0) 1023 || timeout < 0) 1024 return B_BAD_VALUE; 1025 1026 flags = flags & (B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT 1027 | B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT); 1028 slot = id % sMaxPorts; 1029 1030 state = disable_interrupts(); 1031 GRAB_PORT_LOCK(sPorts[slot]); 1032 1033 if (sPorts[slot].id != id 1034 || (is_port_closed(slot) && list_is_empty(&sPorts[slot].msg_queue))) { 1035 RELEASE_PORT_LOCK(sPorts[slot]); 1036 restore_interrupts(state); 1037 TRACE(("read_port_etc(): %s port %ld\n", 1038 sPorts[slot].id == id ? "closed" : "invalid", id)); 1039 return B_BAD_PORT_ID; 1040 } 1041 // store sem_id in local variable 1042 cachedSem = sPorts[slot].read_sem; 1043 1044 // unlock port && enable ints/ 1045 RELEASE_PORT_LOCK(sPorts[slot]); 1046 restore_interrupts(state); 1047 1048 status = acquire_sem_etc(cachedSem, 1, flags, timeout); 1049 // get 1 entry from the queue, block if needed 1050 1051 if (status != B_OK && status != B_BAD_SEM_ID) 1052 return status; 1053 1054 // in case of B_BAD_SEM_ID, the port might have been closed but not yet 1055 // deleted, ie. there could still be messages waiting for us 1056 1057 state = disable_interrupts(); 1058 GRAB_PORT_LOCK(sPorts[slot]); 1059 1060 // first, let's check if the port is still alive 1061 if (sPorts[slot].id == -1) { 1062 // the port has been deleted in the meantime 1063 RELEASE_PORT_LOCK(sPorts[slot]); 1064 restore_interrupts(state); 1065 return B_BAD_PORT_ID; 1066 } 1067 1068 msg = (port_msg*)list_get_first_item(&sPorts[slot].msg_queue); 1069 if (msg == NULL) { 1070 if (status == B_OK) 1071 panic("port %ld: no messages found", sPorts[slot].id); 1072 1073 // the port has obviously been closed, but no messages are left anymore 1074 RELEASE_PORT_LOCK(sPorts[slot]); 1075 restore_interrupts(state); 1076 return B_BAD_PORT_ID; 1077 } 1078 1079 if (peekOnly) { 1080 size = min_c(bufferSize, msg->size); 1081 if (_msgCode != NULL) 1082 *_msgCode = msg->code; 1083 if (size > 0) 1084 cbuf_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size); 1085 RELEASE_PORT_LOCK(sPorts[slot]); 1086 restore_interrupts(state); 1087 release_sem_etc(cachedSem, 1, B_DO_NOT_RESCHEDULE); 1088 // we only peeked, but didn't grab the message 1089 return size; 1090 } 1091 1092 list_remove_link(msg); 1093 1094 sPorts[slot].total_count++; 1095 1096 notify_port_select_events(slot, B_EVENT_WRITE); 1097 1098 cachedSem = sPorts[slot].write_sem; 1099 1100 RELEASE_PORT_LOCK(sPorts[slot]); 1101 restore_interrupts(state); 1102 1103 // check output buffer size 1104 size = min_c(bufferSize, msg->size); 1105 1106 // copy message 1107 if (_msgCode != NULL) 1108 *_msgCode = msg->code; 1109 if (size > 0) { 1110 if (userCopy) { 1111 if ((status = cbuf_user_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size) < B_OK)) { 1112 // leave the port intact, for other threads that might not crash 1113 put_port_msg(msg); 1114 release_sem(cachedSem); 1115 return status; 1116 } 1117 } else 1118 cbuf_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size); 1119 } 1120 put_port_msg(msg); 1121 1122 // make one spot in queue available again for write 1123 release_sem(cachedSem); 1124 // ToDo: we might think about setting B_NO_RESCHEDULE here 1125 // from time to time (always?) 1126 1127 return size; 1128 } 1129 1130 1131 status_t 1132 write_port(port_id id, int32 msgCode, const void *msgBuffer, size_t bufferSize) 1133 { 1134 iovec vec = { (void *)msgBuffer, bufferSize }; 1135 1136 return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0); 1137 } 1138 1139 1140 status_t 1141 write_port_etc(port_id id, int32 msgCode, const void *msgBuffer, 1142 size_t bufferSize, uint32 flags, bigtime_t timeout) 1143 { 1144 iovec vec = { (void *)msgBuffer, bufferSize }; 1145 1146 return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout); 1147 } 1148 1149 1150 status_t 1151 writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs, 1152 size_t vecCount, size_t bufferSize, uint32 flags, 1153 bigtime_t timeout) 1154 { 1155 cpu_status state; 1156 sem_id cachedSem; 1157 status_t status; 1158 port_msg *msg; 1159 bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0; 1160 int slot; 1161 1162 if (!sPortsActive || id < 0) 1163 return B_BAD_PORT_ID; 1164 1165 // mask irrelevant flags (for acquire_sem() usage) 1166 flags = flags & (B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT 1167 | B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT); 1168 slot = id % sMaxPorts; 1169 1170 if (bufferSize > PORT_MAX_MESSAGE_SIZE) 1171 return B_BAD_VALUE; 1172 1173 state = disable_interrupts(); 1174 GRAB_PORT_LOCK(sPorts[slot]); 1175 1176 if (sPorts[slot].id != id) { 1177 RELEASE_PORT_LOCK(sPorts[slot]); 1178 restore_interrupts(state); 1179 TRACE(("write_port_etc: invalid port_id %ld\n", id)); 1180 return B_BAD_PORT_ID; 1181 } 1182 1183 if (is_port_closed(slot)) { 1184 RELEASE_PORT_LOCK(sPorts[slot]); 1185 restore_interrupts(state); 1186 TRACE(("write_port_etc: port %ld closed\n", id)); 1187 return B_BAD_PORT_ID; 1188 } 1189 1190 // store sem_id in local variable 1191 cachedSem = sPorts[slot].write_sem; 1192 1193 RELEASE_PORT_LOCK(sPorts[slot]); 1194 restore_interrupts(state); 1195 1196 status = acquire_sem_etc(cachedSem, 1, flags, timeout); 1197 // get 1 entry from the queue, block if needed 1198 1199 if (status == B_BAD_SEM_ID) { 1200 // somebody deleted or closed the port 1201 return B_BAD_PORT_ID; 1202 } 1203 if (status != B_OK) 1204 return status; 1205 1206 msg = get_port_msg(msgCode, bufferSize); 1207 if (msg == NULL) 1208 return B_NO_MEMORY; 1209 1210 // sender credentials 1211 msg->sender = geteuid(); 1212 msg->sender_group = getegid(); 1213 msg->sender_team = team_get_current_team_id(); 1214 1215 if (bufferSize > 0) { 1216 uint32 i; 1217 if (userCopy) { 1218 // copy from user memory 1219 for (i = 0; i < vecCount; i++) { 1220 size_t bytes = msgVecs[i].iov_len; 1221 if (bytes > bufferSize) 1222 bytes = bufferSize; 1223 1224 if ((status = cbuf_user_memcpy_to_chain(msg->buffer_chain, 1225 0, msgVecs[i].iov_base, bytes)) < B_OK) { 1226 put_port_msg(msg); 1227 return status; 1228 } 1229 1230 bufferSize -= bytes; 1231 if (bufferSize == 0) 1232 break; 1233 } 1234 } else { 1235 // copy from kernel memory 1236 for (i = 0; i < vecCount; i++) { 1237 size_t bytes = msgVecs[i].iov_len; 1238 if (bytes > bufferSize) 1239 bytes = bufferSize; 1240 1241 if ((status = cbuf_memcpy_to_chain(msg->buffer_chain, 1242 0, msgVecs[i].iov_base, bytes)) < 0) { 1243 put_port_msg(msg); 1244 return status; 1245 } 1246 1247 bufferSize -= bytes; 1248 if (bufferSize == 0) 1249 break; 1250 } 1251 } 1252 } 1253 1254 // attach message to queue 1255 state = disable_interrupts(); 1256 GRAB_PORT_LOCK(sPorts[slot]); 1257 1258 // first, let's check if the port is still alive 1259 if (sPorts[slot].id == -1) { 1260 // the port has been deleted in the meantime 1261 RELEASE_PORT_LOCK(sPorts[slot]); 1262 restore_interrupts(state); 1263 1264 put_port_msg(msg); 1265 return B_BAD_PORT_ID; 1266 } 1267 1268 list_add_item(&sPorts[slot].msg_queue, msg); 1269 1270 notify_port_select_events(slot, B_EVENT_READ); 1271 1272 // store sem_id in local variable 1273 cachedSem = sPorts[slot].read_sem; 1274 1275 RELEASE_PORT_LOCK(sPorts[slot]); 1276 restore_interrupts(state); 1277 1278 // release sem, allowing read (might reschedule) 1279 release_sem(cachedSem); 1280 1281 return B_NO_ERROR; 1282 } 1283 1284 1285 status_t 1286 set_port_owner(port_id id, team_id team) 1287 { 1288 cpu_status state; 1289 int slot; 1290 // ToDo: Shouldn't we at least check, whether the team exists? 1291 1292 TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, team)); 1293 1294 if (!sPortsActive || id < 0) 1295 return B_BAD_PORT_ID; 1296 1297 slot = id % sMaxPorts; 1298 1299 state = disable_interrupts(); 1300 GRAB_PORT_LOCK(sPorts[slot]); 1301 1302 if (sPorts[slot].id != id) { 1303 RELEASE_PORT_LOCK(sPorts[slot]); 1304 restore_interrupts(state); 1305 TRACE(("set_port_owner: invalid port_id %ld\n", id)); 1306 return B_BAD_PORT_ID; 1307 } 1308 1309 // transfer ownership to other team 1310 sPorts[slot].owner = team; 1311 1312 // unlock port 1313 RELEASE_PORT_LOCK(sPorts[slot]); 1314 restore_interrupts(state); 1315 1316 return B_NO_ERROR; 1317 } 1318 1319 1320 // #pragma mark - syscalls 1321 1322 1323 port_id 1324 _user_create_port(int32 queueLength, const char *userName) 1325 { 1326 char name[B_OS_NAME_LENGTH]; 1327 1328 if (userName == NULL) 1329 return create_port(queueLength, NULL); 1330 1331 if (!IS_USER_ADDRESS(userName) 1332 || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) 1333 return B_BAD_ADDRESS; 1334 1335 return create_port(queueLength, name); 1336 } 1337 1338 1339 status_t 1340 _user_close_port(port_id id) 1341 { 1342 return close_port(id); 1343 } 1344 1345 1346 status_t 1347 _user_delete_port(port_id id) 1348 { 1349 return delete_port(id); 1350 } 1351 1352 1353 port_id 1354 _user_find_port(const char *userName) 1355 { 1356 char name[B_OS_NAME_LENGTH]; 1357 1358 if (userName == NULL) 1359 return B_BAD_VALUE; 1360 if (!IS_USER_ADDRESS(userName) 1361 || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) 1362 return B_BAD_ADDRESS; 1363 1364 return find_port(name); 1365 } 1366 1367 1368 status_t 1369 _user_get_port_info(port_id id, struct port_info *userInfo) 1370 { 1371 struct port_info info; 1372 status_t status; 1373 1374 if (userInfo == NULL) 1375 return B_BAD_VALUE; 1376 if (!IS_USER_ADDRESS(userInfo)) 1377 return B_BAD_ADDRESS; 1378 1379 status = get_port_info(id, &info); 1380 1381 // copy back to user space 1382 if (status == B_OK 1383 && user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK) 1384 return B_BAD_ADDRESS; 1385 1386 return status; 1387 } 1388 1389 1390 status_t 1391 _user_get_next_port_info(team_id team, int32 *userCookie, 1392 struct port_info *userInfo) 1393 { 1394 struct port_info info; 1395 status_t status; 1396 int32 cookie; 1397 1398 if (userCookie == NULL || userInfo == NULL) 1399 return B_BAD_VALUE; 1400 if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo) 1401 || user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK) 1402 return B_BAD_ADDRESS; 1403 1404 status = get_next_port_info(team, &cookie, &info); 1405 1406 // copy back to user space 1407 if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK 1408 || (status == B_OK && user_memcpy(userInfo, &info, 1409 sizeof(struct port_info)) < B_OK)) 1410 return B_BAD_ADDRESS; 1411 1412 return status; 1413 } 1414 1415 1416 ssize_t 1417 _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout) 1418 { 1419 syscall_restart_handle_timeout_pre(flags, timeout); 1420 1421 status_t status = port_buffer_size_etc(port, flags | B_CAN_INTERRUPT, 1422 timeout); 1423 1424 return syscall_restart_handle_timeout_post(status, timeout); 1425 } 1426 1427 1428 ssize_t 1429 _user_port_count(port_id port) 1430 { 1431 return port_count(port); 1432 } 1433 1434 1435 status_t 1436 _user_set_port_owner(port_id port, team_id team) 1437 { 1438 return set_port_owner(port, team); 1439 } 1440 1441 1442 ssize_t 1443 _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer, 1444 size_t bufferSize, uint32 flags, bigtime_t timeout) 1445 { 1446 int32 messageCode; 1447 ssize_t bytesRead; 1448 1449 syscall_restart_handle_timeout_pre(flags, timeout); 1450 1451 if (userBuffer == NULL && bufferSize != 0) 1452 return B_BAD_VALUE; 1453 if ((userCode != NULL && !IS_USER_ADDRESS(userCode)) 1454 || (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))) 1455 return B_BAD_ADDRESS; 1456 1457 bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize, 1458 flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout); 1459 1460 if (bytesRead >= 0 && userCode != NULL 1461 && user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK) 1462 return B_BAD_ADDRESS; 1463 1464 return syscall_restart_handle_timeout_post(bytesRead, timeout); 1465 } 1466 1467 1468 status_t 1469 _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer, 1470 size_t bufferSize, uint32 flags, bigtime_t timeout) 1471 { 1472 iovec vec = { (void *)userBuffer, bufferSize }; 1473 1474 syscall_restart_handle_timeout_pre(flags, timeout); 1475 1476 if (userBuffer == NULL && bufferSize != 0) 1477 return B_BAD_VALUE; 1478 if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)) 1479 return B_BAD_ADDRESS; 1480 1481 status_t status = writev_port_etc(port, messageCode, &vec, 1, bufferSize, 1482 flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout); 1483 1484 return syscall_restart_handle_timeout_post(status, timeout); 1485 } 1486 1487 1488 status_t 1489 _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs, 1490 size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout) 1491 { 1492 syscall_restart_handle_timeout_pre(flags, timeout); 1493 1494 if (userVecs == NULL && bufferSize != 0) 1495 return B_BAD_VALUE; 1496 if (userVecs != NULL && !IS_USER_ADDRESS(userVecs)) 1497 return B_BAD_ADDRESS; 1498 1499 iovec *vecs = NULL; 1500 if (userVecs && vecCount != 0) { 1501 vecs = (iovec*)malloc(sizeof(iovec) * vecCount); 1502 if (vecs == NULL) 1503 return B_NO_MEMORY; 1504 1505 if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) { 1506 free(vecs); 1507 return B_BAD_ADDRESS; 1508 } 1509 } 1510 1511 status_t status = writev_port_etc(port, messageCode, vecs, vecCount, 1512 bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, 1513 timeout); 1514 1515 free(vecs); 1516 return syscall_restart_handle_timeout_post(status, timeout); 1517 } 1518 1519 1520 status_t 1521 _user_get_port_message_info_etc(port_id port, port_message_info *userInfo, 1522 size_t infoSize, uint32 flags, bigtime_t timeout) 1523 { 1524 if (userInfo == NULL || infoSize != sizeof(port_message_info)) 1525 return B_BAD_VALUE; 1526 1527 syscall_restart_handle_timeout_pre(flags, timeout); 1528 1529 port_message_info info; 1530 status_t error = _get_port_message_info_etc(port, &info, sizeof(info), 1531 flags | B_CAN_INTERRUPT, timeout); 1532 1533 // copy info to userland 1534 if (error == B_OK && (!IS_USER_ADDRESS(userInfo) 1535 || user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) { 1536 error = B_BAD_ADDRESS; 1537 } 1538 1539 return syscall_restart_handle_timeout_post(error, timeout); 1540 } 1541