The Pedigree Project 0.1
poll-syscalls.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/compiler.h"
21#include "pedigree/kernel/process/Process.h"
22#include "pedigree/kernel/process/Readiness.h"
23#include "pedigree/kernel/process/Semaphore.h"
24#include "pedigree/kernel/process/TerminationDeferral.h"
25#include "pedigree/kernel/process/Thread.h"
26#include "pedigree/kernel/processor/Processor.h"
27#include "pedigree/kernel/processor/types.h"
28#include "pedigree/kernel/syscallError.h"
29#include "pedigree/kernel/time/Time.h"
30
31#include <fcntl.h>
32#include <signal.h>
33
34#include "modules/subsys/posix/FileDescriptor.h"
35#include "modules/subsys/posix/PosixSubsystem.h"
36#include "modules/subsys/posix/epoll-syscalls.h"
37#include "modules/subsys/posix/eventfd-syscalls.h"
38#include "modules/subsys/posix/fanotify-syscalls.h"
39#include "modules/subsys/posix/inotify-syscalls.h"
40#include "modules/subsys/posix/mqueue-syscalls.h"
41#include "modules/system/vfs/File.h"
42#include "net-syscalls.h"
43#include "poll-syscalls.h"
44#include "signalfd-syscalls.h"
45#include "timerfd-syscalls.h"
46
47namespace {
48constexpr unsigned int MaxPollDescriptors = 16384;
49constexpr size_t LinuxKernelSigsetSize = sizeof(uint64_t);
50constexpr uint64_t UnblockableSignals =
51 (static_cast<uint64_t>(1) << (SIGKILL - 1)) | (static_cast<uint64_t>(1) << (SIGSTOP - 1));
52
53PollDeadline pollDeadlineAfter(Time::Timestamp duration) {
54 if (!duration) {
55 return {PollDeadlineType::Immediate, 0};
56 }
57
58 const Time::Timestamp now = Time::getTicks();
59 const Time::Timestamp maximum = Time::Infinity - 1;
60 const Time::Timestamp expires =
61 now >= maximum || duration > maximum - now ? maximum : now + duration;
62 return {PollDeadlineType::Finite, expires};
63}
64
65PollDeadline pollDeadlineFromMilliseconds(int timeout) {
66 if (timeout < 0) {
67 return {PollDeadlineType::Infinite, 0};
68 }
69
70 return pollDeadlineAfter(static_cast<Time::Timestamp>(timeout) * Time::Multiplier::Millisecond);
71}
72
73PollDeadline pollDeadlineFromTimespec(const LinuxKernelTimespec& timeout) {
74 const Time::Timestamp maximum = Time::Infinity - 1;
75 Time::Timestamp duration = maximum;
76 if (static_cast<uint64_t>(timeout.tv_sec) <= maximum / Time::Multiplier::Second) {
77 duration = static_cast<Time::Timestamp>(timeout.tv_sec) * Time::Multiplier::Second;
78 const Time::Timestamp nanoseconds = static_cast<Time::Timestamp>(timeout.tv_nsec);
79 duration = nanoseconds > maximum - duration ? maximum : duration + nanoseconds;
80 }
81 return pollDeadlineAfter(duration);
82}
83
84bool deadlineSemaphoreTimeout(const PollDeadline& deadline, size_t& seconds, size_t& microseconds) {
85 seconds = 0;
86 microseconds = 0;
87 if (deadline.type == PollDeadlineType::Infinite) {
88 return true;
89 }
90 if (deadline.type == PollDeadlineType::Immediate) {
91 return false;
92 }
93
94 const Time::Timestamp now = Time::getTicks();
95 if (now >= deadline.expires) {
96 return false;
97 }
98
99 const Time::Timestamp remaining = deadline.expires - now;
100 const Time::Timestamp remainingMicroseconds =
101 (remaining / Time::Multiplier::Microsecond) +
102 ((remaining % Time::Multiplier::Microsecond) ? 1 : 0);
103 const Time::Timestamp microsecondsPerSecond =
104 Time::Multiplier::Second / Time::Multiplier::Microsecond;
105 const Time::Timestamp wholeSeconds = remainingMicroseconds / microsecondsPerSecond;
106 const size_t maximumSeconds = ~static_cast<size_t>(0);
107 if (wholeSeconds > maximumSeconds) {
108 // A shorter saturated chunk is safe: the absolute deadline is checked
109 // again after this timer wakes.
110 seconds = maximumSeconds;
111 microseconds = 0;
112 } else {
113 seconds = static_cast<size_t>(wholeSeconds);
114 microseconds = static_cast<size_t>(remainingMicroseconds % microsecondsPerSecond);
115 }
116 return true;
117}
118
119class PollReadinessObserver final : public ReadinessObserver {
120 public:
121 explicit PollReadinessObserver(const SharedPointer<Semaphore>& semaphore)
122 : m_Semaphore(semaphore) {}
123
124 void readinessChanged(ReadyMask) override {
125 m_Semaphore->release();
126 }
127
128 private:
129 SharedPointer<Semaphore> m_Semaphore;
130};
131
132ReadyMask pollInterest(short events) {
133 ReadyMask interest = ReadyError;
134 if (events & (POLLIN | POLLRDNORM)) {
135 interest |= ReadyRead;
136 }
137 if (events & (POLLPRI | POLLRDBAND)) {
138 interest |= ReadyPriority;
139 }
140 if (events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
141 interest |= ReadyWrite;
142 }
143#ifdef POLLRDHUP
144 if (events & POLLRDHUP) {
145 interest |= ReadyReadHangup;
146 }
147#endif
148 return interest;
149}
150
151short readyMaskToPoll(ReadyMask ready, short events) {
152 short result = 0;
153
154 if (ready & ReadyRead) {
155 result |= events & (POLLIN | POLLRDNORM);
156 }
157 if (ready & ReadyPriority) {
158 result |= events & (POLLPRI | POLLRDBAND);
159 }
160 if (ready & ReadyWrite) {
161 result |= events & (POLLOUT | POLLWRNORM | POLLWRBAND);
162 }
163 if (ready & ReadyError) {
164 result |= POLLERR;
165 }
166 if (ready & ReadyHangup) {
167 result |= POLLHUP;
168 }
169#ifdef POLLRDHUP
170 if ((ready & ReadyReadHangup) && (events & POLLRDHUP)) {
171 result |= POLLRDHUP;
172 }
173#endif
174 if (ready & ReadyInvalid) {
175 result |= POLLNVAL;
176 }
177 return result;
178}
179
180short queryDescriptorPoll(const FileDescriptor& descriptor, short events,
181 SignalFdView* signalView) {
182 if (signalView) {
183 return readyMaskToPoll(signalView->queryReady(), events);
184 }
185 auto timerFd = descriptor.getTimerFdImpl();
186 if (timerFd) {
187 return readyMaskToPoll(timerFd->queryReady(), events);
188 }
189 if (descriptor.epollImpl) {
190 return readyMaskToPoll(descriptor.epollImpl->queryReady(), events);
191 }
192 SharedPointer<EventFd> eventFd = descriptor.getEventFdImpl();
193 if (eventFd) {
194 return readyMaskToPoll(eventFd->queryReady(), events);
195 }
196 SharedPointer<InotifyInstance> inotify = descriptor.getInotifyImpl();
197 if (inotify) {
198 return readyMaskToPoll(inotify->queryReady(), events);
199 }
200 auto fanotify = descriptor.getFanotifyImpl();
201 if (fanotify) {
202 return readyMaskToPoll(fanotify->queryReady(), events);
203 }
204 SharedPointer<PosixMessageQueue> mqueue = descriptor.getMqueueImpl();
205 if (mqueue) {
206 return readyMaskToPoll(mqueue->queryReady(), events);
207 }
208 if (descriptor.getFile()) {
209 const int accessMode = descriptor.getStatusFlags() & O_ACCMODE;
210 const bool canRead = accessMode != O_WRONLY;
211 const bool canWrite = accessMode != O_RDONLY;
212 return readyMaskToPoll(
213 descriptor.acquireOpenFileDescription()->queryFileReady(canRead, canWrite), events);
214 }
215
216 if (descriptor.networkImpl) {
217 const bool checkRead = events & (POLLIN | POLLRDNORM | POLLPRI | POLLRDBAND);
218 const bool checkWrite = events & (POLLOUT | POLLWRNORM | POLLWRBAND);
219 return readyMaskToPoll(descriptor.networkImpl->queryReady(checkRead, checkWrite), events);
220 }
221
222 return 0;
223}
224
225ReadinessSource* descriptorReadinessSource(const FileDescriptor& descriptor,
226 SignalFdView* signalView) {
227 if (signalView) {
228 return signalView;
229 }
230 auto timerFd = descriptor.getTimerFdImpl();
231 if (timerFd) {
232 return timerFd.get();
233 }
234 if (descriptor.epollImpl) {
235 return descriptor.epollImpl.get();
236 }
237 SharedPointer<EventFd> eventFd = descriptor.getEventFdImpl();
238 if (eventFd) {
239 return eventFd.get();
240 }
241 SharedPointer<InotifyInstance> inotify = descriptor.getInotifyImpl();
242 if (inotify) {
243 return inotify.get();
244 }
245 auto fanotify = descriptor.getFanotifyImpl();
246 if (fanotify) {
247 return fanotify->readinessSource();
248 }
249 SharedPointer<PosixMessageQueue> mqueue = descriptor.getMqueueImpl();
250 if (mqueue) {
251 return mqueue.get();
252 }
253 if (descriptor.getFile()) {
254 return descriptor.getFile();
255 }
256 if (descriptor.networkImpl) {
257 return descriptor.networkImpl.get();
258 }
259 return nullptr;
260}
261
262struct PollCleanupContext {
263 SharedPointer<Semaphore>* semaphore;
264 SharedPointer<ReadinessObserver>* readinessObserver;
265 ReadinessSubscription** readinessSubscriptions;
266 DescriptorLease** descriptors;
267 SharedPointer<SignalFdView>** signalViews;
268 size_t descriptorCount;
269 bool active;
270};
271
272void removeReadinessSubscriptions(PollCleanupContext& cleanup) {
273 ReadinessSubscription* subscriptions = *cleanup.readinessSubscriptions;
274 if (!subscriptions) {
275 return;
276 }
277
278 *cleanup.readinessSubscriptions = nullptr;
279 for (size_t i = 0; i < cleanup.descriptorCount; ++i) {
280 subscriptions[i].reset();
281 }
282 delete[] subscriptions;
283 cleanup.readinessObserver->reset();
284}
285
286void removePollRegistrations(void* context) {
287 PollCleanupContext* cleanup = reinterpret_cast<PollCleanupContext*>(context);
288 if (!cleanup->active) {
289 return;
290 }
291 cleanup->active = false;
292
293 removeReadinessSubscriptions(*cleanup);
294 auto* signalViews = *cleanup->signalViews;
295 *cleanup->signalViews = nullptr;
296 delete[] signalViews;
297
298 DescriptorLease* descriptors = *cleanup->descriptors;
299 *cleanup->descriptors = nullptr;
300 delete[] descriptors;
301 cleanup->semaphore->reset();
302}
303
304bool copyPollReventsToUser(struct pollfd* userFds, const struct pollfd* snapshot, size_t nfds) {
305 // fd and events remain concurrent user-owned input fields.
306 for (size_t i = 0; i < nfds; ++i) {
307 if (!PosixSubsystem::copyToUser(&userFds[i].revents, &snapshot[i].revents,
308 sizeof(snapshot[i].revents))) {
309 return false;
310 }
311 }
312 return true;
313}
314} // namespace
315
320int posix_poll(struct pollfd* fds, unsigned int nfds, int timeout) {
321 POLL_NOTICE("poll(" << Dec << nfds << ", " << timeout << Hex << ")");
322 if (nfds > MaxPollDescriptors) {
323 POLL_NOTICE(" -> too many descriptors");
324 SYSCALL_ERROR(InvalidArgument);
325 return -1;
326 }
327
328 size_t extent = 0;
329 if (!PosixSubsystem::checkedUserBufferSize(nfds, sizeof(struct pollfd), extent)) {
330 POLL_NOTICE(" -> descriptor array size overflow");
331 SYSCALL_ERROR(InvalidArgument);
332 return -1;
333 }
334
335 struct pollfd* snapshot = nfds ? new struct pollfd[nfds] : nullptr;
336 if (!PosixSubsystem::copyFromUser(snapshot, fds, nfds, sizeof(struct pollfd))) {
337 POLL_NOTICE(" -> invalid address");
338 delete[] snapshot;
339 SYSCALL_ERROR(BadAddress);
340 return -1;
341 }
342
343 const int result = posix_poll_safe(snapshot, nfds, timeout);
344
345 // posix_poll_safe has retired every registration before it returns, so no
346 // callback can retain a pointer into this snapshot during copyout.
347 const bool copied = copyPollReventsToUser(fds, snapshot, nfds);
348 delete[] snapshot;
349 if (!copied) {
350 POLL_NOTICE(" -> result address became invalid");
351 SYSCALL_ERROR(BadAddress);
352 return -1;
353 }
354
355 return result;
356}
357
358namespace {
359bool refreshPollDescriptors(struct pollfd* fds, size_t nfds, DescriptorLease* descriptors,
360 SharedPointer<SignalFdView>* signalViews) {
361 bool ready = false;
362 for (size_t i = 0; i < nfds; ++i) {
363 struct pollfd* me = &fds[i];
364 DescriptorLease& descriptor = descriptors[i];
365 if (descriptor) {
366 me->revents |= queryDescriptorPoll(*descriptor, me->events, signalViews[i].get());
367 }
368 ready |= me->revents != 0;
369 }
370 return ready;
371}
372
373int pollWithDeadline(struct pollfd* fds, unsigned int nfds, const PollDeadline& deadline) {
374 // Readiness registrations retain the observer and semaphore used by this
375 // call. A terminal request may wake the wait, but cleanup must unregister
376 // every target before the syscall stack can be consumed.
377 TerminationDeferral registrationLifetime;
378
379 Thread* pThread = nullptr;
380 bool returnImmediately = deadline.type == PollDeadlineType::Immediate;
381 EMIT_IF(!THREADS) {
382 // No scheduler is available to complete a blocking wait.
383 returnImmediately = true;
384 }
385 else {
386 pThread = Processor::information().getCurrentThread();
387 Process* pProcess = pThread->getParent();
388 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
389 if (!pSubsystem) {
390 ERROR("No subsystem for this process!");
391 return -1;
392 }
393 }
394
395 SharedPointer<Semaphore> pSem = nullptr;
396 SharedPointer<ReadinessObserver> readinessObserver;
397 ReadinessSubscription* readinessSubscriptions = nullptr;
398 EMIT_IF(THREADS) {
399 pSem.reset(new Semaphore(0, true));
400 readinessObserver.reset(new PollReadinessObserver(pSem));
401 readinessSubscriptions = new ReadinessSubscription[nfds];
402 }
403
404 // Keep the exact descriptor generation used during registration pinned
405 // until every file event and socket waiter has been removed. Re-looking up
406 // the numeric fd during wakeup or cleanup could target a reused descriptor
407 // and leave a registration pointing into this stack behind.
408 DescriptorLease* descriptors = new DescriptorLease[nfds];
409 auto* signalViews = new SharedPointer<SignalFdView>[nfds];
410 PollCleanupContext cleanup = {
411 &pSem, &readinessObserver, &readinessSubscriptions, &descriptors, &signalViews, nfds, true};
412 Thread::StackDiscardScope discardScope(THREADS ? &removePollRegistrations : nullptr, &cleanup);
413
414 for (unsigned int i = 0; i < nfds; ++i) {
415 struct pollfd* me = &fds[i];
416 me->revents = 0;
417 if (me->fd < 0) {
418 continue;
419 }
420
421 const bool acquired = acquireDescriptor(me->fd, descriptors[i]);
422 DescriptorLease& descriptor = descriptors[i];
423 if (!acquired) {
424 POLL_NOTICE("poll: no such file descriptor (" << Dec << me->fd << ")");
425 me->revents |= POLLNVAL;
426 returnImmediately = true;
427 continue;
428 }
429
430 auto signalFd = descriptor->getSignalFdImpl();
431 if (signalFd) {
432 signalViews[i] = signalFd->bindCaller();
433 }
434 ReadinessSource* readinessSource = descriptorReadinessSource(*descriptor, signalViews[i].get());
435 if (!readinessSource) {
436 me->revents |= POLLNVAL;
437 returnImmediately = true;
438 continue;
439 }
440
441 me->revents |= queryDescriptorPoll(*descriptor, me->events, signalViews[i].get());
442 if (me->revents) {
443 returnImmediately = true;
444 }
445
446 EMIT_IF(THREADS) {
447 if (!returnImmediately) {
448 const ReadyMask interest = pollInterest(me->events);
449 if (!readinessSource->subscribeReadiness(interest, readinessObserver,
450 readinessSubscriptions[i])) {
451 me->revents |= POLLNVAL;
452 returnImmediately = true;
453 } else {
454 // Subscription precedes the second snapshot, closing the only
455 // transition window in which a level could otherwise be missed.
456 me->revents |= queryDescriptorPoll(*descriptor, me->events, signalViews[i].get());
457 if (me->revents) {
458 returnImmediately = true;
459 }
460 }
461 }
462 }
463 }
464
465 bool waited = false;
466 bool interrupted = false;
467 bool timedOut = deadline.type == PollDeadlineType::Immediate;
468 EMIT_IF(THREADS) {
469 while (!returnImmediately) {
470 POLL_NOTICE(" -> no fds ready yet, poll will block");
471
472 size_t waitSecs = 0;
473 size_t waitUSecs = 0;
474 if (!deadlineSemaphoreTimeout(deadline, waitSecs, waitUSecs)) {
475 timedOut = true;
476 break;
477 }
478
479 Semaphore::SemaphoreError error = Semaphore::NoError;
480 waited = true;
481 const bool acquired = pSem->acquireWithError(1, waitSecs, waitUSecs, error);
482 if (acquired) {
483 while (pSem->tryAcquire())
484 ;
485 }
486
487 // Recompute the predicate after every wake outcome. A readiness change
488 // racing a timeout or signal owns the result even if the semaphore
489 // reported the other event first.
490 if (refreshPollDescriptors(fds, nfds, descriptors, signalViews)) {
491 break;
492 }
493
494 if (!acquired) {
495 if (error == Semaphore::TimedOut) {
496 POLL_NOTICE(" -> poll interrupted by timeout");
497 timedOut = true;
498 } else {
499 POLL_NOTICE(" -> poll interrupted by external event");
500 interrupted = true;
501 }
502 break;
503 }
504
505 if (pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
506 interrupted = true;
507 break;
508 }
509 }
510 }
511
512 // One last level snapshot closes a change racing the terminal decision.
513 refreshPollDescriptors(fds, nfds, descriptors, signalViews);
514 if (waited && pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
515 interrupted = true;
516 }
517
518 size_t readyCount = 0;
519 for (size_t i = 0; i < nfds; ++i) {
520 POLL_NOTICE(" -> pollfd[" << i << "]: fd=" << fds[i].fd << ", events=" << fds[i].events
521 << ", revents=" << fds[i].revents);
522 if (fds[i].revents != 0) {
523 ++readyCount;
524 }
525 }
526
527 int result = static_cast<int>(readyCount);
528 if (!readyCount && interrupted) {
529 SYSCALL_ERROR(Interrupted);
530 result = -1;
531 } else if (readyCount && interrupted &&
532 pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
533 // The handler ran, but readiness won this syscall's terminal collision.
534 pThread->clearInterruption();
535 }
536
537 POLL_NOTICE(" -> " << Dec << result << Hex);
538 POLL_NOTICE(" -> ready is " << readyCount << ", interrupted is " << interrupted
539 << ", timed out is " << timedOut);
540
541 removePollRegistrations(&cleanup);
542 return result;
543}
544
545void copyPpollTimeoutRemainder(LinuxKernelTimespec* userTimeout, const PollDeadline& deadline) {
546 if (deadline.type != PollDeadlineType::Finite) {
547 return;
548 }
549
550 LinuxKernelTimespec remaining = {0, 0};
551 const Time::Timestamp now = Time::getTicks();
552 if (now < deadline.expires) {
553 const Time::Timestamp nanoseconds = deadline.expires - now;
554 remaining.tv_sec = static_cast<int64_t>(nanoseconds / Time::Multiplier::Second);
555 remaining.tv_nsec = static_cast<int64_t>(nanoseconds % Time::Multiplier::Second);
556 }
557
558 // Linux treats timeout writeback as advisory: a late output fault does not
559 // replace the poll result or a descriptor-copy EFAULT.
560 PosixSubsystem::copyToUser(userTimeout, &remaining, sizeof(remaining));
561}
562
563bool finishPpoll(Thread::TemporarySignalMask* temporarySignalMask, LinuxKernelTimespec* userTimeout,
564 const PollDeadline& deadline) {
565 const bool signalInterrupted = temporarySignalMask && temporarySignalMask->finish();
566 if (userTimeout) {
567 copyPpollTimeoutRemainder(userTimeout, deadline);
568 }
569 return signalInterrupted;
570}
571
572int ppollWithDeadline(struct pollfd* fds, unsigned int nfds, LinuxKernelTimespec* timeout,
573 const PollDeadline& deadline,
574 Thread::TemporarySignalMask* temporarySignalMask) {
575 if (nfds > MaxPollDescriptors) {
576 finishPpoll(temporarySignalMask, timeout, deadline);
577 SYSCALL_ERROR(InvalidArgument);
578 return -1;
579 }
580 size_t extent = 0;
581 if (!PosixSubsystem::checkedUserBufferSize(nfds, sizeof(struct pollfd), extent)) {
582 finishPpoll(temporarySignalMask, timeout, deadline);
583 SYSCALL_ERROR(InvalidArgument);
584 return -1;
585 }
586
587 struct pollfd* snapshot = nfds ? new struct pollfd[nfds] : nullptr;
588 if (!PosixSubsystem::copyFromUser(snapshot, fds, nfds, sizeof(struct pollfd))) {
589 delete[] snapshot;
590 finishPpoll(temporarySignalMask, timeout, deadline);
591 SYSCALL_ERROR(BadAddress);
592 return -1;
593 }
594
595 int result = pollWithDeadline(snapshot, nfds, deadline);
596 // Linux publishes revents while the temporary mask still governs signal
597 // delivery. Timeout writeback happens only after the caller's mask is
598 // restored.
599 const bool copiedResults = copyPollReventsToUser(fds, snapshot, nfds);
600 const bool signalInterrupted = finishPpoll(temporarySignalMask, timeout, deadline);
601 if (!result && signalInterrupted) {
602 SYSCALL_ERROR(Interrupted);
603 result = -1;
604 }
605
606 delete[] snapshot;
607
608 if (!copiedResults) {
609 SYSCALL_ERROR(BadAddress);
610 return -1;
611 }
612 return result;
613}
614} // namespace
615
616PollDeadline posix_poll_deadline(const LinuxKernelTimespec* timeout) {
617 if (!timeout) {
618 return {PollDeadlineType::Infinite, 0};
619 }
620 return pollDeadlineFromTimespec(*timeout);
621}
622
623int posix_poll_safe(struct pollfd* fds, unsigned int nfds, const PollDeadline& deadline) {
624 POLL_NOTICE("poll_safe_deadline(" << Dec << nfds << Hex << ")");
625 return pollWithDeadline(fds, nfds, deadline);
626}
627
628int posix_poll_safe(struct pollfd* fds, unsigned int nfds, int timeout) {
629 POLL_NOTICE("poll_safe(" << Dec << nfds << ", " << timeout << Hex << ")");
630 return pollWithDeadline(fds, nfds, pollDeadlineFromMilliseconds(timeout));
631}
632
633int posix_ppoll(struct pollfd* fds, unsigned int nfds, LinuxKernelTimespec* timeout,
634 const uint64_t* signalMask, size_t signalMaskSize) {
635 LinuxKernelTimespec timeoutSnapshot = {0, 0};
636 const LinuxKernelTimespec* timeoutValue = nullptr;
637 if (timeout) {
638 if (!PosixSubsystem::copyFromUser(&timeoutSnapshot, timeout, sizeof(timeoutSnapshot))) {
639 SYSCALL_ERROR(BadAddress);
640 return -1;
641 }
642 if (timeoutSnapshot.tv_sec < 0 || timeoutSnapshot.tv_nsec < 0 ||
643 timeoutSnapshot.tv_nsec >= static_cast<int64_t>(Time::Multiplier::Second)) {
644 SYSCALL_ERROR(InvalidArgument);
645 return -1;
646 }
647 timeoutValue = &timeoutSnapshot;
648 }
649 const PollDeadline deadline = posix_poll_deadline(timeoutValue);
650
651 uint64_t temporarySignalMask = 0;
652 if (signalMask) {
653 if (signalMaskSize != LinuxKernelSigsetSize) {
654 SYSCALL_ERROR(InvalidArgument);
655 return -1;
656 }
657 if (!PosixSubsystem::copyFromUser(&temporarySignalMask, signalMask, LinuxKernelSigsetSize)) {
658 SYSCALL_ERROR(BadAddress);
659 return -1;
660 }
661 temporarySignalMask &= ~UnblockableSignals;
662 Thread* thread = Processor::information().getCurrentThread();
663 if (!thread) {
664 FATAL("ppoll has no current Thread.");
665 }
666
667 Thread::TemporarySignalMask signalWait(*thread, temporarySignalMask);
668 return ppollWithDeadline(fds, nfds, timeout, deadline, &signalWait);
669 }
670
671 return ppollWithDeadline(fds, nfds, timeout, deadline, nullptr);
672}
ReadyMask queryReady()
SharedPointer< EpollInstance > epollImpl
Epoll implementation for this descriptor (if it is an epoll object).
OpenFileDescriptionLease acquireOpenFileDescription() const
SharedPointer< InotifyInstance > getInotifyImpl() const
SharedPointer< EventFd > getEventFdImpl() const
int getStatusFlags() const
Get current status flags.
SharedPointer< NetworkSyscalls > networkImpl
Network syscall implementation for this descriptor (if it's a socket).
virtual ReadyMask queryReady(bool reading, bool writing)
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool checkedUserBufferSize(size_t count, size_t elementSize, size_t &extent)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static ProcessorInformation & information()
virtual void readinessChanged(ReadyMask mask)=0
MUST_USE_RESULT bool subscribeReadiness(ReadyMask interest, const SharedPointer< ReadinessObserver > &observer, ReadinessSubscription &subscription)
Definition Readiness.cc:181
T * get() const
Process * getParent() const
Definition Thread.h:340
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124