1/* 2 * Copyright 2007-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2002-2008, Axel D��rfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7#include <fs/select_sync_pool.h> 8#include <wait_for_objects.h> 9 10#include <new> 11 12#include <poll.h> 13#include <signal.h> 14#include <stdlib.h> 15#include <string.h> 16#include <sys/select.h> 17 18#include <OS.h> 19#include <Select.h> 20 21#include <AutoDeleter.h> 22 23#include <fs/fd.h> 24#include <port.h> 25#include <sem.h> 26#include <syscalls.h> 27#include <syscall_restart.h> 28#include <thread.h> 29#include <tracing.h> 30#include <util/AutoLock.h> 31#include <util/DoublyLinkedList.h> 32#include <vfs.h> 33 34 35//#define TRACE_WAIT_FOR_OBJECTS 36#ifdef TRACE_WAIT_FOR_OBJECTS 37# define PRINT(x) dprintf x 38# define FUNCTION(x) dprintf x 39#else 40# define PRINT(x) ; 41# define FUNCTION(x) ; 42#endif 43 44 45using std::nothrow; 46 47 48struct select_sync_pool_entry 49 : DoublyLinkedListLinkImpl<select_sync_pool_entry> { 50 selectsync *sync; 51 uint16 events; 52}; 53 54typedef DoublyLinkedList<select_sync_pool_entry> SelectSyncPoolEntryList; 55 56struct select_sync_pool { 57 SelectSyncPoolEntryList entries; 58}; 59 60 61struct select_ops { 62 status_t (*select)(int32 object, struct select_info* info, bool kernel); 63 status_t (*deselect)(int32 object, struct select_info* info, bool kernel); 64}; 65 66 67static const select_ops kSelectOps[] = { 68 // B_OBJECT_TYPE_FD 69 { 70 select_fd, 71 deselect_fd 72 }, 73 74 // B_OBJECT_TYPE_SEMAPHORE 75 { 76 select_sem, 77 deselect_sem 78 }, 79 80 // B_OBJECT_TYPE_PORT 81 { 82 select_port, 83 deselect_port 84 }, 85 86 // B_OBJECT_TYPE_THREAD 87 { 88 select_thread, 89 deselect_thread 90 } 91}; 92 93static const uint32 kSelectOpsCount = sizeof(kSelectOps) / sizeof(select_ops); 94 95 96 97#if WAIT_FOR_OBJECTS_TRACING 98 99 100namespace WaitForObjectsTracing { 101 102 103class SelectTraceEntry : public AbstractTraceEntry { 104 protected: 105 SelectTraceEntry(int count, fd_set* readSet, fd_set* writeSet, 106 fd_set* errorSet) 107 : 108 fReadSet(NULL), 109 fWriteSet(NULL), 110 fErrorSet(NULL), 111 fCount(count) 112 { 113 int sets = (readSet != NULL ? 1 : 0) + (writeSet != NULL ? 1 : 0) 114 + (errorSet != NULL ? 1 : 0); 115 if (sets > 0 && count > 0) { 116 uint32 bytes = _howmany(count, NFDBITS) * sizeof(fd_mask); 117 uint8* allocated = (uint8*)alloc_tracing_buffer(bytes * sets); 118 if (allocated != NULL) { 119 if (readSet != NULL) { 120 fReadSet = (fd_set*)allocated; 121 memcpy(fReadSet, readSet, bytes); 122 allocated += bytes; 123 } 124 if (writeSet != NULL) { 125 fWriteSet = (fd_set*)allocated; 126 memcpy(fWriteSet, writeSet, bytes); 127 allocated += bytes; 128 } 129 if (errorSet != NULL) { 130 fErrorSet = (fd_set*)allocated; 131 memcpy(fErrorSet, errorSet, bytes); 132 } 133 } 134 } 135 } 136 137 void AddDump(TraceOutput& out, const char* name) 138 { 139 out.Print(name); 140 141 _PrintSet(out, "read", fReadSet); 142 _PrintSet(out, ", write", fWriteSet); 143 _PrintSet(out, ", error", fErrorSet); 144 } 145 146 private: 147 void _PrintSet(TraceOutput& out, const char* name, fd_set* set) 148 { 149 150 out.Print("%s: <", name); 151 152 if (set != NULL) { 153 bool first = true; 154 for (int i = 0; i < fCount; i++) { 155 if (!FD_ISSET(i, set)) 156 continue; 157 158 if (first) { 159 out.Print("%d", i); 160 first = false; 161 } else 162 out.Print(", %d", i); 163 } 164 } 165 166 out.Print(">"); 167 } 168 169 protected: 170 fd_set* fReadSet; 171 fd_set* fWriteSet; 172 fd_set* fErrorSet; 173 int fCount; 174}; 175 176 177class SelectBegin : public SelectTraceEntry { 178 public: 179 SelectBegin(int count, fd_set* readSet, fd_set* writeSet, 180 fd_set* errorSet, bigtime_t timeout) 181 : 182 SelectTraceEntry(count, readSet, writeSet, errorSet), 183 fTimeout(timeout) 184 { 185 Initialized(); 186 } 187 188 virtual void AddDump(TraceOutput& out) 189 { 190 SelectTraceEntry::AddDump(out, "select begin: "); 191 out.Print(", timeout: %lld", fTimeout); 192 } 193 194 private: 195 bigtime_t fTimeout; 196}; 197 198 199class SelectDone : public SelectTraceEntry { 200 public: 201 SelectDone(int count, fd_set* readSet, fd_set* writeSet, 202 fd_set* errorSet, status_t status) 203 : 204 SelectTraceEntry(status == B_OK ? count : 0, readSet, writeSet, 205 errorSet), 206 fStatus(status) 207 { 208 Initialized(); 209 } 210 211 virtual void AddDump(TraceOutput& out) 212 { 213 if (fStatus == B_OK) 214 SelectTraceEntry::AddDump(out, "select done: "); 215 else 216 out.Print("select done: error: 0x%lx", fStatus); 217 } 218 219 private: 220 status_t fStatus; 221}; 222 223 224class PollTraceEntry : public AbstractTraceEntry { 225 protected: 226 PollTraceEntry(pollfd* fds, int count, bool resultEvents) 227 : 228 fEntries(NULL), 229 fCount(0) 230 { 231 if (fds != NULL && count > 0) { 232 for (int i = 0; i < count; i++) { 233 if (resultEvents ? fds[i].revents : fds[i].events) 234 fCount++; 235 } 236 } 237 238 if (fCount == 0) 239 return; 240 241 fEntries = (FDEntry*)alloc_tracing_buffer(fCount * sizeof(FDEntry)); 242 if (fEntries != NULL) { 243 for (int i = 0; i < fCount; fds++) { 244 uint16 events = resultEvents ? fds->revents : fds->events; 245 if (events != 0) { 246 fEntries[i].fd = fds->fd; 247 fEntries[i].events = events; 248 i++; 249 } 250 } 251 } 252 } 253 254 void AddDump(TraceOutput& out) 255 { 256 if (fEntries == NULL) 257 return; 258 259 static const struct { 260 const char* name; 261 uint16 event; 262 } kEventNames[] = { 263 { "r", POLLIN }, 264 { "w", POLLOUT }, 265 { "rb", POLLRDBAND }, 266 { "wb", POLLWRBAND }, 267 { "rp", POLLPRI }, 268 { "err", POLLERR }, 269 { "hup", POLLHUP }, 270 { "inv", POLLNVAL }, 271 { NULL, 0 } 272 }; 273 274 bool firstFD = true; 275 for (int i = 0; i < fCount; i++) { 276 if (firstFD) { 277 out.Print("<%u: ", fEntries[i].fd); 278 firstFD = false; 279 } else 280 out.Print(", <%u: ", fEntries[i].fd); 281 282 bool firstEvent = true; 283 for (int k = 0; kEventNames[k].name != NULL; k++) { 284 if ((fEntries[i].events & kEventNames[k].event) != 0) { 285 if (firstEvent) { 286 out.Print("%s", kEventNames[k].name); 287 firstEvent = false; 288 } else 289 out.Print(", %s", kEventNames[k].name); 290 } 291 } 292 293 out.Print(">"); 294 } 295 } 296 297 protected: 298 struct FDEntry { 299 uint16 fd; 300 uint16 events; 301 }; 302 303 FDEntry* fEntries; 304 int fCount; 305}; 306 307 308class PollBegin : public PollTraceEntry { 309 public: 310 PollBegin(pollfd* fds, int count, bigtime_t timeout) 311 : 312 PollTraceEntry(fds, count, false), 313 fTimeout(timeout) 314 { 315 Initialized(); 316 } 317 318 virtual void AddDump(TraceOutput& out) 319 { 320 out.Print("poll begin: "); 321 PollTraceEntry::AddDump(out); 322 out.Print(", timeout: %lld", fTimeout); 323 } 324 325 private: 326 bigtime_t fTimeout; 327}; 328 329 330class PollDone : public PollTraceEntry { 331 public: 332 PollDone(pollfd* fds, int count, int result) 333 : 334 PollTraceEntry(fds, result >= 0 ? count : 0, true), 335 fResult(result) 336 { 337 Initialized(); 338 } 339 340 virtual void AddDump(TraceOutput& out) 341 { 342 if (fResult >= 0) { 343 out.Print("poll done: count: %d: ", fResult); 344 PollTraceEntry::AddDump(out); 345 } else 346 out.Print("poll done: error: 0x%x", fResult); 347 } 348 349 private: 350 int fResult; 351}; 352 353} // namespace WaitForObjectsTracing 354 355# define T(x) new(std::nothrow) WaitForObjectsTracing::x 356 357#else 358# define T(x) 359#endif // WAIT_FOR_OBJECTS_TRACING 360 361 362// #pragma mark - 363 364 365/*! 366 Clears all bits in the fd_set - since we are using variable sized 367 arrays in the kernel, we can't use the FD_ZERO() macro provided by 368 sys/select.h for this task. 369 All other FD_xxx() macros are safe to use, though. 370*/ 371static inline void 372fd_zero(fd_set *set, int numFDs) 373{ 374 if (set != NULL) 375 memset(set, 0, _howmany(numFDs, NFDBITS) * sizeof(fd_mask)); 376} 377 378 379static status_t 380create_select_sync(int numFDs, select_sync*& _sync) 381{ 382 // create sync structure 383 select_sync* sync = new(nothrow) select_sync; 384 if (sync == NULL) 385 return B_NO_MEMORY; 386 ObjectDeleter<select_sync> syncDeleter(sync); 387 388 // create info set 389 sync->set = new(nothrow) select_info[numFDs]; 390 if (sync->set == NULL) 391 return B_NO_MEMORY; 392 ArrayDeleter<select_info> setDeleter(sync->set); 393 394 // create select event semaphore 395 sync->sem = create_sem(0, "select"); 396 if (sync->sem < 0) 397 return sync->sem; 398 399 sync->count = numFDs; 400 sync->ref_count = 1; 401 402 for (int i = 0; i < numFDs; i++) { 403 sync->set[i].next = NULL; 404 sync->set[i].sync = sync; 405 } 406 407 setDeleter.Detach(); 408 syncDeleter.Detach(); 409 _sync = sync; 410 411 return B_OK; 412} 413 414 415void 416put_select_sync(select_sync* sync) 417{ 418 FUNCTION(("put_select_sync(%p): -> %ld\n", sync, sync->ref_count - 1)); 419 420 if (atomic_add(&sync->ref_count, -1) == 1) { 421 delete_sem(sync->sem); 422 delete[] sync->set; 423 delete sync; 424 } 425} 426 427 428static int 429common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet, 430 bigtime_t timeout, const sigset_t *sigMask, bool kernel) 431{ 432 status_t status = B_OK; 433 int fd; 434 435 FUNCTION(("[%ld] common_select(%d, %p, %p, %p, %lld, %p, %d)\n", 436 find_thread(NULL), numFDs, readSet, writeSet, errorSet, timeout, 437 sigMask, kernel)); 438 439 // check if fds are valid before doing anything 440 441 for (fd = 0; fd < numFDs; fd++) { 442 if (((readSet && FD_ISSET(fd, readSet)) 443 || (writeSet && FD_ISSET(fd, writeSet)) 444 || (errorSet && FD_ISSET(fd, errorSet))) 445 && !fd_is_valid(fd, kernel)) 446 return B_FILE_ERROR; 447 } 448 449 // allocate sync object 450 select_sync* sync; 451 status = create_select_sync(numFDs, sync); 452 if (status != B_OK) 453 return status; 454 455 T(SelectBegin(numFDs, readSet, writeSet, errorSet, timeout)); 456 457 // start selecting file descriptors 458 459 for (fd = 0; fd < numFDs; fd++) { 460 sync->set[fd].selected_events = 0; 461 sync->set[fd].events = 0; 462 463 if (readSet && FD_ISSET(fd, readSet)) 464 sync->set[fd].selected_events = SELECT_FLAG(B_SELECT_READ); 465 if (writeSet && FD_ISSET(fd, writeSet)) 466 sync->set[fd].selected_events |= SELECT_FLAG(B_SELECT_WRITE); 467 if (errorSet && FD_ISSET(fd, errorSet)) 468 sync->set[fd].selected_events |= SELECT_FLAG(B_SELECT_ERROR); 469 470 if (sync->set[fd].selected_events != 0) { 471 select_fd(fd, sync->set + fd, kernel); 472 // array position is the same as the fd for select() 473 } 474 } 475 476 // set new signal mask 477 sigset_t oldSigMask; 478 if (sigMask != NULL) 479 sigprocmask(SIG_SETMASK, sigMask, &oldSigMask); 480 481 // wait for something to happen 482 status = acquire_sem_etc(sync->sem, 1, 483 B_CAN_INTERRUPT | (timeout >= 0 ? B_ABSOLUTE_TIMEOUT : 0), timeout); 484 485 // restore the old signal mask 486 if (sigMask != NULL) 487 sigprocmask(SIG_SETMASK, &oldSigMask, NULL); 488 489 PRINT(("common_select(): acquire_sem_etc() returned: %lx\n", status)); 490 491 // deselect file descriptors 492 493 for (fd = 0; fd < numFDs; fd++) 494 deselect_fd(fd, sync->set + fd, kernel); 495 496 PRINT(("common_select(): events deselected\n")); 497 498 // collect the events that have happened in the meantime 499 500 int count = 0; 501 502 if (status == B_INTERRUPTED) { 503 // We must not clear the sets in this case, as applications may 504 // rely on the contents of them. 505 put_select_sync(sync); 506 T(SelectDone(numFDs, readSet, writeSet, errorSet, status)); 507 return B_INTERRUPTED; 508 } 509 510 // Clear sets to store the received events 511 // (we can't use the macros, because we have variable sized arrays; 512 // the other FD_xxx() macros are safe, though). 513 fd_zero(readSet, numFDs); 514 fd_zero(writeSet, numFDs); 515 fd_zero(errorSet, numFDs); 516 517 if (status == B_OK) { 518 for (count = 0, fd = 0;fd < numFDs; fd++) { 519 if (readSet && sync->set[fd].events & SELECT_FLAG(B_SELECT_READ)) { 520 FD_SET(fd, readSet); 521 count++; 522 } 523 if (writeSet 524 && sync->set[fd].events & SELECT_FLAG(B_SELECT_WRITE)) { 525 FD_SET(fd, writeSet); 526 count++; 527 } 528 if (errorSet 529 && sync->set[fd].events & SELECT_FLAG(B_SELECT_ERROR)) { 530 FD_SET(fd, errorSet); 531 count++; 532 } 533 } 534 } 535 536 // B_TIMED_OUT and B_WOULD_BLOCK are supposed to return 0 537 538 put_select_sync(sync); 539 540 T(SelectDone(numFDs, readSet, writeSet, errorSet, status)); 541 542 return count; 543} 544 545 546static int 547common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout, bool kernel) 548{ 549 // allocate sync object 550 select_sync* sync; 551 status_t status = create_select_sync(numFDs, sync); 552 if (status != B_OK) 553 return status; 554 555 T(PollBegin(fds, numFDs, timeout)); 556 557 // start polling file descriptors (by selecting them) 558 559 bool invalid = false; 560 for (uint32 i = 0; i < numFDs; i++) { 561 int fd = fds[i].fd; 562 563 // initialize events masks 564 sync->set[i].selected_events = fds[i].events 565 | POLLNVAL | POLLERR | POLLHUP; 566 sync->set[i].events = 0; 567 fds[i].revents = 0; 568 569 if (fd >= 0 && select_fd(fd, sync->set + i, kernel) != B_OK) { 570 sync->set[i].events = POLLNVAL; 571 fds[i].revents = POLLNVAL; 572 // indicates that the FD doesn't need to be deselected 573 invalid = true; 574 } 575 } 576 577 if (!invalid) { 578 status = acquire_sem_etc(sync->sem, 1, 579 B_CAN_INTERRUPT | (timeout >= 0 ? B_ABSOLUTE_TIMEOUT : 0), timeout); 580 } 581 582 // deselect file descriptors 583 584 for (uint32 i = 0; i < numFDs; i++) { 585 if (fds[i].fd >= 0 && (fds[i].revents & POLLNVAL) == 0) 586 deselect_fd(fds[i].fd, sync->set + i, kernel); 587 } 588 589 // collect the events that have happened in the meantime 590 591 int count = 0; 592 switch (status) { 593 case B_OK: 594 for (uint32 i = 0; i < numFDs; i++) { 595 if (fds[i].fd < 0) 596 continue; 597 598 // POLLxxx flags and B_SELECT_xxx flags are compatible 599 fds[i].revents = sync->set[i].events 600 & sync->set[i].selected_events; 601 if (fds[i].revents != 0) 602 count++; 603 } 604 break; 605 case B_INTERRUPTED: 606 count = B_INTERRUPTED; 607 break; 608 default: 609 // B_TIMED_OUT, and B_WOULD_BLOCK 610 break; 611 } 612 613 put_select_sync(sync); 614 615 T(PollDone(fds, numFDs, count)); 616 617 return count; 618} 619 620 621static ssize_t 622common_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags, 623 bigtime_t timeout, bool kernel) 624{ 625 status_t status = B_OK; 626 627 // allocate sync object 628 select_sync* sync; 629 status = create_select_sync(numInfos, sync); 630 if (status != B_OK) 631 return status; 632 633 // start selecting objects 634 635 bool invalid = false; 636 for (int i = 0; i < numInfos; i++) { 637 uint16 type = infos[i].type; 638 int32 object = infos[i].object; 639 640 // initialize events masks 641 sync->set[i].selected_events = infos[i].events 642 | B_EVENT_INVALID | B_EVENT_ERROR | B_EVENT_DISCONNECTED; 643 sync->set[i].events = 0; 644 infos[i].events = 0; 645 646 if (type >= kSelectOpsCount 647 || kSelectOps[type].select(object, sync->set + i, kernel) != B_OK) { 648 sync->set[i].events = B_EVENT_INVALID; 649 infos[i].events = B_EVENT_INVALID; 650 // indicates that the object doesn't need to be deselected 651 invalid = true; 652 } 653 } 654 655 if (!invalid) { 656 status = acquire_sem_etc(sync->sem, 1, B_CAN_INTERRUPT | flags, 657 timeout); 658 } 659 660 // deselect objects 661 662 for (int i = 0; i < numInfos; i++) { 663 uint16 type = infos[i].type; 664 665 if (type < kSelectOpsCount && (infos[i].events & B_EVENT_INVALID) == 0) 666 kSelectOps[type].deselect(infos[i].object, sync->set + i, kernel); 667 } 668 669 // collect the events that have happened in the meantime 670 671 ssize_t count = 0; 672 if (status == B_OK) { 673 for (int i = 0; i < numInfos; i++) { 674 infos[i].events = sync->set[i].events 675 & sync->set[i].selected_events; 676 if (infos[i].events != 0) 677 count++; 678 } 679 } else { 680 // B_INTERRUPTED, B_TIMED_OUT, and B_WOULD_BLOCK 681 count = status; 682 } 683 684 put_select_sync(sync); 685 686 return count; 687} 688 689 690// #pragma mark - kernel private 691 692 693status_t 694notify_select_events(select_info* info, uint16 events) 695{ 696 FUNCTION(("notify_select_events(%p (%p), 0x%x)\n", info, info->sync, 697 events)); 698 699 if (info == NULL 700 || info->sync == NULL 701 || info->sync->sem < B_OK) 702 return B_BAD_VALUE; 703 704 atomic_or(&info->events, events); 705 706 // only wake up the waiting select()/poll() call if the events 707 // match one of the selected ones 708 if (info->selected_events & events) 709 return release_sem_etc(info->sync->sem, 1, B_DO_NOT_RESCHEDULE); 710 711 return B_OK; 712} 713 714 715void 716notify_select_events_list(select_info* list, uint16 events) 717{ 718 struct select_info* info = list; 719 while (info != NULL) { 720 notify_select_events(info, events); 721 info = info->next; 722 } 723} 724 725 726// #pragma mark - public kernel API 727 728 729status_t 730notify_select_event(struct selectsync *sync, uint8 event) 731{ 732 return notify_select_events((select_info*)sync, SELECT_FLAG(event)); 733} 734 735 736// #pragma mark - private kernel exported API 737 738 739static select_sync_pool_entry * 740find_select_sync_pool_entry(select_sync_pool *pool, selectsync *sync) 741{ 742 for (SelectSyncPoolEntryList::Iterator it = pool->entries.GetIterator(); 743 it.HasNext();) { 744 select_sync_pool_entry *entry = it.Next(); 745 if (entry->sync == sync) 746 return entry; 747 } 748 749 return NULL; 750} 751 752 753static status_t 754add_select_sync_pool_entry(select_sync_pool *pool, selectsync *sync, 755 uint8 event) 756{ 757 // check, whether the entry does already exist 758 select_sync_pool_entry *entry = find_select_sync_pool_entry(pool, sync); 759 if (!entry) { 760 entry = new (std::nothrow) select_sync_pool_entry; 761 if (!entry) 762 return B_NO_MEMORY; 763 764 entry->sync = sync; 765 entry->events = 0; 766 767 pool->entries.Add(entry); 768 } 769 770 entry->events |= SELECT_FLAG(event); 771 772 return B_OK; 773} 774 775 776status_t 777add_select_sync_pool_entry(select_sync_pool **_pool, selectsync *sync, 778 uint8 event) 779{ 780 // create the pool, if necessary 781 select_sync_pool *pool = *_pool; 782 if (!pool) { 783 pool = new (std::nothrow) select_sync_pool; 784 if (!pool) 785 return B_NO_MEMORY; 786 787 *_pool = pool; 788 } 789 790 // add the entry 791 status_t error = add_select_sync_pool_entry(pool, sync, event); 792 793 // cleanup 794 if (pool->entries.IsEmpty()) { 795 delete pool; 796 *_pool = NULL; 797 } 798 799 return error; 800} 801 802 803status_t 804remove_select_sync_pool_entry(select_sync_pool **_pool, selectsync *sync, 805 uint8 event) 806{ 807 select_sync_pool *pool = *_pool; 808 if (!pool) 809 return B_ENTRY_NOT_FOUND; 810 811 // clear the event flag of the concerned entries 812 bool found = false; 813 for (SelectSyncPoolEntryList::Iterator it = pool->entries.GetIterator(); 814 it.HasNext();) { 815 select_sync_pool_entry *entry = it.Next(); 816 if (entry->sync == sync) { 817 found = true; 818 entry->events &= ~SELECT_FLAG(event); 819 820 // remove the entry, if no longer needed 821 if (entry->events == 0) { 822 it.Remove(); 823 delete entry; 824 } 825 } 826 } 827 828 if (!found) 829 return B_ENTRY_NOT_FOUND; 830 831 // delete the pool, if no longer needed 832 if (pool->entries.IsEmpty()) { 833 delete pool; 834 *_pool = NULL; 835 } 836 837 return B_OK; 838} 839 840 841void 842delete_select_sync_pool(select_sync_pool *pool) 843{ 844 if (!pool) 845 return; 846 847 while (select_sync_pool_entry *entry = pool->entries.Head()) { 848 pool->entries.Remove(entry); 849 delete entry; 850 } 851 852 delete pool; 853} 854 855 856void 857notify_select_event_pool(select_sync_pool *pool, uint8 event) 858{ 859 if (!pool) 860 return; 861 862 FUNCTION(("notify_select_event_pool(%p, %u)\n", pool, event)); 863 864 for (SelectSyncPoolEntryList::Iterator it = pool->entries.GetIterator(); 865 it.HasNext();) { 866 select_sync_pool_entry *entry = it.Next(); 867 if (entry->events & SELECT_FLAG(event)) 868 notify_select_event(entry->sync, event); 869 } 870} 871 872 873// #pragma mark - Kernel POSIX layer 874 875 876ssize_t 877_kern_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet, 878 bigtime_t timeout, const sigset_t *sigMask) 879{ 880 if (timeout >= 0) 881 timeout += system_time(); 882 883 return common_select(numFDs, readSet, writeSet, errorSet, timeout, 884 sigMask, true); 885} 886 887 888ssize_t 889_kern_poll(struct pollfd *fds, int numFDs, bigtime_t timeout) 890{ 891 if (timeout >= 0) 892 timeout += system_time(); 893 894 return common_poll(fds, numFDs, timeout, true); 895} 896 897 898ssize_t 899_kern_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags, 900 bigtime_t timeout) 901{ 902 return common_wait_for_objects(infos, numInfos, flags, timeout, true); 903} 904 905 906// #pragma mark - User syscalls 907 908 909ssize_t 910_user_select(int numFDs, fd_set *userReadSet, fd_set *userWriteSet, 911 fd_set *userErrorSet, bigtime_t timeout, const sigset_t *userSigMask) 912{ 913 fd_set *readSet = NULL, *writeSet = NULL, *errorSet = NULL; 914 uint32 bytes = _howmany(numFDs, NFDBITS) * sizeof(fd_mask); 915 sigset_t sigMask; 916 int result; 917 918 syscall_restart_handle_timeout_pre(timeout); 919 920 if (numFDs < 0) 921 return B_BAD_VALUE; 922 923 if ((userReadSet != NULL && !IS_USER_ADDRESS(userReadSet)) 924 || (userWriteSet != NULL && !IS_USER_ADDRESS(userWriteSet)) 925 || (userErrorSet != NULL && !IS_USER_ADDRESS(userErrorSet)) 926 || (userSigMask != NULL && !IS_USER_ADDRESS(userSigMask))) 927 return B_BAD_ADDRESS; 928 929 // copy parameters 930 931 if (userReadSet != NULL) { 932 readSet = (fd_set *)malloc(bytes); 933 if (readSet == NULL) 934 return B_NO_MEMORY; 935 936 if (user_memcpy(readSet, userReadSet, bytes) < B_OK) { 937 result = B_BAD_ADDRESS; 938 goto err; 939 } 940 } 941 942 if (userWriteSet != NULL) { 943 writeSet = (fd_set *)malloc(bytes); 944 if (writeSet == NULL) { 945 result = B_NO_MEMORY; 946 goto err; 947 } 948 if (user_memcpy(writeSet, userWriteSet, bytes) < B_OK) { 949 result = B_BAD_ADDRESS; 950 goto err; 951 } 952 } 953 954 if (userErrorSet != NULL) { 955 errorSet = (fd_set *)malloc(bytes); 956 if (errorSet == NULL) { 957 result = B_NO_MEMORY; 958 goto err; 959 } 960 if (user_memcpy(errorSet, userErrorSet, bytes) < B_OK) { 961 result = B_BAD_ADDRESS; 962 goto err; 963 } 964 } 965 966 if (userSigMask != NULL) 967 sigMask = *userSigMask; 968 969 result = common_select(numFDs, readSet, writeSet, errorSet, timeout, 970 userSigMask ? &sigMask : NULL, false); 971 972 // copy back results 973 974 if (result >= B_OK 975 && ((readSet != NULL 976 && user_memcpy(userReadSet, readSet, bytes) < B_OK) 977 || (writeSet != NULL 978 && user_memcpy(userWriteSet, writeSet, bytes) < B_OK) 979 || (errorSet != NULL 980 && user_memcpy(userErrorSet, errorSet, bytes) < B_OK))) { 981 result = B_BAD_ADDRESS; 982 } else 983 syscall_restart_handle_timeout_post(result, timeout); 984 985err: 986 free(readSet); 987 free(writeSet); 988 free(errorSet); 989 990 return result; 991} 992 993 994ssize_t 995_user_poll(struct pollfd *userfds, int numFDs, bigtime_t timeout) 996{ 997 struct pollfd *fds; 998 size_t bytes; 999 int result; 1000 1001 syscall_restart_handle_timeout_pre(timeout); 1002 1003 if (numFDs < 0) 1004 return B_BAD_VALUE; 1005 1006 if (numFDs == 0) { 1007 // special case: no FDs 1008 result = common_poll(NULL, 0, timeout, false); 1009 return result < 0 1010 ? syscall_restart_handle_timeout_post(result, timeout) : result; 1011 } 1012 1013 // copy parameters 1014 if (userfds == NULL || !IS_USER_ADDRESS(userfds)) 1015 return B_BAD_ADDRESS; 1016 1017 fds = (struct pollfd *)malloc(bytes = numFDs * sizeof(struct pollfd)); 1018 if (fds == NULL) 1019 return B_NO_MEMORY; 1020 1021 if (user_memcpy(fds, userfds, bytes) < B_OK) { 1022 result = B_BAD_ADDRESS; 1023 goto err; 1024 } 1025 1026 result = common_poll(fds, numFDs, timeout, false); 1027 1028 // copy back results 1029 if (numFDs > 0 && user_memcpy(userfds, fds, bytes) != 0) { 1030 if (result >= 0) 1031 result = B_BAD_ADDRESS; 1032 } else 1033 syscall_restart_handle_timeout_post(result, timeout); 1034 1035err: 1036 free(fds); 1037 1038 return result; 1039} 1040 1041 1042ssize_t 1043_user_wait_for_objects(object_wait_info* userInfos, int numInfos, uint32 flags, 1044 bigtime_t timeout) 1045{ 1046 syscall_restart_handle_timeout_pre(flags, timeout); 1047 1048 if (numInfos < 0) 1049 return B_BAD_VALUE; 1050 1051 if (numInfos == 0) { 1052 // special case: no infos 1053 ssize_t result = common_wait_for_objects(NULL, 0, flags, timeout, 1054 false); 1055 return result < 0 1056 ? syscall_restart_handle_timeout_post(result, timeout) : result; 1057 } 1058 1059 if (userInfos == NULL || !IS_USER_ADDRESS(userInfos)) 1060 return B_BAD_ADDRESS; 1061 1062 int bytes = sizeof(object_wait_info) * numInfos; 1063 object_wait_info* infos = (object_wait_info*)malloc(bytes); 1064 if (infos == NULL) 1065 return B_NO_MEMORY; 1066 1067 // copy parameters to kernel space, call the function, and copy the results 1068 // back 1069 ssize_t result; 1070 if (user_memcpy(infos, userInfos, bytes) == B_OK) { 1071 result = common_wait_for_objects(infos, numInfos, flags, timeout, 1072 false); 1073 1074 if (result >= 0 && user_memcpy(userInfos, infos, bytes) != B_OK) { 1075 if (result >= 0) 1076 result = B_BAD_ADDRESS; 1077 } else 1078 syscall_restart_handle_timeout_post(result, timeout); 1079 } else 1080 result = B_BAD_ADDRESS; 1081 1082 free(infos); 1083 1084 return result; 1085} 1086