From 39ea132e1daf851b962780cf122f41800b9e9a33 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Feb 2019 21:54:58 +1100 Subject: [PATCH] extmod/modlwip: Add concurrency protection macros. Some users of this module may require the LwIP stack to run at an elevated priority, to protect against concurrency issues with processing done by the underlying network interface. Since LwIP doesn't provide such protection it must be done here (the other option is to run LwIP in a separate thread, and use thread protection mechanisms, but that is a more heavyweight solution). --- extmod/modlwip.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index bd952111d6..83104a487f 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -447,9 +447,12 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui len = 0xffff; } + MICROPY_PY_LWIP_ENTER + // FIXME: maybe PBUF_ROM? struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); if (p == NULL) { + MICROPY_PY_LWIP_EXIT *_errno = MP_ENOMEM; return -1; } @@ -467,6 +470,8 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui pbuf_free(p); + 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. // So we treat such cases as a success until further investigation. @@ -505,10 +510,14 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ struct pbuf *p = socket->incoming.pbuf; + 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 + return (mp_uint_t) result; } @@ -526,11 +535,14 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui // Check for any pending errors STREAM_ERROR_CHECK(socket); + 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 *_errno = MP_EAGAIN; return MP_STREAM_ERROR; } @@ -543,11 +555,13 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui // 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 if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { *_errno = MP_ETIMEDOUT; return MP_STREAM_ERROR; } poll_sockets(); + MICROPY_PY_LWIP_REENTER } // While we waited, something could happen @@ -563,6 +577,8 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui err = tcp_output(socket->pcb.tcp); } + MICROPY_PY_LWIP_EXIT + if (err != ERR_OK) { *_errno = error_lookup_table[-err]; return MP_STREAM_ERROR; @@ -608,6 +624,8 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ } } + MICROPY_PY_LWIP_ENTER + assert(socket->pcb.tcp != NULL); struct pbuf *p = socket->incoming.pbuf; @@ -633,6 +651,8 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ } tcp_recved(socket->pcb.tcp, len); + MICROPY_PY_LWIP_EXIT + return len; } @@ -865,16 +885,21 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { mp_raise_OSError(MP_EALREADY); } } + // Register our receive callback. + 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 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 + // And now we wait... if (socket->timeout != -1) { for (mp_uint_t retries = socket->timeout / 100; retries--;) { @@ -1209,6 +1234,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; + MICROPY_PY_LWIP_ENTER + if (request == MP_STREAM_POLL) { uintptr_t flags = arg; ret = 0; @@ -1259,6 +1286,7 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ bool socket_is_listener = false; if (socket->pcb.tcp == NULL) { + MICROPY_PY_LWIP_EXIT return 0; } @@ -1305,6 +1333,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ ret = MP_STREAM_ERROR; } + MICROPY_PY_LWIP_EXIT + return ret; } @@ -1452,7 +1482,10 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) { getaddrinfo_state_t state; state.status = 0; + MICROPY_PY_LWIP_ENTER err_t ret = dns_gethostbyname(host, (ip_addr_t*)&state.ipaddr, lwip_getaddrinfo_cb, &state); + MICROPY_PY_LWIP_EXIT + switch (ret) { case ERR_OK: // cached