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