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).
This commit is contained in:
Damien George 2019-02-22 21:54:58 +11:00
parent cc63e19332
commit 39ea132e1d
1 changed files with 33 additions and 0 deletions

View File

@ -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