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 <cfriedt@tenstorrent.com>
This commit is contained in:
Chris Friedt 2024-07-26 22:41:12 -04:00 committed by Henrik Brix Andersen
commit b3d3d4fff7
12 changed files with 148 additions and 83 deletions

View file

@ -19,17 +19,18 @@
* @{
*/
#include <time.h>
#include <zephyr/toolchain.h>
#include <zephyr/net/socket_types.h>
#include <zephyr/sys/fdtable.h>
#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 <zephyr/syscalls/socket_select.h>
/**
* @}
*/

View file

@ -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
}

View file

@ -7,9 +7,10 @@
#define ZEPHYR_INCLUDE_SYS_FDTABLE_H_
#include <stdarg.h>
#include <sys/types.h>
#include <time.h>
/* FIXME: For native_posix ssize_t, off_t. */
#include <zephyr/fs/fs.h>
#include <sys/types.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
@ -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 <zephyr/syscalls/fdtable.h>
#endif /* ZEPHYR_INCLUDE_SYS_FDTABLE_H_ */

View file

@ -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)

View file

@ -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

View file

@ -1,14 +1,16 @@
/*
* Copyright (c) 2018 Linaro Limited
* Copyright (c) 2024 Tenstorrent AI ULC
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <zephyr/kernel.h>
#include <zephyr/internal/syscall_handler.h>
#include <zephyr/sys/math_extras.h>
#include <zephyr/net/socket.h>
#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 <zephyr/syscalls/zsock_select_mrsh.c>
#include <zephyr/syscalls/zvfs_select_mrsh.c>
#endif

View file

@ -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(),

View file

@ -10,7 +10,6 @@
#include <zephyr/posix/poll.h>
#include <zephyr/posix/unistd.h>
#include <zephyr/posix/sys/select.h>
#include <zephyr/posix/sys/socket.h>
/* 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)

View file

@ -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)

View file

@ -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.

View file

@ -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

View file

@ -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);
}