Skip to content

Commit 4e6fa55

Browse files
authored
Merge pull request #6591 from tannewt/web_workflow_ticks
Add socket select task to wake CP
2 parents bad080a + c2a8ef7 commit 4e6fa55

File tree

11 files changed

+243
-101
lines changed

11 files changed

+243
-101
lines changed

ports/espressif/background.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,12 @@
4040
#include "common-hal/pulseio/PulseIn.h"
4141
#endif
4242

43-
#if CIRCUITPY_WEB_WORKFLOW
44-
#include "supervisor/shared/web_workflow/web_workflow.h"
45-
#endif
46-
4743
void port_background_task(void) {
4844
// Zero delay in case FreeRTOS wants to switch to something else.
4945
vTaskDelay(0);
5046
#if CIRCUITPY_PULSEIO
5147
pulsein_background();
5248
#endif
53-
54-
#if CIRCUITPY_WEB_WORKFLOW
55-
supervisor_web_workflow_background();
56-
#endif
5749
}
5850

5951
void port_start_background_task(void) {

ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
1515
CIRCUITPY_ESP_FLASH_MODE = qio
1616
CIRCUITPY_ESP_FLASH_FREQ = 40m
1717
CIRCUITPY_ESP_FLASH_SIZE = 4MB
18+
19+
CIRCUITPY_PS2IO = 0

ports/espressif/boards/adafruit_feather_esp32s3_tft/mpconfigboard.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
1616
CIRCUITPY_ESP_FLASH_MODE = dio
1717
CIRCUITPY_ESP_FLASH_FREQ = 40m
1818
CIRCUITPY_ESP_FLASH_SIZE = 4MB
19+
20+
CIRCUITPY_PS2IO = 0

ports/espressif/common-hal/mdns/Server.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ const char *common_hal_mdns_server_get_hostname(mdns_server_obj_t *self) {
9090

9191
void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *hostname) {
9292
mdns_hostname_set(hostname);
93+
// Wait for the mdns task to set the new hostname.
94+
while (!mdns_hostname_exists(hostname)) {
95+
RUN_BACKGROUND_TASKS;
96+
}
9397
self->hostname = hostname;
9498
}
9599

ports/espressif/common-hal/socketpool/Socket.c

Lines changed: 194 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,38 +30,213 @@
3030
#include "shared/runtime/interrupt_char.h"
3131
#include "py/mperrno.h"
3232
#include "py/runtime.h"
33+
#include "shared-bindings/socketpool/SocketPool.h"
34+
#include "supervisor/port.h"
3335
#include "supervisor/shared/tick.h"
36+
#include "supervisor/workflow.h"
3437

3538
#include "components/lwip/lwip/src/include/lwip/err.h"
3639
#include "components/lwip/lwip/src/include/lwip/sockets.h"
3740
#include "components/lwip/lwip/src/include/lwip/sys.h"
3841
#include "components/lwip/lwip/src/include/lwip/netdb.h"
42+
#include "components/vfs/include/esp_vfs_eventfd.h"
43+
44+
StackType_t socket_select_stack[2 * configMINIMAL_STACK_SIZE];
45+
46+
STATIC int open_socket_fds[CONFIG_LWIP_MAX_SOCKETS];
47+
STATIC bool user_socket[CONFIG_LWIP_MAX_SOCKETS];
48+
StaticTask_t socket_select_task_handle;
49+
STATIC int socket_change_fd = -1;
50+
51+
STATIC void socket_select_task(void *arg) {
52+
uint64_t signal;
53+
54+
while (true) {
55+
fd_set readfds;
56+
fd_set errfds;
57+
FD_ZERO(&readfds);
58+
FD_ZERO(&errfds);
59+
FD_SET(socket_change_fd, &readfds);
60+
FD_SET(socket_change_fd, &errfds);
61+
int max_fd = socket_change_fd;
62+
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
63+
if (open_socket_fds[i] < 0) {
64+
continue;
65+
}
66+
max_fd = MAX(max_fd, open_socket_fds[i]);
67+
FD_SET(open_socket_fds[i], &readfds);
68+
FD_SET(open_socket_fds[i], &errfds);
69+
}
70+
71+
int num_triggered = select(max_fd + 1, &readfds, NULL, &errfds, NULL);
72+
if (num_triggered < 0) {
73+
// Maybe bad file descriptor
74+
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
75+
int sockfd = open_socket_fds[i];
76+
if (sockfd < 0) {
77+
continue;
78+
}
79+
if (FD_ISSET(sockfd, &errfds)) {
80+
int err;
81+
int optlen = sizeof(int);
82+
int ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, (socklen_t *)&optlen);
83+
if (ret < 0) {
84+
open_socket_fds[i] = -1;
85+
// Try again.
86+
continue;
87+
}
88+
}
89+
}
90+
}
91+
assert(num_triggered >= 0);
92+
93+
if (FD_ISSET(socket_change_fd, &readfds)) {
94+
read(socket_change_fd, &signal, sizeof(signal));
95+
num_triggered -= 1;
96+
}
97+
if (num_triggered > 0) {
98+
supervisor_workflow_request_background();
3999

40-
STATIC socketpool_socket_obj_t *open_socket_handles[CONFIG_LWIP_MAX_SOCKETS];
100+
// Wake up CircuitPython. We know it is asleep because we are lower
101+
// priority.
102+
port_wake_main_task();
103+
}
104+
105+
}
106+
close(socket_change_fd);
107+
vTaskDelete(NULL);
108+
}
41109

