Skip to content

Commit 93973e2

Browse files
cfriedtnashif
authored andcommitted
net: sockets: move poll implementation to zvfs
Move the implementation of zsock_poll to zvfs_poll. This allows other types of file descriptors to also make use of poll() 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 <[email protected]>
1 parent 2d72966 commit 93973e2

File tree

15 files changed

+276
-239
lines changed

15 files changed

+276
-239
lines changed

include/zephyr/net/socket.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,10 @@ static inline int zsock_ioctl_wrapper(int sock, unsigned long request, ...)
625625
* it may conflict with generic POSIX ``poll()`` function).
626626
* @endrst
627627
*/
628-
__syscall int zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout);
628+
static inline int zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout)
629+
{
630+
return zvfs_poll(fds, nfds, timeout);
631+
}
629632

630633
/**
631634
* @brief Get various socket options

include/zephyr/net/socket_poll.h

+3-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#ifndef ZEPHYR_INCLUDE_NET_SOCKET_POLL_H_
88
#define ZEPHYR_INCLUDE_NET_SOCKET_POLL_H_
99

10+
#include <zephyr/sys/fdtable.h>
11+
1012
/* Setting for pollfd to avoid circular inclusion */
1113

1214
/**
@@ -25,11 +27,7 @@ extern "C" {
2527
*
2628
* An array of these descriptors is passed as an argument to poll().
2729
*/
28-
struct zsock_pollfd {
29-
int fd; /**< Socket descriptor */
30-
short events; /**< Requested events */
31-
short revents; /**< Returned events */
32-
};
30+
#define zsock_pollfd zvfs_pollfd
3331

3432
#ifdef __cplusplus
3533
}

include/zephyr/sys/fdtable.h

+19
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
/* FIXME: For native_posix ssize_t, off_t. */
1212
#include <zephyr/fs/fs.h>
1313
#include <zephyr/sys/mutex.h>
14+
#include <zephyr/sys/util.h>
1415

1516
/* File mode bits */
1617
#define ZVFS_MODE_IFMT 0170000
@@ -26,6 +27,13 @@
2627
#define ZVFS_MODE_IFLNK 0120000
2728
#define ZVFS_MODE_IFSOCK 0140000
2829

30+
#define ZVFS_POLLIN BIT(0)
31+
#define ZVFS_POLLPRI BIT(1)
32+
#define ZVFS_POLLOUT BIT(2)
33+
#define ZVFS_POLLERR BIT(3)
34+
#define ZVFS_POLLHUP BIT(4)
35+
#define ZVFS_POLLNVAL BIT(5)
36+
2937
#ifdef __cplusplus
3038
extern "C" {
3139
#endif
@@ -191,6 +199,17 @@ static inline int zvfs_fdtable_call_ioctl(const struct fd_op_vtable *vtable, voi
191199
return res;
192200
}
193201

202+
struct zvfs_pollfd {
203+
int fd;
204+
short events;
205+
short revents;
206+
};
207+
208+
__syscall int zvfs_poll(struct zvfs_pollfd *fds, int nfds, int poll_timeout);
209+
210+
struct zsock_fd_set {
211+
uint32_t bitset[(CONFIG_ZVFS_OPEN_MAX + 31) / 32];
212+
};
194213
/**
195214
* Request codes for fd_op_vtable.ioctl().
196215
*

lib/os/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ zephyr_sources(
1212
)
1313

1414
zephyr_sources_ifdef(CONFIG_FDTABLE fdtable.c)
15+
zephyr_syscall_header_ifdef(CONFIG_FDTABLE
16+
${ZEPHYR_BASE}/include/zephyr/sys/fdtable.h
17+
)
1518

1619
zephyr_sources_ifdef(CONFIG_CBPRINTF_COMPLETE cbprintf_complete.c)
1720
zephyr_sources_ifdef(CONFIG_CBPRINTF_NANO cbprintf_nano.c)

lib/os/zvfs/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22

33
zephyr_library()
44
zephyr_library_sources_ifdef(CONFIG_ZVFS_EVENTFD zvfs_eventfd.c)
5+
zephyr_library_sources_ifdef(CONFIG_ZVFS_POLL zvfs_poll.c)

lib/os/zvfs/Kconfig

+19-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ if ZVFS
1616

1717
config ZVFS_EVENTFD
1818
bool "ZVFS event file descriptor support"
19-
select POLL
19+
imply ZVFS_POLL
2020
help
2121
Enable support for ZVFS event file descriptors. An eventfd can
2222
be used as an event wait/notify mechanism together with POSIX calls
@@ -33,4 +33,22 @@ config ZVFS_EVENTFD_MAX
3333

3434
endif # ZVFS_EVENTFD
3535

36+
config ZVFS_POLL
37+
bool "ZVFS poll"
38+
select POLL
39+
help
40+
Enable support for zvfs_poll().
41+
42+
if ZVFS_POLL
43+
44+
config ZVFS_POLL_MAX
45+
int "Max number of supported zvfs_poll() entries"
46+
default 6 if WIFI_NM_WPA_SUPPLICANT
47+
default 4 if SHELL_BACKEND_TELNET
48+
default 3
49+
help
50+
Maximum number of entries supported for poll() call.
51+
52+
endif # ZVFS_POLL
53+
3654
endif # ZVFS

lib/os/zvfs/zvfs_poll.c

+212
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/*
2+
* Copyright (c) 2017-2018 Linaro Limited
3+
* Copyright (c) 2021 Nordic Semiconductor
4+
* Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved.
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/internal/syscall_handler.h>
11+
#include <zephyr/sys/fdtable.h>
12+
13+
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
14+
bool net_socket_is_tls(void *obj);
15+
#else
16+
#define net_socket_is_tls(obj) false
17+
#endif
18+
19+
int zvfs_poll_internal(struct zvfs_pollfd *fds, int nfds, k_timeout_t timeout)
20+
{
21+
bool retry;
22+
int ret = 0;
23+
int i;
24+
struct zvfs_pollfd *pfd;
25+
struct k_poll_event poll_events[CONFIG_ZVFS_POLL_MAX];
26+
struct k_poll_event *pev;
27+
struct k_poll_event *pev_end = poll_events + ARRAY_SIZE(poll_events);
28+
const struct fd_op_vtable *vtable;
29+
struct k_mutex *lock;
30+
k_timepoint_t end;
31+
bool offload = false;
32+
const struct fd_op_vtable *offl_vtable = NULL;
33+
void *offl_ctx = NULL;
34+
35+
end = sys_timepoint_calc(timeout);
36+
37+
pev = poll_events;
38+
for (pfd = fds, i = nfds; i--; pfd++) {
39+
void *ctx;
40+
int result;
41+
42+
/* Per POSIX, negative fd's are just ignored */
43+
if (pfd->fd < 0) {
44+
continue;
45+
}
46+
47+
ctx = zvfs_get_fd_obj_and_vtable(pfd->fd, &vtable, &lock);
48+
if (ctx == NULL) {
49+
/* Will set POLLNVAL in return loop */
50+
continue;
51+
}
52+
53+
(void)k_mutex_lock(lock, K_FOREVER);
54+
55+
result = zvfs_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_PREPARE, pfd, &pev,
56+
pev_end);
57+
if (result == -EALREADY) {
58+
/* If POLL_PREPARE returned with EALREADY, it means
59+
* it already detected that some socket is ready. In
60+
* this case, we still perform a k_poll to pick up
61+
* as many events as possible, but without any wait.
62+
*/
63+
timeout = K_NO_WAIT;
64+
end = sys_timepoint_calc(timeout);
65+
result = 0;
66+
} else if (result == -EXDEV) {
67+
/* If POLL_PREPARE returned EXDEV, it means
68+
* it detected an offloaded socket.
69+
* If offloaded socket is used with native TLS, the TLS
70+
* wrapper for the offloaded poll will be used.
71+
* In case the fds array contains a mixup of offloaded
72+
* and non-offloaded sockets, the offloaded poll handler
73+
* shall return an error.
74+
*/
75+
offload = true;
76+
if (offl_vtable == NULL || net_socket_is_tls(ctx)) {
77+
offl_vtable = vtable;
78+
offl_ctx = ctx;
79+
}
80+
81+
result = 0;
82+
}
83+
84+
k_mutex_unlock(lock);
85+
86+
if (result < 0) {
87+
errno = -result;
88+
return -1;
89+
}
90+
}
91+
92+
if (offload) {
93+
int poll_timeout;
94+
95+
if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
96+
poll_timeout = SYS_FOREVER_MS;
97+
} else {
98+
poll_timeout = k_ticks_to_ms_floor32(timeout.ticks);
99+
}
100+
101+
return zvfs_fdtable_call_ioctl(offl_vtable, offl_ctx, ZFD_IOCTL_POLL_OFFLOAD, fds,
102+
nfds, poll_timeout);
103+
}
104+
105+
timeout = sys_timepoint_timeout(end);
106+
107+
do {
108+
ret = k_poll(poll_events, pev - poll_events, timeout);
109+
/* EAGAIN when timeout expired, EINTR when cancelled (i.e. EOF) */
110+
if (ret != 0 && ret != -EAGAIN && ret != -EINTR) {
111+
errno = -ret;
112+
return -1;
113+
}
114+
115+
retry = false;
116+
ret = 0;
117+
118+
pev = poll_events;
119+
for (pfd = fds, i = nfds; i--; pfd++) {
120+
void *ctx;
121+
int result;
122+
123+
pfd->revents = 0;
124+
125+
if (pfd->fd < 0) {
126+
continue;
127+
}
128+
129+
ctx = zvfs_get_fd_obj_and_vtable(pfd->fd, &vtable, &lock);
130+
if (ctx == NULL) {
131+
pfd->revents = ZVFS_POLLNVAL;
132+
ret++;
133+
continue;
134+
}
135+
136+
(void)k_mutex_lock(lock, K_FOREVER);
137+
138+
result = zvfs_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_UPDATE, pfd,
139+
&pev);
140+
k_mutex_unlock(lock);
141+
142+
if (result == -EAGAIN) {
143+
retry = true;
144+
continue;
145+
} else if (result != 0) {
146+
errno = -result;
147+
return -1;
148+
}
149+
150+
if (pfd->revents != 0) {
151+
ret++;
152+
}
153+
}
154+
155+
if (retry) {
156+
if (ret > 0) {
157+
break;
158+
}
159+
160+
timeout = sys_timepoint_timeout(end);
161+
162+
if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
163+
break;
164+
}
165+
}
166+
} while (retry);
167+
168+
return ret;
169+
}
170+
171+
int z_impl_zvfs_poll(struct zvfs_pollfd *fds, int nfds, int poll_timeout)
172+
{
173+
k_timeout_t timeout;
174+
175+
if (poll_timeout < 0) {
176+
timeout = K_FOREVER;
177+
} else {
178+
timeout = K_MSEC(poll_timeout);
179+
}
180+
181+
return zvfs_poll_internal(fds, nfds, timeout);
182+
}
183+
184+
#ifdef CONFIG_USERSPACE
185+
static inline int z_vrfy_zvfs_poll(struct zvfs_pollfd *fds, int nfds, int timeout)
186+
{
187+
struct zvfs_pollfd *fds_copy;
188+
size_t fds_size;
189+
int ret;
190+
191+
/* Copy fds array from user mode */
192+
if (size_mul_overflow(nfds, sizeof(struct zvfs_pollfd), &fds_size)) {
193+
errno = EFAULT;
194+
return -1;
195+
}
196+
fds_copy = k_usermode_alloc_from_copy((void *)fds, fds_size);
197+
if (!fds_copy) {
198+
errno = ENOMEM;
199+
return -1;
200+
}
201+
202+
ret = z_impl_zvfs_poll(fds_copy, nfds, timeout);
203+
204+
if (ret >= 0) {
205+
k_usermode_to_copy((void *)fds, fds_copy, fds_size);
206+
}
207+
k_free(fds_copy);
208+
209+
return ret;
210+
}
211+
#include <zephyr/syscalls/zvfs_poll_mrsh.c>
212+
#endif

