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"
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"
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));
53PollDeadline pollDeadlineAfter(Time::Timestamp duration) {
55 return {PollDeadlineType::Immediate, 0};
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};
67 return {PollDeadlineType::Infinite, 0};
70 return pollDeadlineAfter(
static_cast<Time::Timestamp
>(timeout) * Time::Multiplier::Millisecond);
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;
81 return pollDeadlineAfter(duration);
84bool deadlineSemaphoreTimeout(
const PollDeadline& deadline,
size_t& seconds,
size_t& microseconds) {
87 if (deadline.type == PollDeadlineType::Infinite) {
90 if (deadline.type == PollDeadlineType::Immediate) {
94 const Time::Timestamp now = Time::getTicks();
95 if (now >= deadline.expires) {
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) {
110 seconds = maximumSeconds;
113 seconds =
static_cast<size_t>(wholeSeconds);
114 microseconds =
static_cast<size_t>(remainingMicroseconds % microsecondsPerSecond);
122 : m_Semaphore(semaphore) {}
125 m_Semaphore->release();
132ReadyMask pollInterest(
short events) {
133 ReadyMask interest = ReadyError;
134 if (events & (POLLIN | POLLRDNORM)) {
135 interest |= ReadyRead;
137 if (events & (POLLPRI | POLLRDBAND)) {
138 interest |= ReadyPriority;
140 if (events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
141 interest |= ReadyWrite;
144 if (events & POLLRDHUP) {
145 interest |= ReadyReadHangup;
151short readyMaskToPoll(ReadyMask ready,
short events) {
154 if (ready & ReadyRead) {
155 result |= events & (POLLIN | POLLRDNORM);
157 if (ready & ReadyPriority) {
158 result |= events & (POLLPRI | POLLRDBAND);
160 if (ready & ReadyWrite) {
161 result |= events & (POLLOUT | POLLWRNORM | POLLWRBAND);
163 if (ready & ReadyError) {
166 if (ready & ReadyHangup) {
170 if ((ready & ReadyReadHangup) && (events & POLLRDHUP)) {
174 if (ready & ReadyInvalid) {
180short queryDescriptorPoll(
const FileDescriptor& descriptor,
short events,
183 return readyMaskToPoll(signalView->queryReady(), events);
185 auto timerFd = descriptor.getTimerFdImpl();
187 return readyMaskToPoll(timerFd->queryReady(), events);
194 return readyMaskToPoll(eventFd->queryReady(), events);
198 return readyMaskToPoll(inotify->queryReady(), events);
200 auto fanotify = descriptor.getFanotifyImpl();
202 return readyMaskToPoll(fanotify->queryReady(), events);
206 return readyMaskToPoll(mqueue->queryReady(), events);
208 if (descriptor.getFile()) {
210 const bool canRead = accessMode != O_WRONLY;
211 const bool canWrite = accessMode != O_RDONLY;
212 return readyMaskToPoll(
217 const bool checkRead = events & (POLLIN | POLLRDNORM | POLLPRI | POLLRDBAND);
218 const bool checkWrite = events & (POLLOUT | POLLWRNORM | POLLWRBAND);
230 auto timerFd = descriptor.getTimerFdImpl();
232 return timerFd.
get();
239 return eventFd.
get();
243 return inotify.
get();
245 auto fanotify = descriptor.getFanotifyImpl();
247 return fanotify->readinessSource();
253 if (descriptor.getFile()) {
254 return descriptor.getFile();
262struct PollCleanupContext {
268 size_t descriptorCount;
272void removeReadinessSubscriptions(PollCleanupContext& cleanup) {
274 if (!subscriptions) {
278 *cleanup.readinessSubscriptions =
nullptr;
279 for (
size_t i = 0; i < cleanup.descriptorCount; ++i) {
280 subscriptions[i].reset();
282 delete[] subscriptions;
283 cleanup.readinessObserver->reset();
286void removePollRegistrations(
void* context) {
287 PollCleanupContext* cleanup =
reinterpret_cast<PollCleanupContext*
>(context);
288 if (!cleanup->active) {
291 cleanup->active =
false;
293 removeReadinessSubscriptions(*cleanup);
294 auto* signalViews = *cleanup->signalViews;
295 *cleanup->signalViews =
nullptr;
296 delete[] signalViews;
299 *cleanup->descriptors =
nullptr;
300 delete[] descriptors;
301 cleanup->semaphore->reset();
304bool copyPollReventsToUser(
struct pollfd* userFds,
const struct pollfd* snapshot,
size_t nfds) {
306 for (
size_t i = 0; i < nfds; ++i) {
308 sizeof(snapshot[i].revents))) {
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);
330 POLL_NOTICE(
" -> descriptor array size overflow");
331 SYSCALL_ERROR(InvalidArgument);
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");
339 SYSCALL_ERROR(BadAddress);
343 const int result = posix_poll_safe(snapshot, nfds, timeout);
347 const bool copied = copyPollReventsToUser(fds, snapshot, nfds);
350 POLL_NOTICE(
" -> result address became invalid");
351 SYSCALL_ERROR(BadAddress);
359bool refreshPollDescriptors(
struct pollfd* fds,
size_t nfds,
DescriptorLease* descriptors,
362 for (
size_t i = 0; i < nfds; ++i) {
363 struct pollfd* me = &fds[i];
366 me->revents |= queryDescriptorPoll(*descriptor, me->events, signalViews[i].get());
368 ready |= me->revents != 0;
373int pollWithDeadline(
struct pollfd* fds,
unsigned int nfds,
const PollDeadline& deadline) {
379 Thread* pThread =
nullptr;
380 bool returnImmediately = deadline.type == PollDeadlineType::Immediate;
383 returnImmediately =
true;
390 ERROR(
"No subsystem for this process!");
400 readinessObserver.
reset(
new PollReadinessObserver(pSem));
410 PollCleanupContext cleanup = {
411 &pSem, &readinessObserver, &readinessSubscriptions, &descriptors, &signalViews, nfds,
true};
414 for (
unsigned int i = 0; i < nfds; ++i) {
415 struct pollfd* me = &fds[i];
421 const bool acquired = acquireDescriptor(me->fd, descriptors[i]);
424 POLL_NOTICE(
"poll: no such file descriptor (" <<
Dec << me->fd <<
")");
425 me->revents |= POLLNVAL;
426 returnImmediately =
true;
430 auto signalFd = descriptor->getSignalFdImpl();
432 signalViews[i] = signalFd->bindCaller();
434 ReadinessSource* readinessSource = descriptorReadinessSource(*descriptor, signalViews[i].get());
435 if (!readinessSource) {
436 me->revents |= POLLNVAL;
437 returnImmediately =
true;
441 me->revents |= queryDescriptorPoll(*descriptor, me->events, signalViews[i].get());
443 returnImmediately =
true;
447 if (!returnImmediately) {
448 const ReadyMask interest = pollInterest(me->events);
450 readinessSubscriptions[i])) {
451 me->revents |= POLLNVAL;
452 returnImmediately =
true;
456 me->revents |= queryDescriptorPoll(*descriptor, me->events, signalViews[i].get());
458 returnImmediately =
true;
466 bool interrupted =
false;
467 bool timedOut = deadline.type == PollDeadlineType::Immediate;
469 while (!returnImmediately) {
470 POLL_NOTICE(
" -> no fds ready yet, poll will block");
473 size_t waitUSecs = 0;
474 if (!deadlineSemaphoreTimeout(deadline, waitSecs, waitUSecs)) {
479 Semaphore::SemaphoreError error = Semaphore::NoError;
481 const bool acquired = pSem->acquireWithError(1, waitSecs, waitUSecs, error);
483 while (pSem->tryAcquire())
490 if (refreshPollDescriptors(fds, nfds, descriptors, signalViews)) {
495 if (error == Semaphore::TimedOut) {
496 POLL_NOTICE(
" -> poll interrupted by timeout");
499 POLL_NOTICE(
" -> poll interrupted by external event");
505 if (pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
513 refreshPollDescriptors(fds, nfds, descriptors, signalViews);
514 if (waited && pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
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) {
527 int result =
static_cast<int>(readyCount);
528 if (!readyCount && interrupted) {
529 SYSCALL_ERROR(Interrupted);
531 }
else if (readyCount && interrupted &&
532 pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
534 pThread->clearInterruption();
537 POLL_NOTICE(
" -> " <<
Dec << result <<
Hex);
538 POLL_NOTICE(
" -> ready is " << readyCount <<
", interrupted is " << interrupted
539 <<
", timed out is " << timedOut);
541 removePollRegistrations(&cleanup);
546 if (deadline.type != PollDeadlineType::Finite) {
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);
565 const bool signalInterrupted = temporarySignalMask && temporarySignalMask->
finish();
567 copyPpollTimeoutRemainder(userTimeout, deadline);
569 return signalInterrupted;
575 if (nfds > MaxPollDescriptors) {
576 finishPpoll(temporarySignalMask, timeout, deadline);
577 SYSCALL_ERROR(InvalidArgument);
582 finishPpoll(temporarySignalMask, timeout, deadline);
583 SYSCALL_ERROR(InvalidArgument);
587 struct pollfd* snapshot = nfds ?
new struct pollfd[nfds] : nullptr;
588 if (!PosixSubsystem::copyFromUser(snapshot, fds, nfds, sizeof(struct pollfd))) {
590 finishPpoll(temporarySignalMask, timeout, deadline);
591 SYSCALL_ERROR(BadAddress);
595 int result = pollWithDeadline(snapshot, nfds, deadline);
599 const bool copiedResults = copyPollReventsToUser(fds, snapshot, nfds);
600 const bool signalInterrupted = finishPpoll(temporarySignalMask, timeout, deadline);
601 if (!result && signalInterrupted) {
602 SYSCALL_ERROR(Interrupted);
608 if (!copiedResults) {
609 SYSCALL_ERROR(BadAddress);
618 return {PollDeadlineType::Infinite, 0};
620 return pollDeadlineFromTimespec(*timeout);
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);
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));
634 const uint64_t* signalMask,
size_t signalMaskSize) {
639 SYSCALL_ERROR(BadAddress);
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);
647 timeoutValue = &timeoutSnapshot;
649 const PollDeadline deadline = posix_poll_deadline(timeoutValue);
651 uint64_t temporarySignalMask = 0;
653 if (signalMaskSize != LinuxKernelSigsetSize) {
654 SYSCALL_ERROR(InvalidArgument);
658 SYSCALL_ERROR(BadAddress);
661 temporarySignalMask &= ~UnblockableSignals;
664 FATAL(
"ppoll has no current Thread.");
668 return ppollWithDeadline(fds, nfds, timeout, deadline, &signalWait);
671 return ppollWithDeadline(fds, nfds, timeout, deadline,
nullptr);
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)
Process * getParent() const