From 87a7718876181ea0e6fd30a8edd032143e5f1f78 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 01:30:21 +1000 Subject: [PATCH 01/13] py/modmicropython: Add scheduler_lock/scheduler_unlock functions. --- docs/library/micropython.rst | 8 ++++++++ py/modmicropython.c | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index ded52deb0d268..d15fd2290a5c1 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -113,6 +113,14 @@ Functions incoming stream of characters that is usually used for the REPL, in case that stream is used for other purposes. +.. function:: scheduler_lock() + + Lock the scheduler. May be nested. + +.. function:: scheduler_unlock() + + Unlock the scheduler. May be nested. + .. function:: schedule(func, arg) Schedule the function *func* to be executed "very soon". The function diff --git a/py/modmicropython.c b/py/modmicropython.c index f7eadf79bd1d2..083e488b86bf8 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -155,6 +155,18 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd #endif #if MICROPY_ENABLE_SCHEDULER +STATIC mp_obj_t mp_micropython_scheduler_lock(void) { + mp_sched_lock(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_scheduler_lock_obj, mp_micropython_scheduler_lock); + +STATIC mp_obj_t mp_micropython_scheduler_unlock(void) { + mp_sched_unlock(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_scheduler_unlock_obj, mp_micropython_scheduler_unlock); + STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) { if (!mp_sched_schedule(function, arg)) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("schedule queue full")); @@ -199,6 +211,8 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_kbd_intr), MP_ROM_PTR(&mp_micropython_kbd_intr_obj) }, #endif #if MICROPY_ENABLE_SCHEDULER + { MP_ROM_QSTR(MP_QSTR_scheduler_lock), MP_ROM_PTR(&mp_micropython_scheduler_lock_obj) }, + { MP_ROM_QSTR(MP_QSTR_scheduler_unlock), MP_ROM_PTR(&mp_micropython_scheduler_unlock_obj) }, { MP_ROM_QSTR(MP_QSTR_schedule), MP_ROM_PTR(&mp_micropython_schedule_obj) }, #endif }; From 4162b6cf8a11cd1666c83bdab9434738c166a220 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 01:33:16 +1000 Subject: [PATCH 02/13] py/runtime.h: Add mp_sched_any_pending() functions. --- py/runtime.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/py/runtime.h b/py/runtime.h index 0bf988b905656..7253400c54735 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -71,8 +71,11 @@ void mp_handle_pending_tail(mp_uint_t atomic_state); #if MICROPY_ENABLE_SCHEDULER void mp_sched_lock(void); void mp_sched_unlock(void); +#define mp_sched_any_pending() (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) #define mp_sched_num_pending() (MP_STATE_VM(sched_len)) bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg); +#else +#define mp_sched_any_pending() (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) #endif // extra printing method specifically for mp_obj_t's which are integral type From f0020d9af61c57df9ea6605136927eabde64ac43 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 01:34:02 +1000 Subject: [PATCH 03/13] extmod: Add simple socketpair() implementation for bare-metal. --- extmod/modlwip.c | 5 ++ extmod/usocket_socketpair.c | 142 ++++++++++++++++++++++++++++++++++++ py/py.mk | 1 + 3 files changed, 148 insertions(+) create mode 100644 extmod/usocket_socketpair.c diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 216e81749d1c3..d3a8fcaed2ecb 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1733,10 +1733,15 @@ MP_DEFINE_CONST_FUN_OBJ_0(lwip_print_pcbs_obj, lwip_print_pcbs); #if MICROPY_PY_LWIP +MP_DECLARE_CONST_FUN_OBJ_0(mod_socket_socketpair_obj); + STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_lwip) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&mod_lwip_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&mod_lwip_callback_obj) }, + #if MICROPY_PY_USOCKET_SOCKETPAIR + { MP_ROM_QSTR(MP_QSTR_socketpair), MP_ROM_PTR(&mod_socket_socketpair_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&lwip_getaddrinfo_obj) }, { MP_ROM_QSTR(MP_QSTR_print_pcbs), MP_ROM_PTR(&lwip_print_pcbs_obj) }, // objects diff --git a/extmod/usocket_socketpair.c b/extmod/usocket_socketpair.c new file mode 100644 index 0000000000000..c5be79f613109 --- /dev/null +++ b/extmod/usocket_socketpair.c @@ -0,0 +1,142 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" + +#if MICROPY_PY_USOCKET_SOCKETPAIR + +typedef struct _mp_obj_socketpair_t { + mp_obj_base_t base; + bool blocking; + volatile size_t avail; + uint8_t buf[1]; +} mp_obj_socketpair_t; + +STATIC mp_uint_t socketpair_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_socketpair_t *self = MP_OBJ_TO_PTR(self_in); + switch (request) { + case MP_STREAM_POLL: { + uintptr_t flags = arg; + if (self->avail) { + return MP_STREAM_POLL_RD & flags; + } else { + return MP_STREAM_POLL_WR & flags; + } + } + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC mp_obj_t socketpair_recv_into(mp_obj_t self_in, mp_obj_t buf_in) { + mp_obj_socketpair_t *self = MP_OBJ_TO_PTR(self_in); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.len == 0) { + return MP_OBJ_NEW_SMALL_INT(0); + } + + if (!self->avail) { + if (!self->blocking) { + mp_raise_OSError(MP_EAGAIN); + } + while (!self->avail) { + MICROPY_EVENT_POLL_HOOK; + } + } + + ((uint8_t *)bufinfo.buf)[0] = self->buf[0]; + self->avail = 0; + + return MP_OBJ_NEW_SMALL_INT(1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpair_recv_into_obj, socketpair_recv_into); + +STATIC mp_obj_t socketpair_send(mp_obj_t self_in, mp_obj_t buf_in) { + mp_obj_socketpair_t *self = MP_OBJ_TO_PTR(self_in); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len == 0) { + return MP_OBJ_NEW_SMALL_INT(0); + } + + if (self->avail) { + return MP_OBJ_NEW_SMALL_INT(0); + } + + self->buf[0] = ((uint8_t *)bufinfo.buf)[0]; + self->avail = 1; + + return MP_OBJ_NEW_SMALL_INT(1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpair_send_obj, socketpair_send); + +STATIC mp_obj_t socketpair_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { + mp_obj_socketpair_t *self = MP_OBJ_TO_PTR(self_in); + self->blocking = mp_obj_is_true(flag_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpair_setblocking_obj, socketpair_setblocking); + +STATIC const mp_rom_map_elem_t socketpair_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_recv_into), MP_ROM_PTR(&socketpair_recv_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socketpair_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socketpair_setblocking_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(socketpair_locals_dict, socketpair_locals_dict_table); + +STATIC const mp_stream_p_t socketpair_stream_p = { + .ioctl = socketpair_ioctl, +}; + +STATIC const mp_obj_type_t mp_type_socketpair = { + { &mp_type_type }, + .name = MP_QSTR_socketpair, + .protocol = &socketpair_stream_p, + .locals_dict = (mp_obj_dict_t *)&socketpair_locals_dict, +}; + +STATIC mp_obj_t socketpair_new(void) { + mp_obj_socketpair_t *self = m_new_obj(mp_obj_socketpair_t); + self->base.type = &mp_type_socketpair; + self->blocking = true; + self->avail = 0; + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t mod_socket_socketpair(void) { + mp_obj_t s = socketpair_new(); + mp_obj_t tuple[2] = { s, s }; + return mp_obj_new_tuple(2, tuple); +} +MP_DEFINE_CONST_FUN_OBJ_0(mod_socket_socketpair_obj, mod_socket_socketpair); + +#endif // MICROPY_PY_USOCKET_SOCKETPAIR diff --git a/py/py.mk b/py/py.mk index 0a98ccc00ca0f..2f7895f122c48 100644 --- a/py/py.mk +++ b/py/py.mk @@ -202,6 +202,7 @@ PY_EXTMOD_O_BASENAME = \ extmod/vfs_fat_diskio.o \ extmod/vfs_fat_file.o \ extmod/vfs_lfs.o \ + extmod/usocket_socketpair.o \ extmod/utime_mphal.o \ extmod/uos_dupterm.o \ lib/embed/abort_.o \ From 9196c5f5fb77f44b1e788f40e18ec11372e90ef4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 01:32:06 +1000 Subject: [PATCH 04/13] stm32/mpconfigport.h: Improve MICROPY_EVENT_POLL_HOOK to not miss events --- ports/stm32/mpconfigport.h | 41 ++++++++++++++++++++++++-------- ports/stm32/usbd_hid_interface.c | 2 +- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 13dce6e96d334..b45c075d74c77 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -380,27 +380,48 @@ static inline mp_uint_t disable_irq(void) { do { \ extern void mp_handle_pending(bool); \ mp_handle_pending(true); \ - if (pyb_thread_enabled) { \ - MP_THREAD_GIL_EXIT(); \ - pyb_thread_yield(); \ - MP_THREAD_GIL_ENTER(); \ + } while (0); + +#define MICROPY_EVENT_WAIT_ATOMIC \ + do { \ + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); \ + if (!mp_sched_any_pending()) { \ + if (pyb_thread_enabled) { \ + MICROPY_END_ATOMIC_SECTION(atomic_state); \ + MP_THREAD_GIL_EXIT(); \ + pyb_thread_yield(); \ + MP_THREAD_GIL_ENTER(); \ + } else { \ + __WFI(); \ + MICROPY_END_ATOMIC_SECTION(atomic_state); \ + } \ } else { \ - __WFI(); \ + MICROPY_END_ATOMIC_SECTION(atomic_state); \ } \ - } while (0); + } while (0) #define MICROPY_THREAD_YIELD() pyb_thread_yield() #else + +#define MICROPY_EVENT_WAIT_ATOMIC \ + do { \ + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); \ + if (!mp_sched_any_pending()) { \ + __WFI(); \ + } \ + MICROPY_END_ATOMIC_SECTION(atomic_state); \ + } while (0) + +#define MICROPY_THREAD_YIELD() +#endif + #define MICROPY_EVENT_POLL_HOOK \ do { \ + MICROPY_EVENT_WAIT_ATOMIC; \ extern void mp_handle_pending(bool); \ mp_handle_pending(true); \ - __WFI(); \ } while (0); -#define MICROPY_THREAD_YIELD() -#endif - // The LwIP interface must run at a raised IRQ priority #define MICROPY_PY_LWIP_ENTER uint32_t atomic_state = raise_irq_pri(IRQ_PRI_PENDSV); #define MICROPY_PY_LWIP_REENTER atomic_state = raise_irq_pri(IRQ_PRI_PENDSV); diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c index c167fb38f2522..5d00c3a92c3b8 100644 --- a/ports/stm32/usbd_hid_interface.c +++ b/ports/stm32/usbd_hid_interface.c @@ -26,7 +26,7 @@ #include "usbd_hid_interface.h" -#include "py/mpstate.h" +#include "py/runtime.h" #include "py/mperrno.h" #include "py/mphal.h" #include "usb.h" From e8a20e24fc3e831fcd1ada12ffa6051ea30abca7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 02:02:33 +1000 Subject: [PATCH 05/13] stm32: Enable socket.socketpair(). --- ports/stm32/modusocket.c | 5 +++++ ports/stm32/mpconfigport.h | 1 + 2 files changed, 6 insertions(+) diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c index 2732d472b5cdc..d549527972444 100644 --- a/ports/stm32/modusocket.c +++ b/ports/stm32/modusocket.c @@ -445,10 +445,15 @@ STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_usocket_getaddrinfo_obj, mod_usocket_getaddrinfo); +MP_DECLARE_CONST_FUN_OBJ_0(mod_socket_socketpair_obj); + STATIC const mp_rom_map_elem_t mp_module_usocket_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) }, + #if MICROPY_PY_USOCKET_SOCKETPAIR + { MP_ROM_QSTR(MP_QSTR_socketpair), MP_ROM_PTR(&mod_socket_socketpair_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_usocket_getaddrinfo_obj) }, // class constants diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index b45c075d74c77..204d9e4700c35 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -198,6 +198,7 @@ #endif #ifndef MICROPY_PY_USOCKET #define MICROPY_PY_USOCKET (1) +#define MICROPY_PY_USOCKET_SOCKETPAIR (1) #endif #ifndef MICROPY_PY_NETWORK #define MICROPY_PY_NETWORK (1) From ea2e33ea21b8bd6b00bd034ebd588647f1eaf008 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 01:34:58 +1000 Subject: [PATCH 06/13] esp32/modsocket: Include bare-metal socketpair() function in socket mod. --- ports/esp32/modsocket.c | 5 +++++ ports/esp32/mpconfigport.h | 1 + 2 files changed, 6 insertions(+) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 85433e575fc51..94d9427fc83e6 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -829,10 +829,15 @@ STATIC mp_obj_t esp_socket_initialize() { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_socket_initialize_obj, esp_socket_initialize); +MP_DECLARE_CONST_FUN_OBJ_0(mod_socket_socketpair_obj); + STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_socket_initialize_obj) }, { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) }, + #if MICROPY_PY_USOCKET_SOCKETPAIR + { MP_ROM_QSTR(MP_QSTR_socketpair), MP_ROM_PTR(&mod_socket_socketpair_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&esp_socket_getaddrinfo_obj) }, { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) }, diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 7c09bdbd9218c..a94e94ed51650 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -160,6 +160,7 @@ #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) +#define MICROPY_PY_USOCKET_SOCKETPAIR (1) #define MICROPY_PY_BLUETOOTH_RANDOM_ADDR (1) #define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME ("ESP32") From 0be1f674b0fa4fd95dd41f0084e8914f3794fd37 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 02:01:28 +1000 Subject: [PATCH 07/13] esp8266: Enable socket.socketpair(). --- ports/esp8266/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 5344a98d6a548..198c592a81f8d 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -75,6 +75,7 @@ #define MICROPY_PY_UZLIB (1) #define MICROPY_PY_LWIP (1) #define MICROPY_PY_LWIP_SOCK_RAW (1) +#define MICROPY_PY_USOCKET_SOCKETPAIR (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_PY_MACHINE_PULSE (1) From 15a7fe9d53850e614cae6e46b2bc32e9ec2b2ffe Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 01:35:25 +1000 Subject: [PATCH 08/13] unix/modusocket: Implement socket.socketpair(). --- ports/unix/modusocket.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index 1c9ef336228a2..e068efc00beda 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -493,6 +493,17 @@ const mp_obj_type_t mp_type_socket = { .locals_dict = (mp_obj_dict_t *)&usocket_locals_dict, }; +STATIC mp_obj_t mod_socket_socketpair(void) { + MP_THREAD_GIL_EXIT(); + int fds[2]; + int r = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + MP_THREAD_GIL_ENTER(); + RAISE_ERRNO(r, errno); + mp_obj_t tuple[2] = { MP_OBJ_FROM_PTR(socket_new(fds[0])), MP_OBJ_FROM_PTR(socket_new(fds[1])) }; + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_socket_socketpair_obj, mod_socket_socketpair); + #define BINADDR_MAX_LEN sizeof(struct in6_addr) STATIC mp_obj_t mod_socket_inet_pton(mp_obj_t family_in, mp_obj_t addr_in) { int family = mp_obj_get_int(family_in); @@ -638,6 +649,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_sockaddr_obj, mod_socket_sockaddr); STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_type_socket) }, + { MP_ROM_QSTR(MP_QSTR_socketpair), MP_ROM_PTR(&mod_socket_socketpair_obj) }, { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_socket_getaddrinfo_obj) }, { MP_ROM_QSTR(MP_QSTR_inet_pton), MP_ROM_PTR(&mod_socket_inet_pton_obj) }, { MP_ROM_QSTR(MP_QSTR_inet_ntop), MP_ROM_PTR(&mod_socket_inet_ntop_obj) }, From d6a853acc9ac45b09a47a120f4cfd53028d1a50d Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 01:50:20 +1000 Subject: [PATCH 09/13] unix/modusocket: Implement socket.recv_into. --- ports/unix/modusocket.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index e068efc00beda..d41b5342812d4 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -252,6 +252,26 @@ STATIC mp_obj_t socket_recv(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_recv_obj, 2, 3, socket_recv); +STATIC mp_obj_t socket_recv_into(size_t n_args, const mp_obj_t *args) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + int flags = 0; + if (n_args > 2) { + mp_int_t sz = mp_obj_get_int(args[2]); + if (sz > 0 && (mp_uint_t)sz < bufinfo.len) { + bufinfo.len = sz; + } + if (n_args > 3) { + flags = MP_OBJ_SMALL_INT_VALUE(args[3]); + } + } + ssize_t out_sz; + MP_HAL_RETRY_SYSCALL(out_sz, recv(self->fd, bufinfo.buf, bufinfo.len, flags), mp_raise_OSError(err)); + return MP_OBJ_NEW_SMALL_INT(out_sz); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_recv_into_obj, 2, 4, socket_recv_into); + STATIC mp_obj_t socket_recvfrom(size_t n_args, const mp_obj_t *args) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]); int sz = MP_OBJ_SMALL_INT_VALUE(args[1]); @@ -465,6 +485,7 @@ STATIC const mp_rom_map_elem_t usocket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv_into), MP_ROM_PTR(&socket_recv_into_obj) }, { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, From 7147dea966bf90f7a6c30e5a7b77a516953ad421 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 01:37:11 +1000 Subject: [PATCH 10/13] extmod/uasyncio: Allow event loop to be interrupted by external signal. This is how CPython does it, using a special "self socket". --- extmod/uasyncio/core.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/extmod/uasyncio/core.py b/extmod/uasyncio/core.py index 689487d36a6fd..11a296b4fbc5a 100644 --- a/extmod/uasyncio/core.py +++ b/extmod/uasyncio/core.py @@ -68,8 +68,14 @@ def sleep(t): class IOQueue: def __init__(self): + import usocket as socket + self.poller = select.poll() self.map = {} # maps id(stream) to [task_waiting_read, task_waiting_write, stream] + self.pipe_rd, self.pipe_wr = socket.socketpair() + self.pipe_rd.setblocking(False) + self.poller.register(self.pipe_rd, select.POLLIN) + self.buf = bytearray(16) def _enqueue(self, s, idx): if id(s) not in self.map: @@ -109,8 +115,14 @@ def remove(self, task): else: break + def notify_threadsafe(self): + self.pipe_wr.send(b"\x00") + def wait_io_event(self, dt): for s, ev in self.poller.ipoll(dt): + if s is self.pipe_rd: + s.recv_into(self.buf) + continue sm = self.map[id(s)] # print('poll', s, sm, ev) if ev & ~select.POLLOUT and sm[0] is not None: @@ -160,9 +172,6 @@ def run_until_complete(main_task=None): if t: # A task waiting on _task_queue; "ph_key" is time to schedule task at dt = max(0, ticks_diff(t.ph_key, ticks())) - elif not _io_queue.map: - # No tasks can be woken so finished running - return # print('(poll {})'.format(dt), len(_io_queue.map)) _io_queue.wait_io_event(dt) From 0e207d0c7130be956bc19ed55b814187ec45425b Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 May 2020 01:38:19 +1000 Subject: [PATCH 11/13] extmod/uasyncio: Make Event scheduler-safe. So it can be set from a scheduled callback (but not a hard IRQ). TODO: work out if it can be set from another thread, probably only with the GIL enabled. --- extmod/uasyncio/event.py | 15 +++++++++++++++ extmod/uasyncio/task.py | 3 +++ 2 files changed, 18 insertions(+) diff --git a/extmod/uasyncio/event.py b/extmod/uasyncio/event.py index 31cb00e055deb..8a9cd0910cee5 100644 --- a/extmod/uasyncio/event.py +++ b/extmod/uasyncio/event.py @@ -1,9 +1,11 @@ # MicroPython uasyncio module # MIT license; Copyright (c) 2019-2020 Damien P. George +from micropython import scheduler_lock, scheduler_unlock from . import core # Event class for primitive events that can be waited on, set, and cleared +# The following methods are safe to call from a scheduled callback: is_set, set, clear class Event: def __init__(self): self.state = False # False=unset; True=set @@ -13,19 +15,32 @@ def is_set(self): return self.state def set(self): + if self.state: + return # Event becomes set, schedule any tasks waiting on it + scheduler_lock() + signal = False while self.waiting.peek(): core._task_queue.push_head(self.waiting.pop_head()) + signal = True + if signal: + # signal poll to finish + core._io_queue.notify_threadsafe() self.state = True + scheduler_unlock() def clear(self): self.state = False async def wait(self): + scheduler_lock() if not self.state: # Event not set, put the calling task on the event's waiting queue self.waiting.push_head(core.cur_task) # Set calling task's data to the event's queue so it can be removed if needed core.cur_task.data = self.waiting + scheduler_unlock() yield + else: + scheduler_unlock() return True diff --git a/extmod/uasyncio/task.py b/extmod/uasyncio/task.py index 1788cf0ed0486..8c6db0d983929 100644 --- a/extmod/uasyncio/task.py +++ b/extmod/uasyncio/task.py @@ -4,6 +4,7 @@ # This file contains the core TaskQueue based on a pairing heap, and the core Task class. # They can optionally be replaced by C implementations. +import micropython from . import core @@ -152,6 +153,7 @@ def cancel(self): # Can't cancel self (not supported yet). if self is core.cur_task: raise RuntimeError("can't cancel self") + micropython.scheduler_lock() # If Task waits on another task then forward the cancel to the one it's waiting on. while isinstance(self.data, Task): self = self.data @@ -165,4 +167,5 @@ def cancel(self): core._task_queue.remove(self) core._task_queue.push_head(self) self.data = core.CancelledError + micropython.scheduler_unlock() return True From 437ed7caea120ff299b43ec752044f35554673a4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 May 2020 19:48:17 +1000 Subject: [PATCH 12/13] py/modmicropython: Make scheduler_lock/unlock always available. --- py/modmicropython.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/py/modmicropython.c b/py/modmicropython.c index 083e488b86bf8..c105a3e1af130 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -154,19 +154,23 @@ STATIC mp_obj_t mp_micropython_kbd_intr(mp_obj_t int_chr_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd_intr); #endif -#if MICROPY_ENABLE_SCHEDULER STATIC mp_obj_t mp_micropython_scheduler_lock(void) { + #if MICROPY_ENABLE_SCHEDULER mp_sched_lock(); + #endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_scheduler_lock_obj, mp_micropython_scheduler_lock); STATIC mp_obj_t mp_micropython_scheduler_unlock(void) { + #if MICROPY_ENABLE_SCHEDULER mp_sched_unlock(); + #endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_scheduler_unlock_obj, mp_micropython_scheduler_unlock); +#if MICROPY_ENABLE_SCHEDULER STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) { if (!mp_sched_schedule(function, arg)) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("schedule queue full")); @@ -210,9 +214,9 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { #if MICROPY_KBD_EXCEPTION { MP_ROM_QSTR(MP_QSTR_kbd_intr), MP_ROM_PTR(&mp_micropython_kbd_intr_obj) }, #endif - #if MICROPY_ENABLE_SCHEDULER { MP_ROM_QSTR(MP_QSTR_scheduler_lock), MP_ROM_PTR(&mp_micropython_scheduler_lock_obj) }, { MP_ROM_QSTR(MP_QSTR_scheduler_unlock), MP_ROM_PTR(&mp_micropython_scheduler_unlock_obj) }, + #if MICROPY_ENABLE_SCHEDULER { MP_ROM_QSTR(MP_QSTR_schedule), MP_ROM_PTR(&mp_micropython_schedule_obj) }, #endif }; From 66f197b1472b45b13d2080de476ef16002772e76 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 May 2020 21:39:02 +1000 Subject: [PATCH 13/13] stm32/mpconfigport.h: Fix duplicate EVENT_POLL_HOOK when thread enabled. --- ports/stm32/mpconfigport.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 204d9e4700c35..a253fcf69ec10 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -377,12 +377,6 @@ static inline mp_uint_t disable_irq(void) { #define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) #if MICROPY_PY_THREAD -#define MICROPY_EVENT_POLL_HOOK \ - do { \ - extern void mp_handle_pending(bool); \ - mp_handle_pending(true); \ - } while (0); - #define MICROPY_EVENT_WAIT_ATOMIC \ do { \ mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); \ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy