Compare commits

...

2 Commits
main ... 8.0.x

Author SHA1 Message Date
Jeff Epler
8e947f456a
Merge pull request #7592 from gneverov/lwip_threadsafe
Add LWIP thread safety sections
2023-05-02 07:19:26 -05:00
Gregory Neverov
12f5518ad6 Add LWIP thread safety sections 2023-02-15 17:58:56 -08:00
4 changed files with 81 additions and 36 deletions

View File

@ -53,12 +53,14 @@ void mdns_server_construct(mdns_server_obj_t *self, bool workflow) {
return;
}
MICROPY_PY_LWIP_ENTER;
if (!inited) {
mdns_resp_init();
inited = true;
} else {
mdns_resp_restart(NETIF_STA);
}
MICROPY_PY_LWIP_EXIT;
self->inited = true;
uint8_t mac[6];
@ -70,7 +72,9 @@ void mdns_server_construct(mdns_server_obj_t *self, bool workflow) {
// Add a second host entry to respond to "circuitpython.local" queries as well.
#if MDNS_MAX_SECONDARY_HOSTNAMES > 0
MICROPY_PY_LWIP_ENTER;
mdns_resp_add_secondary_hostname(NETIF_STA, "circuitpython");
MICROPY_PY_LWIP_EXIT;
#endif
}
}
@ -92,7 +96,9 @@ void common_hal_mdns_server_deinit(mdns_server_obj_t *self) {
}
self->inited = false;
object_inited = false;
MICROPY_PY_LWIP_ENTER;
mdns_resp_remove_netif(NETIF_STA);
MICROPY_PY_LWIP_EXIT;
}
bool common_hal_mdns_server_deinited(mdns_server_obj_t *self) {
@ -104,11 +110,13 @@ const char *common_hal_mdns_server_get_hostname(mdns_server_obj_t *self) {
}
void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *hostname) {
MICROPY_PY_LWIP_ENTER;
if (mdns_resp_netif_active(NETIF_STA)) {
mdns_resp_rename_netif(NETIF_STA, hostname);
} else {
mdns_resp_add_netif(NETIF_STA, hostname);
}
MICROPY_PY_LWIP_EXIT;
self->hostname = hostname;
}
@ -313,7 +321,9 @@ void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const cha
if (existing_slot < MDNS_MAX_SERVICES) {
mdns_resp_del_service(NETIF_STA, existing_slot);
}
MICROPY_PY_LWIP_ENTER;
int8_t slot = mdns_resp_add_service(NETIF_STA, self->instance_name, service_type, proto, port, NULL, NULL);
MICROPY_PY_LWIP_EXIT;
if (slot < 0) {
mp_raise_RuntimeError(translate("Out of MDNS service slots"));
return;

View File

@ -148,8 +148,10 @@ STATIC void lwip_socket_free_incoming(socketpool_socket_obj_t *socket) {
for (uint8_t i = 0; i < alloc; ++i) {
// Deregister callback and abort
if (tcp_array[i] != NULL) {
MICROPY_PY_LWIP_ENTER;
tcp_poll(tcp_array[i], NULL, 0);
tcp_abort(tcp_array[i]);
MICROPY_PY_LWIP_EXIT;
tcp_array[i] = NULL;
}
}
@ -283,7 +285,9 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
}
socketpool_socket_obj_t *socket = (socketpool_socket_obj_t *)arg;
MICROPY_PY_LWIP_ENTER;
tcp_recv(newpcb, _lwip_tcp_recv_unaccepted);
MICROPY_PY_LWIP_EXIT;
// Search for an empty slot to store the new connection
struct tcp_pcb *volatile *slot = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iput];
@ -302,8 +306,10 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
// The ->connected entry is repurposed to store the parent socket; this is safe
// because it's only ever used by lwIP if tcp_connect is called on the TCP PCB.
newpcb->connected = (void *)socket;
MICROPY_PY_LWIP_ENTER;
tcp_arg(newpcb, newpcb);
tcp_err(newpcb, _lwip_tcp_err_unaccepted);
MICROPY_PY_LWIP_EXIT;
return ERR_OK;
}
@ -350,11 +356,11 @@ STATIC mp_uint_t lwip_raw_udp_send(socketpool_socket_obj_t *socket, const byte *
len = 0xffff;
}
MICROPY_PY_LWIP_ENTER
MICROPY_PY_LWIP_ENTER;
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
if (p == NULL) {
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
*_errno = MP_ENOMEM;
return -1;
}
@ -384,7 +390,7 @@ STATIC mp_uint_t lwip_raw_udp_send(socketpool_socket_obj_t *socket, const byte *
pbuf_free(p);
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
// udp_sendto can return 1 on occasion for ESP8266 port. It's not known why
// but it seems that the send actually goes through without error in this case.
@ -425,13 +431,13 @@ STATIC mp_uint_t lwip_raw_udp_receive(socketpool_socket_obj_t *socket, byte *buf
struct pbuf *p = socket->incoming.pbuf;
MICROPY_PY_LWIP_ENTER
MICROPY_PY_LWIP_ENTER;
u16_t result = pbuf_copy_partial(p, buf, ((p->tot_len > len) ? len : p->tot_len), 0);
pbuf_free(p);
socket->incoming.pbuf = NULL;
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
return (mp_uint_t)result;
}
@ -459,14 +465,14 @@ STATIC mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf,
// Check for any pending errors
STREAM_ERROR_CHECK(socket);
MICROPY_PY_LWIP_ENTER
MICROPY_PY_LWIP_ENTER;
u16_t available = tcp_sndbuf(socket->pcb.tcp);
if (available == 0) {
// Non-blocking socket
if (socket->timeout == 0) {
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
*_errno = MP_EAGAIN;
return MP_STREAM_ERROR;
}
@ -479,13 +485,13 @@ STATIC mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf,
// reset) by error callback.
// Avoid sending too small packets, so wait until at least 16 bytes available
while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) {
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
if (socket->timeout != (unsigned)-1 && mp_hal_ticks_ms() - start > socket->timeout) {
*_errno = MP_ETIMEDOUT;
return MP_STREAM_ERROR;
}
poll_sockets();
MICROPY_PY_LWIP_REENTER
MICROPY_PY_LWIP_REENTER;
}
// While we waited, something could happen
@ -514,9 +520,9 @@ STATIC mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf,
if (err != ERR_OK) {
break;
}
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
mp_hal_delay_ms(50);
MICROPY_PY_LWIP_REENTER
MICROPY_PY_LWIP_REENTER;
}
// If the output buffer is getting full then send the data to the lower layers
@ -524,7 +530,7 @@ STATIC mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf,
err = tcp_output(socket->pcb.tcp);
}
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
if (err != ERR_OK) {
*_errno = error_lookup_table[-err];
@ -574,7 +580,7 @@ STATIC mp_uint_t lwip_tcp_receive(socketpool_socket_obj_t *socket, byte *buf, mp
}
}
MICROPY_PY_LWIP_ENTER
MICROPY_PY_LWIP_ENTER;
assert(socket->pcb.tcp != NULL);
@ -601,7 +607,7 @@ STATIC mp_uint_t lwip_tcp_receive(socketpool_socket_obj_t *socket, byte *buf, mp
}
tcp_recved(socket->pcb.tcp, len);
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
return len;
}
@ -680,17 +686,23 @@ bool socketpool_socket(socketpool_socketpool_obj_t *self,
switch (socket->type) {
case SOCKETPOOL_SOCK_STREAM:
MICROPY_PY_LWIP_ENTER;
socket->pcb.tcp = tcp_new();
MICROPY_PY_LWIP_EXIT;
socket->incoming.connection.alloc = 0;
socket->incoming.connection.tcp.item = NULL;
break;
case SOCKETPOOL_SOCK_DGRAM:
MICROPY_PY_LWIP_ENTER;
socket->pcb.udp = udp_new();
MICROPY_PY_LWIP_EXIT;
socket->incoming.pbuf = NULL;
break;
#if MICROPY_PY_LWIP_SOCK_RAW
case SOCKETPOOL_SOCK_RAW: {
MICROPY_PY_LWIP_ENTER;
socket->pcb.raw = raw_new(0);
MICROPY_PY_LWIP_EXIT;
break;
}
#endif
@ -704,24 +716,30 @@ bool socketpool_socket(socketpool_socketpool_obj_t *self,
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: {
MICROPY_PY_LWIP_ENTER;
// Register the socket object as our callback argument.
tcp_arg(socket->pcb.tcp, (void *)socket);
// Register our error callback.
tcp_err(socket->pcb.tcp, _lwip_tcp_error);
MICROPY_PY_LWIP_EXIT;
break;
}
case MOD_NETWORK_SOCK_DGRAM: {
socket->state = STATE_ACTIVE_UDP;
MICROPY_PY_LWIP_ENTER;
// Register our receive callback now. Since UDP sockets don't require binding or connection
// before use, there's no other good time to do it.
udp_recv(socket->pcb.udp, _lwip_udp_incoming, (void *)socket);
MICROPY_PY_LWIP_EXIT;
break;
}
#if MICROPY_PY_LWIP_SOCK_RAW
case MOD_NETWORK_SOCK_RAW: {
MICROPY_PY_LWIP_ENTER;
// Register our receive callback now. Since raw sockets don't require binding or connection
// before use, there's no other good time to do it.
raw_recv(socket->pcb.raw, _lwip_raw_incoming, (void *)socket);
MICROPY_PY_LWIP_EXIT;
break;
}
#endif
@ -755,17 +773,17 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_
return -MP_EBADF;
}
MICROPY_PY_LWIP_ENTER
MICROPY_PY_LWIP_ENTER;
if (self->pcb.tcp == NULL) {
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
return -MP_EBADF;
}
// I need to do this because "tcp_accepted", later, is a macro.
struct tcp_pcb *listener = self->pcb.tcp;
if (listener->state != LISTEN) {
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
return -MP_EINVAL;
}
@ -773,23 +791,23 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_
struct tcp_pcb *volatile *incoming_connection = &lwip_socket_incoming_array(self)[self->incoming.connection.iget];
if (*incoming_connection == NULL) {
if (self->timeout == 0) {
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
return -MP_EAGAIN;
} else if (self->timeout != (unsigned)-1) {
mp_uint_t retries = self->timeout / 100;
while (*incoming_connection == NULL && !mp_hal_is_interrupted()) {
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
if (retries-- == 0) {
return -MP_ETIMEDOUT;
}
mp_hal_delay_ms(100);
MICROPY_PY_LWIP_REENTER
MICROPY_PY_LWIP_REENTER;
}
} else {
while (*incoming_connection == NULL && !mp_hal_is_interrupted()) {
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
poll_sockets();
MICROPY_PY_LWIP_REENTER
MICROPY_PY_LWIP_REENTER;
}
}
}
@ -825,7 +843,7 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_
tcp_accepted(listener);
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
// output values
memcpy(ip, &(accepted->pcb.tcp->remote_ip), NETUTILS_IPV4ADDR_BUFSIZE);
@ -879,6 +897,7 @@ bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t *socket,
ip_set_option(socket->pcb.ip, SOF_REUSEADDR);
err_t err = ERR_ARG;
MICROPY_PY_LWIP_ENTER;
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: {
err = tcp_bind(socket->pcb.tcp, bind_addr_ptr, port);
@ -889,6 +908,7 @@ bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t *socket,
break;
}
}
MICROPY_PY_LWIP_EXIT;
if (err != ERR_OK) {
mp_raise_OSError(error_lookup_table[-err]);
@ -899,16 +919,18 @@ bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t *socket,
STATIC err_t _lwip_tcp_close_poll(void *arg, struct tcp_pcb *pcb) {
// Connection has not been cleanly closed so just abort it to free up memory
MICROPY_PY_LWIP_ENTER;
tcp_poll(pcb, NULL, 0);
tcp_abort(pcb);
MICROPY_PY_LWIP_EXIT;
return ERR_OK;
}
void socketpool_socket_close(socketpool_socket_obj_t *socket) {
unregister_open_socket(socket);
MICROPY_PY_LWIP_ENTER
MICROPY_PY_LWIP_ENTER;
if (socket->pcb.tcp == NULL) { // already closed
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
return;
}
lwip_socket_free_incoming(socket);
@ -945,7 +967,7 @@ void socketpool_socket_close(socketpool_socket_obj_t *socket) {
socket->pcb.tcp = NULL;
socket->state = _ERR_BADF;
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
}
void common_hal_socketpool_socket_close(socketpool_socket_obj_t *socket) {
@ -975,18 +997,18 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *socket,
}
// Register our receive callback.
MICROPY_PY_LWIP_ENTER
MICROPY_PY_LWIP_ENTER;
tcp_recv(socket->pcb.tcp, _lwip_tcp_recv);
socket->state = STATE_CONNECTING;
err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected);
if (err != ERR_OK) {
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
socket->state = STATE_NEW;
mp_raise_OSError(error_lookup_table[-err]);
}
socket->peer_port = (mp_uint_t)port;
memcpy(socket->peer, &dest, sizeof(socket->peer));
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
// And now we wait...
if (socket->timeout != (unsigned)-1) {
@ -1012,12 +1034,16 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *socket,
break;
}
case MOD_NETWORK_SOCK_DGRAM: {
MICROPY_PY_LWIP_ENTER;
err = udp_connect(socket->pcb.udp, &dest, port);
MICROPY_PY_LWIP_EXIT;
break;
}
#if MICROPY_PY_LWIP_SOCK_RAW
case MOD_NETWORK_SOCK_RAW: {
MICROPY_PY_LWIP_ENTER;
err = raw_connect(socket->pcb.raw, &dest);
MICROPY_PY_LWIP_EXIT;
break;
}
#endif
@ -1041,7 +1067,9 @@ bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *socket, int ba
mp_raise_OSError(MP_EOPNOTSUPP);
}
MICROPY_PY_LWIP_ENTER;
struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog);
MICROPY_PY_LWIP_EXIT;
if (new_pcb == NULL) {
mp_raise_OSError(MP_ENOMEM);
}
@ -1058,7 +1086,9 @@ bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *socket, int ba
socket->incoming.connection.iget = 0;
socket->incoming.connection.iput = 0;
MICROPY_PY_LWIP_ENTER;
tcp_accept(new_pcb, _lwip_tcp_accept);
MICROPY_PY_LWIP_EXIT;
// Socket is no longer considered "new" for purposes of polling
socket->state = STATE_LISTENING;

View File

@ -62,9 +62,9 @@ STATIC int socketpool_resolve_host(socketpool_socketpool_obj_t *self, const char
getaddrinfo_state_t state;
state.status = 0;
MICROPY_PY_LWIP_ENTER
MICROPY_PY_LWIP_ENTER;
err_t ret = dns_gethostbyname(host, (ip_addr_t *)&state.ipaddr, lwip_getaddrinfo_cb, &state);
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
switch (ret) {
case ERR_OK:

View File

@ -138,6 +138,7 @@ mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self, u
wifi_scannednetworks_obj_t *scan = m_new_obj(wifi_scannednetworks_obj_t);
scan->base.type = &wifi_scannednetworks_type;
mp_obj_t args[] = { mp_const_empty_tuple, MP_OBJ_NEW_SMALL_INT(16) };
MP_STATIC_ASSERT(MICROPY_PY_COLLECTIONS_DEQUE);
scan->results = mp_type_deque.make_new(&mp_type_deque, 2, 0, args);
self->current_scan = scan;
wifi_scannednetworks_start_scan(scan);
@ -343,11 +344,15 @@ void common_hal_wifi_radio_set_ipv4_dns(wifi_radio_obj_t *self, mp_obj_t ipv4_dn
}
void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self) {
MICROPY_PY_LWIP_ENTER;
dhcp_start(NETIF_STA);
MICROPY_PY_LWIP_EXIT;
}
void common_hal_wifi_radio_stop_dhcp_client(wifi_radio_obj_t *self) {
MICROPY_PY_LWIP_ENTER;
dhcp_stop(NETIF_STA);
MICROPY_PY_LWIP_EXIT;
}
void common_hal_wifi_radio_set_ipv4_address(wifi_radio_obj_t *self, mp_obj_t ipv4, mp_obj_t netmask, mp_obj_t gateway, mp_obj_t ipv4_dns) {
@ -398,15 +403,15 @@ mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address,
ipaddress_ipaddress_to_lwip(ip_address, &ping_addr);
struct raw_pcb *ping_pcb;
MICROPY_PY_LWIP_ENTER
MICROPY_PY_LWIP_ENTER;
ping_pcb = raw_new(IP_PROTO_ICMP);
if (!ping_pcb) {
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
return -1;
}
raw_recv(ping_pcb, ping_recv, NULL);
raw_bind(ping_pcb, IP_ADDR_ANY);
MICROPY_PY_LWIP_EXIT
MICROPY_PY_LWIP_EXIT;
ping_received = false;
ping_send(ping_pcb, &ping_addr);