42110
void socket_user_reset(void) {
43-
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
44-
if (open_socket_handles[i]) {
45-
if (open_socket_handles[i]->num > 0) {
46-
// Close automatically clears socket handle
47-
common_hal_socketpool_socket_close(open_socket_handles[i]);
48-
} else {
49-
open_socket_handles[i] = NULL;
50-
}
111+
if (socket_change_fd < 0) {
112+
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
113+
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&config));
114+
115+
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
116+
open_socket_fds[i] = -1;
117+
user_socket[i] = false;
118+
}
119+
socket_change_fd = eventfd(0, 0);
120+
// This task runs at a lower priority than CircuitPython and is used to wake CircuitPython
121+
// up when any open sockets have data to read. It allows us to sleep otherwise.
122+
(void)xTaskCreateStaticPinnedToCore(socket_select_task,
123+
"socket_select",
124+
2 * configMINIMAL_STACK_SIZE,
125+
NULL,
126+
0, // Run this at IDLE priority. We only need it when CP isn't running (at 1).
127+
socket_select_stack,
128+
&socket_select_task_handle,
129+
xPortGetCoreID());
130+
}
131+
132+
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
133+
if (open_socket_fds[i] >= 0 && user_socket[i]) {
134+
int num = open_socket_fds[i];
135+
// Close automatically clears socket handle
136+
lwip_shutdown(num, SHUT_RDWR);
137+
lwip_close(num);
138+
open_socket_fds[i] = -1;
139+
user_socket[i] = false;
51140
}
52141
}
53142
}
54143

55-
bool register_open_socket(socketpool_socket_obj_t *self) {
56-
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
57-
if (open_socket_handles[i] == NULL) {
58-
open_socket_handles[i] = self;
144+
// The writes below send an event to the socket select task so that it redoes the
145+
// select with the new open socket set.
146+
147+
STATIC bool register_open_socket(int fd) {
148+
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
149+
if (open_socket_fds[i] == -1) {
150+
open_socket_fds[i] = fd;
151+
user_socket[i] = false;
152+
uint64_t signal = 1;
153+
write(socket_change_fd, &signal, sizeof(signal));
59154
return true;
60155
}
61156
}
62157
return false;
63158
}
64159

160+
STATIC void unregister_open_socket(int fd) {
161+
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
162+
if (open_socket_fds[i] == fd) {
163+
open_socket_fds[i] = -1;
164+
user_socket[i] = false;
165+
write(socket_change_fd, &fd, sizeof(fd));
166+
return;
167+
}
168+
}
169+
}
170+
171+
STATIC void mark_user_socket(int fd) {
172+
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
173+
if (open_socket_fds[i] == fd) {
174+
user_socket[i] = true;
175+
return;
176+
}
177+
}
178+
}
179+
180+
bool socketpool_socket(socketpool_socketpool_obj_t *self,
181+
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type,
182+
socketpool_socket_obj_t *sock) {
183+
int addr_family;
184+
int ipproto;
185+
if (family == SOCKETPOOL_AF_INET) {
186+
addr_family = AF_INET;
187+
ipproto = IPPROTO_IP;
188+
} else { // INET6
189+
addr_family = AF_INET6;
190+
ipproto = IPPROTO_IPV6;
191+
}
192+
193+
int socket_type;
194+
if (type == SOCKETPOOL_SOCK_STREAM) {
195+
socket_type = SOCK_STREAM;
196+
} else if (type == SOCKETPOOL_SOCK_DGRAM) {
197+
socket_type = SOCK_DGRAM;
198+
} else { // SOCKETPOOL_SOCK_RAW
199+
socket_type = SOCK_RAW;
200+
}
201+
sock->type = socket_type;
202+
sock->family = addr_family;
203+
sock->ipproto = ipproto;
204+
sock->pool = self;
205+
sock->timeout_ms = (uint)-1;
206+
207+
// Create LWIP socket
208+
int socknum = -1;
209+
socknum = lwip_socket(sock->family, sock->type, sock->ipproto);
210+
if (socknum < 0) {
211+
return false;
212+
}
213+
// This shouldn't happen since we have room for the same number of sockets as LWIP.
214+
if (!register_open_socket(socknum)) {
215+
lwip_close(socknum);
216+
return false;
217+
}
218+
sock->num = socknum;
219+
// Sockets should be nonblocking in most cases
220+
lwip_fcntl(socknum, F_SETFL, O_NONBLOCK);
221+
return true;
222+
}
223+
224+
socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_t *self,
225+
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type) {
226+
if (family != SOCKETPOOL_AF_INET) {
227+
mp_raise_NotImplementedError(translate("Only IPv4 sockets supported"));
228+
}
229+
230+
socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t);
231+
sock->base.type = &socketpool_socket_type;
232+
233+
if (!socketpool_socket(self, family, type, sock)) {
234+
mp_raise_RuntimeError(translate("Out of sockets"));
235+
}
236+
mark_user_socket(sock->num);
237+
return sock;
238+
}
239+
65240
int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_t *port) {
66241
struct sockaddr_in accept_addr;
67242
socklen_t socklen = sizeof(accept_addr);
@@ -92,6 +267,10 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_
92267
if (newsoc < 0) {
93268
return -MP_EBADF;
94269
}
270+
if (!register_open_socket(newsoc)) {
271+
lwip_close(newsoc);
272+
return -MP_EBADF;
273+
}
95274
return newsoc;
96275
}
97276

