diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 13:54:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 13:54:38 +0000 |
commit | 8c1ab65c0f548d20b7f177bdb736daaf603340e1 (patch) | |
tree | df55b7e75bf43f2bf500845b105afe3ac3a5157e /libc-bottom-half/cloudlibc/src/libc/sys/select | |
parent | Initial commit. (diff) | |
download | wasi-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.c | 125 | ||||
-rw-r--r-- | libc-bottom-half/cloudlibc/src/libc/sys/select/select.c | 25 |
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 = ∅ + if (writefds == NULL) + writefds = ∅ + + // 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); + } +} |