diff --git a/include/zephyr/net/socket_select.h b/include/zephyr/net/socket_select.h index 5fca2950d6a..877bd863a6b 100644 --- a/include/zephyr/net/socket_select.h +++ b/include/zephyr/net/socket_select.h @@ -19,17 +19,18 @@ * @{ */ +#include + #include #include +#include #ifdef __cplusplus extern "C" { #endif /** Socket file descriptor set. */ -typedef struct zsock_fd_set { - uint32_t bitset[(CONFIG_ZVFS_OPEN_MAX + 31) / 32]; -} zsock_fd_set; +typedef struct zvfs_fd_set zsock_fd_set; /** * @brief Legacy function to poll multiple sockets for events @@ -47,13 +48,16 @@ typedef struct zsock_fd_set { * it may conflict with generic POSIX ``select()`` function). * @endrst */ -__syscall int zsock_select(int nfds, zsock_fd_set *readfds, - zsock_fd_set *writefds, - zsock_fd_set *exceptfds, - struct zsock_timeval *timeout); +static inline int zsock_select(int nfds, zsock_fd_set *readfds, zsock_fd_set *writefds, + zsock_fd_set *exceptfds, struct zsock_timeval *timeout) +{ + struct timeval; + + return zvfs_select(nfds, readfds, writefds, exceptfds, (struct timeval *)timeout); +} /** Number of file descriptors which can be added to zsock_fd_set */ -#define ZSOCK_FD_SETSIZE (sizeof(((zsock_fd_set *)0)->bitset) * 8) +#define ZSOCK_FD_SETSIZE ZVFS_FD_SETSIZE /** * @brief Initialize (clear) fd_set @@ -67,7 +71,10 @@ __syscall int zsock_select(int nfds, zsock_fd_set *readfds, * if :kconfig:option:`CONFIG_POSIX_API` is defined. * @endrst */ -void ZSOCK_FD_ZERO(zsock_fd_set *set); +static inline void ZSOCK_FD_ZERO(zsock_fd_set *set) +{ + ZVFS_FD_ZERO(set); +} /** * @brief Check whether socket is a member of fd_set @@ -81,7 +88,10 @@ void ZSOCK_FD_ZERO(zsock_fd_set *set); * if :kconfig:option:`CONFIG_POSIX_API` is defined. * @endrst */ -int ZSOCK_FD_ISSET(int fd, zsock_fd_set *set); +static inline int ZSOCK_FD_ISSET(int fd, zsock_fd_set *set) +{ + return ZVFS_FD_ISSET(fd, set); +} /** * @brief Remove socket from fd_set @@ -95,7 +105,10 @@ int ZSOCK_FD_ISSET(int fd, zsock_fd_set *set); * if :kconfig:option:`CONFIG_POSIX_API` is defined. * @endrst */ -void ZSOCK_FD_CLR(int fd, zsock_fd_set *set); +static inline void ZSOCK_FD_CLR(int fd, zsock_fd_set *set) +{ + ZVFS_FD_CLR(fd, set); +} /** * @brief Add socket to fd_set @@ -109,7 +122,10 @@ void ZSOCK_FD_CLR(int fd, zsock_fd_set *set); * if :kconfig:option:`CONFIG_POSIX_API` is defined. * @endrst */ -void ZSOCK_FD_SET(int fd, zsock_fd_set *set); +static inline void ZSOCK_FD_SET(int fd, zsock_fd_set *set) +{ + ZVFS_FD_SET(fd, set); +} /** @cond INTERNAL_HIDDEN */ @@ -153,8 +169,6 @@ static inline void FD_SET(int fd, zsock_fd_set *set) } #endif -#include - /** * @} */ diff --git a/include/zephyr/posix/sys/select.h b/include/zephyr/posix/sys/select.h index fc61c018e24..e10eeb237ee 100644 --- a/include/zephyr/posix/sys/select.h +++ b/include/zephyr/posix/sys/select.h @@ -13,16 +13,18 @@ extern "C" { #endif +#undef fd_set #define fd_set zsock_fd_set -#define FD_SETSIZE ZSOCK_FD_SETSIZE -#define FD_ZERO ZSOCK_FD_ZERO -#define FD_SET ZSOCK_FD_SET -#define FD_CLR ZSOCK_FD_CLR -#define FD_ISSET ZSOCK_FD_ISSET + +#define FD_SETSIZE ZVFS_FD_SETSIZE struct timeval; -int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); +int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); +void FD_CLR(int fd, fd_set *fdset); +int FD_ISSET(int fd, fd_set *fdset); +void FD_SET(int fd, fd_set *fdset); +void FD_ZERO(fd_set *fdset); #ifdef __cplusplus } diff --git a/include/zephyr/sys/fdtable.h b/include/zephyr/sys/fdtable.h index 5db80988b30..ba709a68cdb 100644 --- a/include/zephyr/sys/fdtable.h +++ b/include/zephyr/sys/fdtable.h @@ -7,9 +7,10 @@ #define ZEPHYR_INCLUDE_SYS_FDTABLE_H_ #include -#include +#include + /* FIXME: For native_posix ssize_t, off_t. */ -#include +#include #include #include @@ -207,6 +208,23 @@ struct zvfs_pollfd { __syscall int zvfs_poll(struct zvfs_pollfd *fds, int nfds, int poll_timeout); +struct zvfs_fd_set { + uint32_t bitset[(CONFIG_ZVFS_OPEN_MAX + 31) / 32]; +}; + +/** @brief Number of file descriptors which can be added @ref zvfs_fd_set */ +#define ZVFS_FD_SETSIZE (sizeof(((struct zvfs_fd_set *)0)->bitset) * 8) + +void ZVFS_FD_CLR(int fd, struct zvfs_fd_set *fdset); +int ZVFS_FD_ISSET(int fd, struct zvfs_fd_set *fdset); +void ZVFS_FD_SET(int fd, struct zvfs_fd_set *fdset); +void ZVFS_FD_ZERO(struct zvfs_fd_set *fdset); + +__syscall int zvfs_select(int nfds, struct zvfs_fd_set *ZRESTRICT readfds, + struct zvfs_fd_set *ZRESTRICT writefds, + struct zvfs_fd_set *ZRESTRICT errorfds, + const struct timeval *ZRESTRICT timeout); + /** * Request codes for fd_op_vtable.ioctl(). * @@ -236,4 +254,6 @@ enum { } #endif +#include + #endif /* ZEPHYR_INCLUDE_SYS_FDTABLE_H_ */ diff --git a/lib/os/zvfs/CMakeLists.txt b/lib/os/zvfs/CMakeLists.txt index ef0dde4513b..d855d1005ef 100644 --- a/lib/os/zvfs/CMakeLists.txt +++ b/lib/os/zvfs/CMakeLists.txt @@ -3,3 +3,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_ZVFS_EVENTFD zvfs_eventfd.c) zephyr_library_sources_ifdef(CONFIG_ZVFS_POLL zvfs_poll.c) +zephyr_library_sources_ifdef(CONFIG_ZVFS_SELECT zvfs_select.c) diff --git a/lib/os/zvfs/Kconfig b/lib/os/zvfs/Kconfig index 40cba2cd9c9..df107c24c62 100644 --- a/lib/os/zvfs/Kconfig +++ b/lib/os/zvfs/Kconfig @@ -49,6 +49,11 @@ config ZVFS_POLL_MAX help Maximum number of entries supported for poll() call. +config ZVFS_SELECT + bool "ZVFS select" + help + Enable support for zvfs_select(). + endif # ZVFS_POLL endif # ZVFS diff --git a/subsys/net/lib/sockets/sockets_select.c b/lib/os/zvfs/zvfs_select.c similarity index 61% rename from subsys/net/lib/sockets/sockets_select.c rename to lib/os/zvfs/zvfs_select.c index 49d61a2d28c..32748fc694b 100644 --- a/subsys/net/lib/sockets/sockets_select.c +++ b/lib/os/zvfs/zvfs_select.c @@ -1,14 +1,16 @@ /* * Copyright (c) 2018 Linaro Limited + * Copyright (c) 2024 Tenstorrent AI ULC * * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include #include #include -#include "sockets_internal.h" /* Get size, in elements, of an array within a struct. */ #define STRUCT_MEMBER_ARRAY_SIZE(type, field) ARRAY_SIZE(((type *)0)->field) @@ -20,7 +22,9 @@ bit_mask = 1 << b_idx; \ } -void ZSOCK_FD_ZERO(zsock_fd_set *set) +int zvfs_poll_internal(struct zvfs_pollfd *fds, int nfds, k_timeout_t timeout); + +void ZVFS_FD_ZERO(struct zvfs_fd_set *set) { int i; @@ -29,11 +33,11 @@ void ZSOCK_FD_ZERO(zsock_fd_set *set) } } -int ZSOCK_FD_ISSET(int fd, zsock_fd_set *set) +int ZVFS_FD_ISSET(int fd, struct zvfs_fd_set *set) { uint32_t word_idx, bit_mask; - if (fd < 0 || fd >= ZSOCK_FD_SETSIZE) { + if (fd < 0 || fd >= ZVFS_FD_SETSIZE) { return 0; } @@ -42,11 +46,11 @@ int ZSOCK_FD_ISSET(int fd, zsock_fd_set *set) return (set->bitset[word_idx] & bit_mask) != 0U; } -void ZSOCK_FD_CLR(int fd, zsock_fd_set *set) +void ZVFS_FD_CLR(int fd, struct zvfs_fd_set *set) { uint32_t word_idx, bit_mask; - if (fd < 0 || fd >= ZSOCK_FD_SETSIZE) { + if (fd < 0 || fd >= ZVFS_FD_SETSIZE) { return; } @@ -55,11 +59,11 @@ void ZSOCK_FD_CLR(int fd, zsock_fd_set *set) set->bitset[word_idx] &= ~bit_mask; } -void ZSOCK_FD_SET(int fd, zsock_fd_set *set) +void ZVFS_FD_SET(int fd, struct zvfs_fd_set *set) { uint32_t word_idx, bit_mask; - if (fd < 0 || fd >= ZSOCK_FD_SETSIZE) { + if (fd < 0 || fd >= ZVFS_FD_SETSIZE) { return; } @@ -68,17 +72,19 @@ void ZSOCK_FD_SET(int fd, zsock_fd_set *set) set->bitset[word_idx] |= bit_mask; } -int z_impl_zsock_select(int nfds, zsock_fd_set *readfds, zsock_fd_set *writefds, - zsock_fd_set *exceptfds, struct zsock_timeval *timeout) +int z_impl_zvfs_select(int nfds, struct zvfs_fd_set *ZRESTRICT readfds, + struct zvfs_fd_set *ZRESTRICT writefds, + struct zvfs_fd_set *ZRESTRICT exceptfds, + const struct timeval *ZRESTRICT timeout) { - struct zsock_pollfd pfds[CONFIG_NET_SOCKETS_POLL_MAX]; + struct zvfs_pollfd pfds[CONFIG_ZVFS_POLL_MAX]; k_timeout_t poll_timeout; int i, res; int num_pfds = 0; int num_selects = 0; int fd_no = 0; - for (i = 0; i < STRUCT_MEMBER_ARRAY_SIZE(zsock_fd_set, bitset); i++) { + for (i = 0; i < STRUCT_MEMBER_ARRAY_SIZE(struct zvfs_fd_set, bitset); i++) { uint32_t bit_mask = 1U; uint32_t read_mask = 0U, write_mask = 0U, except_mask = 0U; uint32_t ored_mask; @@ -111,15 +117,15 @@ int z_impl_zsock_select(int nfds, zsock_fd_set *readfds, zsock_fd_set *writefds, } if (read_mask & bit_mask) { - events |= ZSOCK_POLLIN; + events |= ZVFS_POLLIN; } if (write_mask & bit_mask) { - events |= ZSOCK_POLLOUT; + events |= ZVFS_POLLOUT; } if (except_mask & bit_mask) { - events |= ZSOCK_POLLPRI; + events |= ZVFS_POLLPRI; } pfds[num_pfds].fd = fd_no; @@ -134,25 +140,24 @@ int z_impl_zsock_select(int nfds, zsock_fd_set *readfds, zsock_fd_set *writefds, if (timeout == NULL) { poll_timeout = K_FOREVER; } else { - poll_timeout = - K_USEC(timeout->tv_sec * 1000000UL + timeout->tv_usec); + poll_timeout = K_USEC(timeout->tv_sec * USEC_PER_SEC + timeout->tv_usec); } - res = zsock_poll_internal(pfds, num_pfds, poll_timeout); + res = zvfs_poll_internal(pfds, num_pfds, poll_timeout); if (res == -1) { return -1; } if (readfds != NULL) { - ZSOCK_FD_ZERO(readfds); + ZVFS_FD_ZERO(readfds); } if (writefds != NULL) { - ZSOCK_FD_ZERO(writefds); + ZVFS_FD_ZERO(writefds); } if (exceptfds != NULL) { - ZSOCK_FD_ZERO(exceptfds); + ZVFS_FD_ZERO(exceptfds); } for (i = 0; i < num_pfds && res > 0; i++) { @@ -169,21 +174,21 @@ int z_impl_zsock_select(int nfds, zsock_fd_set *readfds, zsock_fd_set *writefds, * So, unlike poll(), a single invalid fd aborts the entire * select(). */ - if (revents & ZSOCK_POLLNVAL) { + if (revents & ZVFS_POLLNVAL) { errno = EBADF; return -1; } - if (revents & ZSOCK_POLLIN) { + if (revents & ZVFS_POLLIN) { if (readfds != NULL) { - ZSOCK_FD_SET(fd, readfds); + ZVFS_FD_SET(fd, readfds); num_selects++; } } - if (revents & ZSOCK_POLLOUT) { + if (revents & ZVFS_POLLOUT) { if (writefds != NULL) { - ZSOCK_FD_SET(fd, writefds); + ZVFS_FD_SET(fd, writefds); num_selects++; } } @@ -191,14 +196,14 @@ int z_impl_zsock_select(int nfds, zsock_fd_set *readfds, zsock_fd_set *writefds, /* It's unclear if HUP/ERR belong here. At least not ignore * them. Zephyr doesn't use HUP and barely use ERR so far. */ - if (revents & (ZSOCK_POLLPRI | ZSOCK_POLLHUP | ZSOCK_POLLERR)) { + if (revents & (ZVFS_POLLPRI | ZVFS_POLLHUP | ZVFS_POLLERR)) { if (exceptfds != NULL) { - ZSOCK_FD_SET(fd, exceptfds); + ZVFS_FD_SET(fd, exceptfds); num_selects++; } if (writefds != NULL) { - ZSOCK_FD_SET(fd, writefds); + ZVFS_FD_SET(fd, writefds); num_selects++; } } @@ -210,19 +215,18 @@ int z_impl_zsock_select(int nfds, zsock_fd_set *readfds, zsock_fd_set *writefds, } #ifdef CONFIG_USERSPACE -static int z_vrfy_zsock_select(int nfds, zsock_fd_set *readfds, - zsock_fd_set *writefds, - zsock_fd_set *exceptfds, - struct zsock_timeval *timeout) +static int z_vrfy_zvfs_select(int nfds, struct zvfs_fd_set *ZRESTRICT readfds, + struct zvfs_fd_set *ZRESTRICT writefds, + struct zvfs_fd_set *ZRESTRICT exceptfds, + const struct timeval *ZRESTRICT timeout) { - zsock_fd_set *readfds_copy = NULL, *writefds_copy = NULL, - *exceptfds_copy = NULL; - struct zsock_timeval *timeval = NULL; + struct zvfs_fd_set *readfds_copy = NULL, *writefds_copy = NULL, *exceptfds_copy = NULL; + struct timeval *to = NULL; int ret = -1; if (readfds) { - readfds_copy = k_usermode_alloc_from_copy((void *)readfds, - sizeof(zsock_fd_set)); + readfds_copy = + k_usermode_alloc_from_copy((void *)readfds, sizeof(struct zvfs_fd_set)); if (!readfds_copy) { errno = ENOMEM; goto out; @@ -230,8 +234,8 @@ static int z_vrfy_zsock_select(int nfds, zsock_fd_set *readfds, } if (writefds) { - writefds_copy = k_usermode_alloc_from_copy((void *)writefds, - sizeof(zsock_fd_set)); + writefds_copy = + k_usermode_alloc_from_copy((void *)writefds, sizeof(struct zvfs_fd_set)); if (!writefds_copy) { errno = ENOMEM; goto out; @@ -239,8 +243,8 @@ static int z_vrfy_zsock_select(int nfds, zsock_fd_set *readfds, } if (exceptfds) { - exceptfds_copy = k_usermode_alloc_from_copy((void *)exceptfds, - sizeof(zsock_fd_set)); + exceptfds_copy = + k_usermode_alloc_from_copy((void *)exceptfds, sizeof(struct zvfs_fd_set)); if (!exceptfds_copy) { errno = ENOMEM; goto out; @@ -248,41 +252,39 @@ static int z_vrfy_zsock_select(int nfds, zsock_fd_set *readfds, } if (timeout) { - timeval = k_usermode_alloc_from_copy((void *)timeout, - sizeof(struct zsock_timeval)); - if (!timeval) { + to = k_usermode_alloc_from_copy((void *)timeout, sizeof(*to)); + if (!to) { errno = ENOMEM; goto out; } } - ret = z_impl_zsock_select(nfds, readfds_copy, writefds_copy, - exceptfds_copy, timeval); + ret = z_impl_zvfs_select(nfds, readfds_copy, writefds_copy, exceptfds_copy, to); if (ret >= 0) { if (readfds_copy) { k_usermode_to_copy((void *)readfds, readfds_copy, - sizeof(zsock_fd_set)); + sizeof(struct zvfs_fd_set)); } if (writefds_copy) { k_usermode_to_copy((void *)writefds, writefds_copy, - sizeof(zsock_fd_set)); + sizeof(struct zvfs_fd_set)); } if (exceptfds_copy) { k_usermode_to_copy((void *)exceptfds, exceptfds_copy, - sizeof(zsock_fd_set)); + sizeof(struct zvfs_fd_set)); } } out: - k_free(timeval); + k_free(to); k_free(readfds_copy); k_free(writefds_copy); k_free(exceptfds_copy); return ret; } -#include +#include #endif diff --git a/lib/posix/options/Kconfig.device_io b/lib/posix/options/Kconfig.device_io index 74e408313ce..e8bae34b7bd 100644 --- a/lib/posix/options/Kconfig.device_io +++ b/lib/posix/options/Kconfig.device_io @@ -10,6 +10,7 @@ config POSIX_DEVICE_IO select REQUIRES_FULL_LIBC select ZVFS select ZVFS_POLL + select ZVFS_SELECT help Select 'y' here and Zephyr will provide an implementation of the POSIX_DEVICE_IO Option Group such as FD_CLR(), FD_ISSET(), FD_SET(), FD_ZERO(), close(), fdopen(), fileno(), open(), diff --git a/lib/posix/options/device_io.c b/lib/posix/options/device_io.c index 7b638c84976..eaae1c69c79 100644 --- a/lib/posix/options/device_io.c +++ b/lib/posix/options/device_io.c @@ -10,7 +10,6 @@ #include #include #include -#include /* prototypes for external, not-yet-public, functions in fdtable.c or fs.c */ int zvfs_close(int fd); @@ -18,6 +17,26 @@ int zvfs_open(const char *name, int flags); ssize_t zvfs_read(int fd, void *buf, size_t sz, size_t *from_offset); ssize_t zvfs_write(int fd, const void *buf, size_t sz, size_t *from_offset); +void FD_CLR(int fd, struct zvfs_fd_set *fdset) +{ + return ZVFS_FD_CLR(fd, (struct zvfs_fd_set *)fdset); +} + +int FD_ISSET(int fd, struct zvfs_fd_set *fdset) +{ + return ZVFS_FD_ISSET(fd, (struct zvfs_fd_set *)fdset); +} + +void FD_SET(int fd, struct zvfs_fd_set *fdset) +{ + ZVFS_FD_SET(fd, (struct zvfs_fd_set *)fdset); +} + +void FD_ZERO(fd_set *fdset) +{ + ZVFS_FD_ZERO((struct zvfs_fd_set *)fdset); +} + int close(int fd) { return zvfs_close(fd); @@ -74,8 +93,7 @@ FUNC_ALIAS(read, _read, ssize_t); int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { - /* TODO: create zvfs_select() and dispatch to subsystems based on file type */ - return zsock_select(nfds, readfds, writefds, exceptfds, (struct zsock_timeval *)timeout); + return zvfs_select(nfds, readfds, writefds, exceptfds, timeout); } ssize_t write(int fd, const void *buf, size_t sz) diff --git a/subsys/net/lib/sockets/CMakeLists.txt b/subsys/net/lib/sockets/CMakeLists.txt index 28b76df4a7a..63710f42226 100644 --- a/subsys/net/lib/sockets/CMakeLists.txt +++ b/subsys/net/lib/sockets/CMakeLists.txt @@ -2,7 +2,6 @@ zephyr_syscall_header( ${ZEPHYR_BASE}/include/zephyr/net/socket.h - ${ZEPHYR_BASE}/include/zephyr/net/socket_select.h ) zephyr_library_include_directories(.) @@ -10,7 +9,6 @@ zephyr_library_include_directories(.) zephyr_library_sources( getaddrinfo.c sockets.c - sockets_select.c ) if(NOT CONFIG_NET_SOCKETS_OFFLOAD) diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index 09c436558a9..47192211fb8 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -7,6 +7,7 @@ menuconfig NET_SOCKETS bool "BSD Sockets compatible API" select ZVFS select ZVFS_POLL + select ZVFS_SELECT help Provide BSD Sockets like API on top of native Zephyr networking API. diff --git a/tests/posix/headers/prj.conf b/tests/posix/headers/prj.conf index 374baf4cbdf..e5c34983aea 100644 --- a/tests/posix/headers/prj.conf +++ b/tests/posix/headers/prj.conf @@ -22,3 +22,4 @@ CONFIG_POSIX_TIMERS=y CONFIG_POSIX_MESSAGE_PASSING=y CONFIG_EVENTFD=y CONFIG_POSIX_C_LIB_EXT=y +CONFIG_POSIX_DEVICE_IO=y diff --git a/tests/posix/headers/src/sys_select_h.c b/tests/posix/headers/src/sys_select_h.c index 5cca4541971..49fd4dc8ed5 100644 --- a/tests/posix/headers/src/sys_select_h.c +++ b/tests/posix/headers/src/sys_select_h.c @@ -22,12 +22,14 @@ ZTEST(posix_headers, test_sys_select_h) fd_set fds = {0}; zassert_not_equal(-1, FD_SETSIZE); - FD_CLR(0, &fds); - FD_ISSET(0, &fds); - FD_SET(0, &fds); - FD_ZERO(&fds); if (IS_ENABLED(CONFIG_POSIX_DEVICE_IO)) { + + FD_CLR(0, &fds); + FD_ISSET(0, &fds); + FD_SET(0, &fds); + FD_ZERO(&fds); + /* zassert_not_null(pselect); */ /* not implemented */ zassert_not_null(select); }