summaryrefslogtreecommitdiffstats
path: root/libc-bottom-half/cloudlibc/src/libc/sys/select
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 13:54:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 13:54:38 +0000
commit8c1ab65c0f548d20b7f177bdb736daaf603340e1 (patch)
treedf55b7e75bf43f2bf500845b105afe3ac3a5157e /libc-bottom-half/cloudlibc/src/libc/sys/select
parentInitial commit. (diff)
downloadwasi-libc-upstream/0.0_git20221206.8b7148f.tar.xz
wasi-libc-upstream/0.0_git20221206.8b7148f.zip
Adding upstream version 0.0~git20221206.8b7148f.upstream/0.0_git20221206.8b7148f
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libc-bottom-half/cloudlibc/src/libc/sys/select')
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c125
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/select/select.c25
2 files changed, 150 insertions, 0 deletions
diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c b/libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c
new file mode 100644
index 0000000..fdc470e
--- /dev/null
+++ b/libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c
@@ -0,0 +1,125 @@
+// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
+//
+// SPDX-License-Identifier: BSD-2-Clause
+
+#include <common/time.h>
+
+#include <sys/select.h>
+
+#include <wasi/api.h>
+#include <errno.h>
+
+int pselect(int nfds, fd_set *restrict readfds, fd_set *restrict writefds,
+ fd_set *restrict errorfds, const struct timespec *restrict timeout,
+ const sigset_t *sigmask) {
+ // Negative file descriptor upperbound.
+ if (nfds < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // This implementation does not support polling for exceptional
+ // conditions, such as out-of-band data on TCP sockets.
+ if (errorfds != NULL && errorfds->__nfds > 0) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ // Replace NULL pointers by the empty set.
+ fd_set empty;
+ FD_ZERO(&empty);
+ if (readfds == NULL)
+ readfds = &empty;
+ if (writefds == NULL)
+ writefds = &empty;
+
+ // Determine the maximum number of events.
+ size_t maxevents = readfds->__nfds + writefds->__nfds + 1;
+ __wasi_subscription_t subscriptions[maxevents];
+ size_t nsubscriptions = 0;
+
+ // Convert the readfds set.
+ for (size_t i = 0; i < readfds->__nfds; ++i) {
+ int fd = readfds->__fds[i];
+ if (fd < nfds) {
+ __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++];
+ *subscription = (__wasi_subscription_t){
+ .userdata = fd,
+ .u.tag = __WASI_EVENTTYPE_FD_READ,
+ .u.u.fd_read.file_descriptor = fd,
+ };
+ }
+ }
+
+ // Convert the writefds set.
+ for (size_t i = 0; i < writefds->__nfds; ++i) {
+ int fd = writefds->__fds[i];
+ if (fd < nfds) {
+ __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++];
+ *subscription = (__wasi_subscription_t){
+ .userdata = fd,
+ .u.tag = __WASI_EVENTTYPE_FD_WRITE,
+ .u.u.fd_write.file_descriptor = fd,
+ };
+ }
+ }
+
+ // Create extra event for the timeout.
+ if (timeout != NULL) {
+ __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++];
+ *subscription = (__wasi_subscription_t){
+ .u.tag = __WASI_EVENTTYPE_CLOCK,
+ .u.u.clock.id = __WASI_CLOCKID_REALTIME,
+ };
+ if (!timespec_to_timestamp_clamp(timeout, &subscription->u.u.clock.timeout)) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ // Execute poll().
+ size_t nevents;
+ __wasi_event_t events[nsubscriptions];
+ __wasi_errno_t error =
+ __wasi_poll_oneoff(subscriptions, events, nsubscriptions, &nevents);
+ if (error != 0) {
+ // WASI's poll requires at least one subscription, or else it returns
+ // `EINVAL`. Since a `pselect` with nothing to wait for is valid in POSIX,
+ // return `ENOTSUP` to indicate that we don't support that case.
+ //
+ // Wasm has no signal handling, so if none of the user-provided `pollfd`
+ // elements, nor the timeout, led us to producing even one subscription
+ // to wait for, there would be no way for the poll to wake up. WASI
+ // returns `EINVAL` in this case, but for users of `poll`, `ENOTSUP` is
+ // more likely to be understood.
+ if (nsubscriptions == 0)
+ errno = ENOTSUP;
+ else
+ errno = error;
+ return -1;
+ }
+
+ // Test for EBADF.
+ for (size_t i = 0; i < nevents; ++i) {
+ const __wasi_event_t *event = &events[i];
+ if ((event->type == __WASI_EVENTTYPE_FD_READ ||
+ event->type == __WASI_EVENTTYPE_FD_WRITE) &&
+ event->error == __WASI_ERRNO_BADF) {
+ errno = EBADF;
+ return -1;
+ }
+ }
+
+ // Clear and set entries in the result sets.
+ FD_ZERO(readfds);
+ FD_ZERO(writefds);
+ for (size_t i = 0; i < nevents; ++i) {
+ const __wasi_event_t *event = &events[i];
+ if (event->type == __WASI_EVENTTYPE_FD_READ) {
+ readfds->__fds[readfds->__nfds++] = event->userdata;
+ } else if (event->type == __WASI_EVENTTYPE_FD_WRITE) {
+ writefds->__fds[writefds->__nfds++] = event->userdata;
+ }
+ }
+ return readfds->__nfds + writefds->__nfds;
+}
diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/select/select.c b/libc-bottom-half/cloudlibc/src/libc/sys/select/select.c
new file mode 100644
index 0000000..ebe5e8c
--- /dev/null
+++ b/libc-bottom-half/cloudlibc/src/libc/sys/select/select.c
@@ -0,0 +1,25 @@
+// Copyright (c) 2015 Nuxi, https://nuxi.nl/
+//
+// SPDX-License-Identifier: BSD-2-Clause
+
+#include <sys/select.h>
+
+#include <errno.h>
+#include <stddef.h>
+
+int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds,
+ fd_set *restrict errorfds, struct timeval *restrict timeout) {
+ if (timeout != NULL) {
+ // Timeout specified.
+ if (timeout->tv_usec < 0 || timeout->tv_usec >= 1000000) {
+ errno = EINVAL;
+ return -1;
+ }
+ struct timespec ts = {.tv_sec = timeout->tv_sec,
+ .tv_nsec = (long)timeout->tv_usec * 1000};
+ return pselect(nfds, readfds, writefds, errorfds, &ts, NULL);
+ } else {
+ // No timeout specified.
+ return pselect(nfds, readfds, writefds, errorfds, NULL, NULL);
+ }
+}