lib/posix/options/Kconfig.device_io

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ menu "POSIX device I/O"
66

77
config POSIX_DEVICE_IO
88
bool "POSIX device I/O [EXPERIMENTAL]"
9-
select FDTABLE
109
select EXPERIMENTAL
1110
select REQUIRES_FULL_LIBC
11+
select ZVFS
12+
select ZVFS_POLL
1213
help
1314
Select 'y' here and Zephyr will provide an implementation of the POSIX_DEVICE_IO Option
1415
Group such as FD_CLR(), FD_ISSET(), FD_SET(), FD_ZERO(), close(), fdopen(), fileno(), open(),

lib/posix/options/device_io.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ FUNC_ALIAS(open, _open, int);
3737

3838
int poll(struct pollfd *fds, int nfds, int timeout)
3939
{
40-
/* TODO: create zvfs_poll() and dispatch to subsystems based on file type */
41-
return zsock_poll(fds, nfds, timeout);
40+
return zvfs_poll(fds, nfds, timeout);
4241
}
4342

4443
ssize_t pread(int fd, void *buf, size_t count, off_t offset)

subsys/net/lib/sockets/Kconfig

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
menuconfig NET_SOCKETS
77
bool "BSD Sockets compatible API"
8-
select FDTABLE
8+
select ZVFS
9+
select ZVFS_POLL
910
help
1011
Provide BSD Sockets like API on top of native Zephyr networking API.
1112

@@ -47,9 +48,7 @@ config NET_SOCKETS_POSIX_NAMES
4748

4849
config NET_SOCKETS_POLL_MAX
4950
int "Max number of supported poll() entries"
50-
default 6 if WIFI_NM_WPA_SUPPLICANT
51-
default 4 if SHELL_BACKEND_TELNET
52-
default 3
51+
default ZVFS_POLL_MAX
5352
help
5453
Maximum number of entries supported for poll() call.
5554

0 commit comments

Comments
 (0)