@@ -100,17 +279,14 @@ socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_o
100279
int newsoc = socketpool_socket_accept(self, ip, port);
101280

102281
if (newsoc > 0) {
282+
mark_user_socket(newsoc);
103283
// Create the socket
104284
socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t);
105285
sock->base.type = &socketpool_socket_type;
106286
sock->num = newsoc;
107287
sock->pool = self->pool;
108288
sock->connected = true;
109289

110-
if (!register_open_socket(sock)) {
111-
mp_raise_OSError(MP_EBADF);
112-
}
113-
114290
lwip_fcntl(newsoc, F_SETFL, O_NONBLOCK);
115291
return sock;
116292
} else {
@@ -150,18 +326,13 @@ void socketpool_socket_close(socketpool_socket_obj_t *self) {
150326
if (self->num >= 0) {
151327
lwip_shutdown(self->num, SHUT_RDWR);
152328
lwip_close(self->num);
329+
unregister_open_socket(self->num);
153330
self->num = -1;
154331
}
155332
}
156333

157334
void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self) {
158335
socketpool_socket_close(self);
159-
// Remove socket record
160-
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
161-
if (open_socket_handles[i] == self) {
162-
open_socket_handles[i] = NULL;
163-
}
164-
}
165336
}
166337

167338
void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self,

ports/espressif/common-hal/socketpool/Socket.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,5 @@ typedef struct {
4646
} socketpool_socket_obj_t;
4747

4848
void socket_user_reset(void);
49-
bool register_open_socket(socketpool_socket_obj_t *self);
5049

5150
#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL_SOCKET_H

ports/espressif/common-hal/socketpool/SocketPool.c

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -40,61 +40,7 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel
4040
}
4141
}
4242

43-
bool socketpool_socket(socketpool_socketpool_obj_t *self,
44-
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type,
45-
socketpool_socket_obj_t *sock) {
46-
int addr_family;
47-
int ipproto;
48-
if (family == SOCKETPOOL_AF_INET) {
49-
addr_family = AF_INET;
50-
ipproto = IPPROTO_IP;
51-
} else { // INET6
52-
addr_family = AF_INET6;
53-
ipproto = IPPROTO_IPV6;
54-
}
55-
56-
int socket_type;
57-
if (type == SOCKETPOOL_SOCK_STREAM) {
58-
socket_type = SOCK_STREAM;
59-
} else if (type == SOCKETPOOL_SOCK_DGRAM) {
60-
socket_type = SOCK_DGRAM;
61-
} else { // SOCKETPOOL_SOCK_RAW
62-
socket_type = SOCK_RAW;
63-
}
64-
sock->type = socket_type;
65-
sock->family = addr_family;
66-
sock->ipproto = ipproto;
67-
sock->pool = self;
68-
sock->timeout_ms = (uint)-1;
69-
70-
// Create LWIP socket
71-
int socknum = -1;
72-
socknum = lwip_socket(sock->family, sock->type, sock->ipproto);
73-
if (socknum < 0) {
74-
return false;
75-
}
76-
sock->num = socknum;
77-
// Sockets should be nonblocking in most cases
78-
lwip_fcntl(socknum, F_SETFL, O_NONBLOCK);
79-
return true;
80-
}
81-
82-
socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_t *self,
83-
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type) {
84-
if (family != SOCKETPOOL_AF_INET) {
85-
mp_raise_NotImplementedError(translate("Only IPv4 sockets supported"));
86-
}
87-
88-
socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t);
89-
sock->base.type = &socketpool_socket_type;
90-
91-
if (!socketpool_socket(self, family, type, sock) ||
92-
!register_open_socket(sock)) {
93-
mp_raise_RuntimeError(translate("Out of sockets"));
94-
}
95-
return sock;
96-
}
97-
43+
// common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking.
9844

9945
mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self,
10046
const char *host) {

ports/espressif/esp-idf

0 commit comments

Comments
 (0)