@@ -7,6 +7,24 @@ please raise an issue. None of this information is required to use the library:
7
7
it is intended to satisfy the curiosity of scheduler geeks or to help those
8
8
wishing to modify it.
9
9
10
+ # 0. Contents
11
+
12
+ 1 . [ Introduction] ( ./UNDER_THE_HOOD.md#1-introduction )
13
+ 2 . [ Generators and coroutines] ( ./UNDER_THE_HOOD.md#2-generators-and-coroutines )
14
+ 3 . [ Coroutine yield types] ( ./UNDER_THE_HOOD.md#3-coroutine-yield-types )
15
+ 3.1 [ SysCall1 classes] (SysCall1 classes)
16
+ 4 . [ The EventLoop] ( ./UNDER_THE_HOOD.md#4-the-eventloop )
17
+ 4.1 [ Exceptions] ( ./UNDER_THE_HOOD.md#41-exceptions )
18
+ 4.2 [ Task Cancellation] ( ./UNDER_THE_HOOD.md#42-task-cancellation )
19
+ 5 . [ Stream I/O] ( ./UNDER_THE_HOOD.md#5-stream-i/o )
20
+ 5.1 [ StreamReader] ( ./UNDER_THE_HOOD.md#51-streamreader )
21
+ 5.2 [ StreamWriter] ( ./UNDER_THE_HOOD.md#52-streamwriter )
22
+ 5.3 [ PollEventLoop.wait] ( ./UNDER_THE_HOOD.md#53-polleventloop.wait )
23
+ 6 . [ Debug code] ( ./UNDER_THE_HOOD.md#6-debug-code )
24
+ 7 . [ Modifying uasyncio] ( ./UNDER_THE_HOOD.md#7-modifying-uasyncio )
25
+
26
+ # 1. Introduction
27
+
10
28
Where the versions differ, this explanation relates to the ` fast_io ` version.
11
29
Differences are largely in ` __init__.py ` : the scheduling algorithm in ` core.py `
12
30
is little changed. Note that the code in ` fast_io ` contains additional comments
@@ -37,7 +55,7 @@ This has additional comments to aid in its understanding.
37
55
38
56
###### [ Main README] ( ./README.md )
39
57
40
- # Generators and coroutines
58
+ # 2. Generators and coroutines
41
59
42
60
In MicroPython coroutines and generators are identical: this differs from
43
61
CPython. The knowledge that a coro is a generator is crucial to understanding
@@ -62,7 +80,9 @@ creates a generator and transfers execution to it via `yield from`. The
62
80
generator yields a value of 1000; this is passed to the scheduler to invoke the
63
81
delay (see below).
64
82
65
- # Coroutine yield types
83
+ ###### [ Contents] ( ./UNDER_THE_HOOD.md#0-contents )
84
+
85
+ # 3. Coroutine yield types
66
86
67
87
Because coroutines are generators it is valid to issue ` yield ` in a coroutine,
68
88
behaviour which would cause a syntax error in CPython. While explicitly issuing
@@ -95,7 +115,7 @@ the type of that object. The following object types are handled:
95
115
` yield ` is rescheduled.
96
116
* A ` SysCall1 ` instance. See below.
97
117
98
- ## SysCall1 classes
118
+ ## 3.1 SysCall1 classes
99
119
100
120
The ` SysCall1 ` constructor takes a single argument stored in ` self.arg ` . It is
101
121
effectively an abstract base class: only subclasses are instantiated. When a
@@ -117,7 +137,9 @@ The following subclasses exist:
117
137
The ` IO* ` classes are for the exclusive use of ` StreamReader ` and ` StreamWriter `
118
138
objects.
119
139
120
- # The EventLoop
140
+ ###### [ Contents] ( ./UNDER_THE_HOOD.md#0-contents )
141
+
142
+ # 4. The EventLoop
121
143
122
144
The file ` core.py ` defines an ` EventLoop ` class which is subclassed by
123
145
` PollEventLoop ` in ` __init__.py ` . The latter extends the base class to support
@@ -168,7 +190,9 @@ The `.wait()` method is called with this delay. If the delay is > 0 the
168
190
scheduler pauses for this period (polling I/O). On a zero delay I/O is checked
169
191
once: if nothing is pending it returns quickly.
170
192
171
- ## Exceptions
193
+ ###### [ Contents] ( ./UNDER_THE_HOOD.md#0-contents )
194
+
195
+ ## 4.1 Exceptions
172
196
173
197
There are two "normal" cases where tasks raise an exception: when the task is
174
198
complete (` StopIteration ` ) and when it is cancelled (` CancelledError ` ). In both
@@ -178,23 +202,25 @@ the run queue - the task is simply not rescheduled.
178
202
If an unhandled exception occurs in a task this will be propagated to the
179
203
caller of ` run_forever() ` or ` run_until_complete ` a explained in the tutorial.
180
204
181
- ## Task Cancellation
205
+ ## 4.2 Task Cancellation
182
206
183
207
The ` cancel ` function uses ` pend_throw ` to pass a ` CancelledError ` to the coro
184
208
to be cancelled. The generator's ` .throw ` and ` .close ` methods cause the coro
185
209
to execute code immediately. This is incorrect behaviour for a de-scheduled
186
210
coro. The ` .pend_throw ` method causes the exception to be processed the next
187
211
time the coro is scheduled.
188
212
189
- # Stream I/O
213
+ ###### [ Contents] ( ./UNDER_THE_HOOD.md#0-contents )
214
+
215
+ # 5. Stream I/O
190
216
191
217
Stream I/O is an efficient way of polling stream devices using ` select.poll ` .
192
218
Device drivers for this mechanism must provide an ` ioctl ` method which reports
193
219
whether a read device has data ready, or whether a write device is capable of
194
220
accepting data. Stream I/O is handled via ` StreamReader ` and ` StreamWriter `
195
221
instances (defined in ` __init__.py ` ).
196
222
197
- ## StreamReader
223
+ ## 5.1 StreamReader
198
224
199
225
The class supports three read coros which work in a similar fashion. The coro
200
226
yields an ` IORead ` instance with the device to be polled as its arg. It is
@@ -230,7 +256,7 @@ When the `StreamReader` read method completes it yields
230
256
` IOReadDone(object_to_poll) ` : this updates ` .flags ` and the poll flags so that
231
257
` ioctl ` no longer responds to an ` MP_STREAM_POLL_RD ` query.
232
258
233
- ## StreamWriter
259
+ ## 5.2 StreamWriter
234
260
235
261
This supports the ` awrite ` coro which works in a similar way to ` StreamReader ` ,
236
262
yielding ` IOWrite(object_to_poll) ` until all data has been written, followed
@@ -240,7 +266,7 @@ The mechanism is the same as for reading, except that when `ioctl` returns a
240
266
"ready" state for a writeable device it means the device is capable of writing
241
267
at least one character.
242
268
243
- ## PollEventLoop.wait()
269
+ ## 5.3 PollEventLoop.wait
244
270
245
271
When this is called the ` Poll ` instance is checked in a one-shot mode. In this
246
272
mode it will return either when ` delay ` has elapsed or when at least one device
@@ -258,29 +284,37 @@ I/O queue has been instantiated.
258
284
259
285
Writing is handled similarly.
260
286
261
- # Debug code
287
+ ###### [ Contents] ( ./UNDER_THE_HOOD.md#0-contents )
288
+
289
+ # 6. Debug code
262
290
263
291
The official ` uasyncio ` contains considerable explicit debug code: schedulers
264
- are hard to debug. There is code which I believe is for debugging purposes and
265
- some I have added myself for this purpose. The aim is to ensure that, if an
266
- error causes a coro to be scheduled when it shouldn't be, an exception is
267
- thrown. The alternative is weird, hard to diagnose, behaviour.
268
- These are the instances:
292
+ are hard to debug.
293
+
294
+ There is also code which I believe is for debugging purposes including some I
295
+ have added myself for this purpose. The aim is to ensure that, if an error
296
+ causes a coro to be scheduled when it shouldn't be, an exception is thrown. The
297
+ alternative is weird, hard to diagnose, behaviour.
298
+
299
+ Consider these instances:
269
300
[ pend_throw(false)] ( https://github.com/peterhinch/micropython-lib/blob/f20d89c6aad9443a696561ca2a01f7ef0c8fb302/uasyncio.core/uasyncio/core.py#L119 )
270
301
also [ here] ( https://github.com/peterhinch/micropython-lib/blob/f20d89c6aad9443a696561ca2a01f7ef0c8fb302/uasyncio.core/uasyncio/core.py#L123 ) .
271
302
I think the intention here is to throw an exception (exception doesn't inherit
272
303
from Exception) if it is scheduled incorrectly. Correct scheduling coutermands
273
304
this
274
305
[ here] ( https://github.com/peterhinch/micropython-lib/blob/819562312bae807ce0d01aa8ad36a13c22ba9e40/uasyncio/uasyncio/__init__.py#L97 )
275
306
and [ here] ( https://github.com/peterhinch/micropython-lib/blob/819562312bae807ce0d01aa8ad36a13c22ba9e40/uasyncio/uasyncio/__init__.py#L114 ) :
276
- these lines ensures that the exception will not be thrown.
307
+ these lines ensures that the exception will not be thrown.
308
+
277
309
The ` rdobjmap ` and ` wrobjmap ` dictionary entries are invalidated
278
310
[ here] ( https://github.com/peterhinch/micropython-lib/blob/819562312bae807ce0d01aa8ad36a13c22ba9e40/uasyncio/uasyncio/__init__.py#L91 )
279
311
and [ here] ( https://github.com/peterhinch/micropython-lib/blob/819562312bae807ce0d01aa8ad36a13c22ba9e40/uasyncio/uasyncio/__init__.py#L101 ) .
280
312
This has the same aim: if an attempt is made incorrectly to reschedule them, an
281
313
exception is thrown.
282
314
283
- # Modifying uasyncio
315
+ ###### [ Contents] ( ./UNDER_THE_HOOD.md#0-contents )
316
+
317
+ # 7. Modifying uasyncio
284
318
285
319
The library is designed to be extensible. By following these guidelines a
286
320
module can be constructed which alters the functionality of asyncio without the
@@ -312,4 +346,6 @@ def get_event_loop(args):
312
346
return _event_loop
313
347
```
314
348
349
+ ###### [ Contents] ( ./UNDER_THE_HOOD.md#0-contents )
350
+
315
351
###### [ Main README] ( ./README.md )
0 commit comments