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/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/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) 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 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/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") 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) 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 13dce6e96d334..a253fcf69ec10 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) @@ -376,31 +377,46 @@ 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 \ +#define MICROPY_EVENT_WAIT_ATOMIC \ 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(); \ + 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" diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index 1c9ef336228a2..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) }, @@ -493,6 +514,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 +670,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) }, diff --git a/py/modmicropython.c b/py/modmicropython.c index f7eadf79bd1d2..c105a3e1af130 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -154,6 +154,22 @@ 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 +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)) { @@ -198,6 +214,8 @@ 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 + { 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 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 \ 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
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: