/ asyncio / event.py
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