summaryrefslogtreecommitdiff
path: root/extmod/moduasyncio.c
AgeCommit message (Collapse)Author
2021-06-24all: Fix signed shifts and NULL access errors from -fsanitize=undefined.Jeff Epler
Fixes the following (the line numbers match commit 0e87459e2bfd07): ../../extmod/crypto-algorithms/sha256.c:49:19: runtime error: left shif... ../../extmod/moduasyncio.c:106:35: runtime error: member access within ... ../../py/binary.c:210:13: runtime error: left shift of negative value -... ../../py/mpz.c:744:16: runtime error: negation of -9223372036854775808 ... ../../py/objint.c:109:22: runtime error: left shift of 1 by 31 places c... ../../py/objint_mpz.c:374:9: runtime error: left shift of 4611686018427... ../../py/objint_mpz.c:374:9: runtime error: left shift of negative valu... ../../py/parsenum.c:106:14: runtime error: left shift of 46116860184273... ../../py/runtime.c:395:33: runtime error: left shift of negative value ... ../../py/showbc.c:177:28: runtime error: left shift of negative value -... ../../py/vm.c:321:36: runtime error: left shift of negative value -1``` Testing was done on an amd64 Debian Buster system using gcc-8.3 and these settings: CFLAGS += -g3 -Og -fsanitize=undefined LDFLAGS += -fsanitize=undefined The introduced TASK_PAIRHEAP macro's conditional (x ? &x->i : NULL) assembles (under amd64 gcc 8.3 -Os) to the same as &x->i, since i is the initial field of the struct. However, for the purposes of undefined behavior analysis the conditional is needed. Signed-off-by: Jeff Epler <jepler@gmail.com>
2021-06-16extmod/uasyncio: Fix race with cancelled task waiting on finished task.Damien George
This commit fixes a problem with a race between cancellation of task A and completion of task B, when A waits on B. If task B completes just before task A is cancelled then the cancellation of A does not work. Instead, the CancelledError meant to cancel A gets passed through to B (that's expected behaviour) but B handles it as a "Task exception wasn't retrieved" scenario, printing out such a message (this is because finished tasks point their "coro" attribute to themselves to indicate they are done, and implement the throw() method, but that method inadvertently catches the CancelledError). The correct behaviour is for B to bounce that CancelledError back out. This bug is mainly seen when wait_for() is used, and in that context the symptoms are: - occurs when using wait_for(T, S), if the task T being waited on finishes at exactly the same time as the wait-for timeout S expires - task T will have run to completion - the "Task exception wasn't retrieved message" is printed with "<class 'CancelledError'>" as the error (ie no traceback) - the wait_for(T, S) call never returns (it's never put back on the uasyncio run queue) and all tasks waiting on this are blocked forever from running - uasyncio otherwise continues to function and other tasks continue to be scheduled as normal The fix here reworks the "waiting" attribute of Task to be called "state" and uses it to indicate whether a task is: running and not awaited on, running and awaited on, finished and not awaited on, or finished and awaited on. This means the task does not need to point "coro" to itself to indicate finished, and also allows removal of the throw() method. A benefit of this is that "Task exception wasn't retrieved" messages can go back to being able to print the name of the coroutine function. Fixes issue #7386. Signed-off-by: Damien George <damien@micropython.org>
2020-12-02extmod/uasyncio: Add Task.done() method.Damien George
This is added because task.coro==None is no longer the way to detect if a task is finished. Providing a (CPython compatible) function for this allows the implementation to be abstracted away. Signed-off-by: Damien George <damien@micropython.org>
2020-12-02extmod/uasyncio: Delay calling Loop.call_exception_handler by 1 loop.Damien George
When a tasks raises an exception which is uncaught, and no other task await's on that task, then an error message is printed (or a user function called) via a call to Loop.call_exception_handler. In CPython this call is made when the Task object is freed (eg via reference counting) because it's at that point that it is known that the exception that was raised will never be handled. MicroPython does not have reference counting and the current behaviour is to deal with uncaught exceptions as early as possible, ie as soon as they terminate the task. But this can be undesirable because in certain cases a task can start and raise an exception immediately (before any await is executed in that task's coro) and before any other task gets a chance to await on it to catch the exception. This commit changes the behaviour so that tasks which end due to an uncaught exception are scheduled one more time for execution, and if they are not await'ed on by the next scheduling loop, then the exception handler is called (eg the exception is printed out). Signed-off-by: Damien George <damien@micropython.org>
2020-04-13all: Clean up error strings to use lowercase and change cannot to can't.Damien George
Now that error string compression is supported it's more important to have consistent error string formatting (eg all lowercase English words, consistent contractions). This commit cleans up some of the strings to make them more consistent.
2020-04-05all: Use MP_ERROR_TEXT for all error messages.Jim Mussared
2020-03-26extmod/uasyncio: Add optional implementation of core uasyncio in C.Damien George
Implements Task and TaskQueue classes in C, using a pairing-heap data structure. Using this reduces RAM use of each Task, and improves overall performance of the uasyncio scheduler.