From 49ac1912b29d858af6059901c2eb291e17e34a49 Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Sat, 15 Jun 2024 10:04:55 -0400 Subject: [PATCH] net: sockets: move select() implementation to zvfs Move the implementation of zsock_select() to zvfs_select(). This allows other types of file descriptors to also make use of select() functionality even when the network subsystem is not enabled. Additionally, it partially removes a dependency cycle between posix and networking by moving functionality into a mutual dependency. Signed-off-by: Chris Friedt --- include/zephyr/net/socket_select.h | 42 ++++--- include/zephyr/posix/sys/select.h | 14 ++- include/zephyr/sys/fdtable.h | 19 ++- lib/os/zvfs/CMakeLists.txt | 1 + lib/os/zvfs/Kconfig | 5 + .../os/zvfs/zvfs_select.c | 108 +++++++++--------- lib/posix/options/Kconfig.device_io | 1 + lib/posix/options/device_io.c | 24 +++- subsys/net/lib/sockets/CMakeLists.txt | 2 - subsys/net/lib/sockets/Kconfig | 1 + tests/posix/headers/prj.conf | 1 + tests/posix/headers/src/sys_select_h.c | 10 +- 12 files changed, 146 insertions(+), 82 deletions(-) rename subsys/net/lib/sockets/sockets_select.c => lib/os/zvfs/zvfs_select.c (60%) diff --git a/include/zephyr/net/socket_select.h b/include/zephyr/net/socket_select.h index 5fca2950d6a596..877bd863a6b823 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 fc61c018e249f3..e10eeb237ee0d5 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 e6cc49929dbef7..86e254a05d7d97 100644 --- a/include/zephyr/sys/fdtable.h +++ b/include/zephyr/sys/fdtable.h @@ -8,6 +8,7 @@ #include #include + /* FIXME: For native_posix ssize_t, off_t. */ #include #include @@ -207,9 +208,23 @@ struct zvfs_pollfd { __syscall int zvfs_poll(struct zvfs_pollfd *fds, int nfds, int poll_timeout); -struct zsock_fd_set { +struct zvfs_fd_set { uint32_t bitset[(CONFIG_ZVFS_OPEN_MAX + 31) / 32]; }; + +#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); + +struct timespec; +__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(). * @@ -239,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 ef0dde4513bed3..d855d1005efc6c 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 40cba2cd9c9f4a..df107c24c626db 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 60% rename from subsys/net/lib/sockets/sockets_select.c rename to lib/os/zvfs/zvfs_select.c index 49d61a2d28c659..36a8457db0fc8b 100644 --- a/subsys/net/lib/sockets/sockets_select.c +++ b/lib/os/zvfs/zvfs_select.c @@ -4,11 +4,12 @@ * 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 +21,12 @@ bit_mask = 1 << b_idx; \ } -void ZSOCK_FD_ZERO(zsock_fd_set *set) +/** Number of file descriptors which can be added to zsock_fd_set */ +#define ZVFS_FD_SETSIZE (sizeof(((struct zvfs_fd_set *)0)->bitset) * 8) + +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 +35,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 +48,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 +61,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 +74,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 +119,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 +142,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 +176,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 +198,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 +217,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 +236,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 +245,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 +254,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 9a4bbd60f45917..80447326b375e2 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 7b638c84976e7b..eaae1c69c79e11 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 253cb4a182f8c8..8e8b156260222f 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 b767a05cba5edc..43331d7141390b 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 374baf4cbdfa69..e5c34983aeaf26 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 5cca45419712dd..49fd4dc8ed5f85 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); }