20#include "pedigree/kernel/Subsystem.h"
21#include "pedigree/kernel/compiler.h"
22#include "pedigree/kernel/process/Thread.h"
23#include "pedigree/kernel/processor/Processor.h"
24#include "pedigree/kernel/processor/types.h"
25#include "pedigree/kernel/syscallError.h"
26#include "pedigree/kernel/time/Time.h"
28#include <PosixSubsystem.h>
31#include "net-syscalls.h"
32#include "poll-syscalls.h"
33#include "select-syscalls.h"
37constexpr int MaximumSelectDescriptors = 16384;
38constexpr size_t SelectWordBits =
sizeof(uintptr_t) * 8;
39constexpr size_t LinuxKernelSigsetSize =
sizeof(uint64_t);
40constexpr uint64_t UnblockableSignals =
41 (
static_cast<uint64_t
>(1) << (SIGKILL - 1)) | (
static_cast<uint64_t
>(1) << (SIGSTOP - 1));
42constexpr short SelectReadReady = POLLIN | POLLRDNORM | POLLRDBAND | POLLHUP | POLLERR;
43constexpr short SelectWriteReady = POLLOUT | POLLWRNORM | POLLWRBAND | POLLERR;
44constexpr short SelectExceptionalReady = POLLPRI;
46struct SelectProjection {
53SelectProjection projectSelectReadiness(
short revents,
bool checkRead,
bool checkWrite,
54 bool checkExceptional) {
55 SelectProjection result = {
56 checkRead && (revents & SelectReadReady),
57 checkWrite && (revents & SelectWriteReady),
58 checkExceptional && (revents & SelectExceptionalReady),
61 result.count =
static_cast<int>(result.read) +
static_cast<int>(result.write) +
62 static_cast<int>(result.exceptional);
66size_t selectBitmapBytes(
int nfds) {
70 return ((
static_cast<size_t>(nfds) + SelectWordBits - 1) / SelectWordBits) *
sizeof(uintptr_t);
73bool selectBitIsSet(
const uintptr_t* bitmap,
size_t descriptor) {
74 return bitmap[descriptor / SelectWordBits] &
75 (
static_cast<uintptr_t
>(1) << (descriptor % SelectWordBits));
78void setSelectBit(uintptr_t* bitmap,
size_t descriptor) {
79 bitmap[descriptor / SelectWordBits] |=
static_cast<uintptr_t
>(1) << (descriptor % SelectWordBits);
83 explicit SelectBitmaps(
size_t bitmapBytes)
91 wordCount(bitmapBytes / sizeof(uintptr_t)) {
96 storage =
new uintptr_t[wordCount * 6];
98 writeInput = readInput + wordCount;
99 errorInput = writeInput + wordCount;
100 readResult = errorInput + wordCount;
101 writeResult = readResult + wordCount;
102 errorResult = writeResult + wordCount;
103 for (
size_t i = 0; i < wordCount * 6; ++i) {
113 uintptr_t* readInput;
114 uintptr_t* writeInput;
115 uintptr_t* errorInput;
116 uintptr_t* readResult;
117 uintptr_t* writeResult;
118 uintptr_t* errorResult;
122bool importSelectTimeval(timeval* userTimeout,
PollDeadline& deadline) {
124 deadline = posix_poll_deadline(
nullptr);
128 timeval snapshot = {0, 0};
130 SYSCALL_ERROR(BadAddress);
133 if (snapshot.tv_sec < 0 || snapshot.tv_usec < 0) {
134 SYSCALL_ERROR(InvalidArgument);
138 const uint64_t microseconds =
static_cast<uint64_t
>(snapshot.tv_usec);
139 const uint64_t additionalSeconds = microseconds / 1000000;
140 const uint64_t seconds =
static_cast<uint64_t
>(snapshot.tv_sec);
141 const uint64_t maximumSeconds =
static_cast<uint64_t
>(INT64_MAX);
143 if (seconds > maximumSeconds - additionalSeconds) {
144 normalized.tv_sec = INT64_MAX;
145 normalized.tv_nsec =
static_cast<int64_t
>(Time::Multiplier::Second - 1);
147 normalized.tv_sec =
static_cast<int64_t
>(seconds + additionalSeconds);
148 normalized.tv_nsec =
static_cast<int64_t
>(microseconds % 1000000) *
149 static_cast<int64_t
>(Time::Multiplier::Microsecond);
151 deadline = posix_poll_deadline(&normalized);
157 deadline = posix_poll_deadline(
nullptr);
163 SYSCALL_ERROR(BadAddress);
166 if (snapshot.tv_sec < 0 || snapshot.tv_nsec < 0 ||
167 snapshot.tv_nsec >=
static_cast<int64_t
>(Time::Multiplier::Second)) {
168 SYSCALL_ERROR(InvalidArgument);
171 deadline = posix_poll_deadline(&snapshot);
177 if (deadline.type != PollDeadlineType::Finite) {
181 const Time::Timestamp now = Time::getTicks();
182 if (now < deadline.expires) {
183 const Time::Timestamp nanoseconds = deadline.expires - now;
184 remaining.tv_sec =
static_cast<int64_t
>(nanoseconds / Time::Multiplier::Second);
185 remaining.tv_nsec =
static_cast<int64_t
>(nanoseconds % Time::Multiplier::Second);
190void copySelectTimevalRemainder(timeval* userTimeout,
const PollDeadline& deadline) {
191 if (!userTimeout || deadline.type != PollDeadlineType::Finite) {
196 timeval remaining = {
197 static_cast<time_t
>(nanoseconds.tv_sec),
198 static_cast<suseconds_t
>(nanoseconds.tv_nsec / Time::Multiplier::Microsecond),
204 if (!userTimeout || deadline.type != PollDeadlineType::Finite) {
219 SYSCALL_ERROR(BadAddress);
226 uint64_t& temporaryMask) {
227 hasTemporaryMask =
false;
229 if (!argument.signalMask) {
232 if (argument.signalMaskSize != LinuxKernelSigsetSize) {
233 SYSCALL_ERROR(InvalidArgument);
237 reinterpret_cast<const void*
>(argument.signalMask),
238 LinuxKernelSigsetSize)) {
239 SYSCALL_ERROR(BadAddress);
242 temporaryMask &= ~UnblockableSignals;
243 hasTemporaryMask =
true;
247int selectWithDeadline(
int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds,
249 if (nfds < 0 || nfds > MaximumSelectDescriptors) {
250 SYSCALL_ERROR(InvalidArgument);
254 const size_t bitmapBytes = selectBitmapBytes(nfds);
255 SelectBitmaps bitmaps(bitmapBytes);
256 const bool copiedInputs =
261 SYSCALL_ERROR(BadAddress);
265 size_t selectedCount = 0;
266 for (
int descriptor = 0; descriptor < nfds; ++descriptor) {
267 const size_t index =
static_cast<size_t>(descriptor);
268 if ((readfds && selectBitIsSet(bitmaps.readInput, index)) ||
269 (writefds && selectBitIsSet(bitmaps.writeInput, index)) ||
270 (errorfds && selectBitIsSet(bitmaps.errorInput, index))) {
275 struct pollfd* descriptors = selectedCount ?
new struct pollfd[selectedCount] : nullptr;
276 size_t pollIndex = 0;
277 for (int descriptor = 0; descriptor < nfds; ++descriptor) {
278 const size_t index = static_cast<size_t>(descriptor);
279 const bool checkRead = readfds && selectBitIsSet(bitmaps.readInput, index);
280 const bool checkWrite = writefds && selectBitIsSet(bitmaps.writeInput, index);
281 const bool checkError = errorfds && selectBitIsSet(bitmaps.errorInput, index);
282 if (!(checkRead || checkWrite || checkError)) {
286 descriptors[pollIndex].fd = descriptor;
287 descriptors[pollIndex].events = 0;
289 descriptors[pollIndex].events |= POLLIN;
292 descriptors[pollIndex].events |= POLLOUT;
295 descriptors[pollIndex].events |= POLLPRI;
297 descriptors[pollIndex].revents = 0;
301 int result = posix_poll_safe(descriptors, static_cast<unsigned int>(selectedCount), deadline);
303 for (
size_t i = 0; i < selectedCount; ++i) {
304 if (descriptors[i].revents & POLLNVAL) {
305 SYSCALL_ERROR(BadFileDescriptor);
314 for (
int descriptor = 0; result >= 0 && descriptor < nfds; ++descriptor) {
315 const size_t index =
static_cast<size_t>(descriptor);
316 const bool checkRead = readfds && selectBitIsSet(bitmaps.readInput, index);
317 const bool checkWrite = writefds && selectBitIsSet(bitmaps.writeInput, index);
318 const bool checkError = errorfds && selectBitIsSet(bitmaps.errorInput, index);
319 if (!(checkRead || checkWrite || checkError)) {
323 const SelectProjection projection =
324 projectSelectReadiness(descriptors[pollIndex].revents, checkRead, checkWrite, checkError);
325 if (projection.read) {
326 setSelectBit(bitmaps.readResult, index);
328 if (projection.write) {
329 setSelectBit(bitmaps.writeResult, index);
331 if (projection.exceptional) {
332 setSelectBit(bitmaps.errorResult, index);
334 readyCount += projection.count;
338 delete[] descriptors;
343 const bool copiedResults =
347 if (!copiedResults) {
348 SYSCALL_ERROR(BadAddress);
355#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
356extern "C" EXPORTED_PUBLIC
unsigned int posixSelectProjectionForTest(
short revents,
bool checkRead,
358 bool checkExceptional) {
359 const SelectProjection projection =
360 projectSelectReadiness(revents, checkRead, checkWrite, checkExceptional);
361 return static_cast<unsigned int>(projection.read) |
362 (
static_cast<unsigned int>(projection.write) << 1) |
363 (
static_cast<unsigned int>(projection.exceptional) << 2) |
364 (
static_cast<unsigned int>(projection.count) << 8);
369int posix_select(
int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout) {
370 POLL_NOTICE(
"select(" << nfds <<
", " << readfds <<
", " << writefds <<
", " << errorfds <<
", "
372 PollDeadline deadline = {PollDeadlineType::Infinite, 0};
373 if (!importSelectTimeval(timeout, deadline)) {
377 const int result = selectWithDeadline(nfds, readfds, writefds, errorfds, deadline);
378 copySelectTimevalRemainder(timeout, deadline);
379 POLL_NOTICE(
" -> select via poll returns " << result);
383int posix_pselect6(
int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds,
386 if (!importPselectSignalArgument(signalArgument, signalArgumentSnapshot)) {
390 PollDeadline deadline = {PollDeadlineType::Infinite, 0};
391 if (!importPselectTimespec(timeout, deadline)) {
395 bool hasTemporaryMask =
false;
396 uint64_t temporaryMask = 0;
397 if (!importPselectSignalMask(signalArgumentSnapshot, hasTemporaryMask, temporaryMask)) {
402 if (hasTemporaryMask) {
405 FATAL(
"pselect6 has no current Thread.");
409 result = selectWithDeadline(nfds, readfds, writefds, errorfds, deadline);
410 const bool signalInterrupted = signalWait.finish();
411 if (!result && signalInterrupted) {
412 SYSCALL_ERROR(Interrupted);
416 result = selectWithDeadline(nfds, readfds, writefds, errorfds, deadline);
419 copyPselectTimespecRemainder(timeout, deadline);
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static ProcessorInformation & information()