Skip to content

Commit 4a2286b

Browse files
committed
UNDER_THE_HOOD.md: add TOC.
1 parent 8cd56e0 commit 4a2286b

File tree

1 file changed

+54
-18
lines changed

1 file changed

+54
-18
lines changed

UNDER_THE_HOOD.md

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,24 @@ please raise an issue. None of this information is required to use the library:
77
it is intended to satisfy the curiosity of scheduler geeks or to help those
88
wishing to modify it.
99

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+
1028
Where the versions differ, this explanation relates to the `fast_io` version.
1129
Differences are largely in `__init__.py`: the scheduling algorithm in `core.py`
1230
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.
3755

3856
###### [Main README](./README.md)
3957

40-
# Generators and coroutines
58+
# 2. Generators and coroutines
4159

4260
In MicroPython coroutines and generators are identical: this differs from
4361
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
6280
generator yields a value of 1000; this is passed to the scheduler to invoke the
6381
delay (see below).
6482

65-
# Coroutine yield types
83+
###### [Contents](./UNDER_THE_HOOD.md#0-contents)
84+
85+
# 3. Coroutine yield types
6686

6787
Because coroutines are generators it is valid to issue `yield` in a coroutine,
6888
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:
95115
`yield` is rescheduled.
96116
* A `SysCall1` instance. See below.
97117

98-
## SysCall1 classes
118+
## 3.1 SysCall1 classes
99119

100120
The `SysCall1` constructor takes a single argument stored in `self.arg`. It is
101121
effectively an abstract base class: only subclasses are instantiated. When a
@@ -117,7 +137,9 @@ The following subclasses exist:
117137
The `IO*` classes are for the exclusive use of `StreamReader` and `StreamWriter`
118138
objects.
119139

120-
# The EventLoop
140+
###### [Contents](./UNDER_THE_HOOD.md#0-contents)
141+
142+
# 4. The EventLoop
121143

122144
The file `core.py` defines an `EventLoop` class which is subclassed by
123145
`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
168190
scheduler pauses for this period (polling I/O). On a zero delay I/O is checked
169191
once: if nothing is pending it returns quickly.
170192

171-
## Exceptions
193+
###### [Contents](./UNDER_THE_HOOD.md#0-contents)
194+
195+
## 4.1 Exceptions
172196

173197
There are two "normal" cases where tasks raise an exception: when the task is
174198
complete (`StopIteration`) and when it is cancelled (`CancelledError`). In both
@@ -178,23 +202,25 @@ the run queue - the task is simply not rescheduled.
178202
If an unhandled exception occurs in a task this will be propagated to the
179203
caller of `run_forever()` or `run_until_complete` a explained in the tutorial.
180204

181-
## Task Cancellation
205+
## 4.2 Task Cancellation
182206

183207
The `cancel` function uses `pend_throw` to pass a `CancelledError` to the coro
184208
to be cancelled. The generator's `.throw` and `.close` methods cause the coro
185209
to execute code immediately. This is incorrect behaviour for a de-scheduled
186210
coro. The `.pend_throw` method causes the exception to be processed the next
187211
time the coro is scheduled.
188212

189-
# Stream I/O
213+
###### [Contents](./UNDER_THE_HOOD.md#0-contents)
214+
215+
# 5. Stream I/O
190216

191217
Stream I/O is an efficient way of polling stream devices using `select.poll`.
192218
Device drivers for this mechanism must provide an `ioctl` method which reports
193219
whether a read device has data ready, or whether a write device is capable of
194220
accepting data. Stream I/O is handled via `StreamReader` and `StreamWriter`
195221
instances (defined in `__init__.py`).
196222

197-
## StreamReader
223+
## 5.1 StreamReader
198224

199225
The class supports three read coros which work in a similar fashion. The coro
200226
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
230256
`IOReadDone(object_to_poll)`: this updates `.flags` and the poll flags so that
231257
`ioctl` no longer responds to an `MP_STREAM_POLL_RD` query.
232258

233-
## StreamWriter
259+
## 5.2 StreamWriter
234260

235261
This supports the `awrite` coro which works in a similar way to `StreamReader`,
236262
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
240266
"ready" state for a writeable device it means the device is capable of writing
241267
at least one character.
242268

243-
## PollEventLoop.wait()
269+
## 5.3 PollEventLoop.wait
244270

245271
When this is called the `Poll` instance is checked in a one-shot mode. In this
246272
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.
258284

259285
Writing is handled similarly.
260286

261-
# Debug code
287+
###### [Contents](./UNDER_THE_HOOD.md#0-contents)
288+
289+
# 6. Debug code
262290

263291
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:
269300
[pend_throw(false)](https://github.com/peterhinch/micropython-lib/blob/f20d89c6aad9443a696561ca2a01f7ef0c8fb302/uasyncio.core/uasyncio/core.py#L119)
270301
also [here](https://github.com/peterhinch/micropython-lib/blob/f20d89c6aad9443a696561ca2a01f7ef0c8fb302/uasyncio.core/uasyncio/core.py#L123).
271302
I think the intention here is to throw an exception (exception doesn't inherit
272303
from Exception) if it is scheduled incorrectly. Correct scheduling coutermands
273304
this
274305
[here](https://github.com/peterhinch/micropython-lib/blob/819562312bae807ce0d01aa8ad36a13c22ba9e40/uasyncio/uasyncio/__init__.py#L97)
275306
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+
277309
The `rdobjmap` and `wrobjmap` dictionary entries are invalidated
278310
[here](https://github.com/peterhinch/micropython-lib/blob/819562312bae807ce0d01aa8ad36a13c22ba9e40/uasyncio/uasyncio/__init__.py#L91)
279311
and [here](https://github.com/peterhinch/micropython-lib/blob/819562312bae807ce0d01aa8ad36a13c22ba9e40/uasyncio/uasyncio/__init__.py#L101).
280312
This has the same aim: if an attempt is made incorrectly to reschedule them, an
281313
exception is thrown.
282314

283-
# Modifying uasyncio
315+
###### [Contents](./UNDER_THE_HOOD.md#0-contents)
316+
317+
# 7. Modifying uasyncio
284318

285319
The library is designed to be extensible. By following these guidelines a
286320
module can be constructed which alters the functionality of asyncio without the
@@ -312,4 +346,6 @@ def get_event_loop(args):
312346
return _event_loop
313347
```
314348

349+
###### [Contents](./UNDER_THE_HOOD.md#0-contents)
350+
315351
###### [Main README](./README.md)

0 commit comments

Comments
 (0)