event.py
1 # SPDX-FileCopyrightText: 2019-2020 Damien P. George 2 # 3 # SPDX-License-Identifier: MIT 4 # 5 # MicroPython uasyncio module 6 # MIT license; Copyright (c) 2019-2020 Damien P. George 7 # 8 # This code comes from MicroPython, and has not been run through black or pylint there. 9 # Altering these files significantly would make merging difficult, so we will not use 10 # pylint or black. 11 # pylint: skip-file 12 # fmt: off 13 """ 14 Events 15 ====== 16 """ 17 18 from . import core 19 20 # Event class for primitive events that can be waited on, set, and cleared 21 class Event: 22 """Create a new event which can be used to synchronize tasks. Events 23 start in the cleared state. 24 """ 25 26 def __init__(self): 27 self.state = False # False=unset; True=set 28 self.waiting = ( 29 core.TaskQueue() 30 ) # Queue of Tasks waiting on completion of this event 31 32 def is_set(self): 33 """Returns ``True`` if the event is set, ``False`` otherwise.""" 34 35 return self.state 36 37 def set(self): 38 """Set the event. Any tasks waiting on the event will be scheduled to run. 39 """ 40 41 # Event becomes set, schedule any tasks waiting on it 42 # Note: This must not be called from anything except the thread running 43 # the asyncio loop (i.e. neither hard or soft IRQ, or a different thread). 44 while self.waiting.peek(): 45 core._task_queue.push_head(self.waiting.pop_head()) 46 self.state = True 47 48 def clear(self): 49 """Clear the event.""" 50 51 self.state = False 52 53 async def wait(self): 54 """Wait for the event to be set. If the event is already set then it returns 55 immediately. 56 57 This is a coroutine. 58 """ 59 60 if not self.state: 61 # Event not set, put the calling task on the event's waiting queue 62 self.waiting.push_head(core.cur_task) 63 # Set calling task's data to the event's queue so it can be removed if needed 64 core.cur_task.data = self.waiting 65 await core.sleep(0) 66 return True 67 68 69 # MicroPython-extension: This can be set from outside the asyncio event loop, 70 # such as other threads, IRQs or scheduler context. Implementation is a stream 71 # that asyncio will poll until a flag is set. 72 # Note: Unlike Event, this is self-clearing. 73 try: 74 import uio 75 76 class ThreadSafeFlag(uio.IOBase): 77 def __init__(self): 78 self._flag = 0 79 80 def ioctl(self, req, flags): 81 if req == 3: # MP_STREAM_POLL 82 return self._flag * flags 83 return None 84 85 def set(self): 86 self._flag = 1 87 88 async def wait(self): 89 if not self._flag: 90 yield core._io_queue.queue_read(self) 91 self._flag = 0 92 93 94 except ImportError: 95 pass