diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 6960546f68..d501f4be2a 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -859,15 +859,28 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen); STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); - if (socket->pcb.tcp == NULL) { - mp_raise_OSError(MP_EBADF); - } if (socket->type != MOD_NETWORK_SOCK_STREAM) { mp_raise_OSError(MP_EOPNOTSUPP); } + + // Create new socket object, do it here because we must not raise an out-of-memory + // exception when the LWIP concurrency lock is held + lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t); + socket2->base.type = &lwip_socket_type; + + MICROPY_PY_LWIP_ENTER + + if (socket->pcb.tcp == NULL) { + MICROPY_PY_LWIP_EXIT + m_del_obj(lwip_socket_obj_t, socket2); + mp_raise_OSError(MP_EBADF); + } + // I need to do this because "tcp_accepted", later, is a macro. struct tcp_pcb *listener = socket->pcb.tcp; if (listener->state != LISTEN) { + MICROPY_PY_LWIP_EXIT + m_del_obj(lwip_socket_obj_t, socket2); mp_raise_OSError(MP_EINVAL); } @@ -875,26 +888,29 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { struct tcp_pcb *volatile *incoming_connection = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iget]; if (*incoming_connection == NULL) { if (socket->timeout == 0) { + MICROPY_PY_LWIP_EXIT + m_del_obj(lwip_socket_obj_t, socket2); mp_raise_OSError(MP_EAGAIN); } else if (socket->timeout != -1) { - for (mp_uint_t retries = socket->timeout / 100; retries--;) { + mp_uint_t retries = socket->timeout / 100; + while (*incoming_connection == NULL) { + MICROPY_PY_LWIP_EXIT + if (retries-- == 0) { + m_del_obj(lwip_socket_obj_t, socket2); + mp_raise_OSError(MP_ETIMEDOUT); + } mp_hal_delay_ms(100); - if (*incoming_connection != NULL) break; - } - if (*incoming_connection == NULL) { - mp_raise_OSError(MP_ETIMEDOUT); + MICROPY_PY_LWIP_REENTER } } else { while (*incoming_connection == NULL) { + MICROPY_PY_LWIP_EXIT poll_sockets(); + MICROPY_PY_LWIP_REENTER } } } - // create new socket object - lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t); - socket2->base.type = &lwip_socket_type; - // We get a new pcb handle... socket2->pcb.tcp = *incoming_connection; if (++socket->incoming.connection.iget >= socket->incoming.connection.alloc) { @@ -916,6 +932,8 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { tcp_accepted(listener); + MICROPY_PY_LWIP_EXIT + // make the return value uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip));