Fixed bugs with cancellations and exceptions

This commit is contained in:
Nocturn9x 2023-05-11 14:17:09 +02:00
parent 98a280ce39
commit 724b5c98ba
Signed by: nocturn9x
GPG Key ID: 8270F9F467971E59
4 changed files with 41 additions and 26 deletions

View File

@ -166,6 +166,8 @@ async def cancel(task: Task, block: bool = False):
if task.done():
return
if task.scope and not task.scope.cancellable:
return
await syscall("cancel", task)
if block:
await wait(task)

View File

@ -126,10 +126,12 @@ class FIFOKernel:
:return:
"""
self._sigint_handled = True
if not currently_protected():
self.run_ready.appendleft(self.entry_point)
self.entry_point.pending_exception = KeyboardInterrupt()
self.handle_errors(self.run_task_step)
else:
self._sigint_handled = True
def done(self) -> bool:
"""
@ -352,28 +354,17 @@ class FIFOKernel:
# there are no more runnable tasks
return
self.current_task = self.run_ready.popleft()
if self.current_task.pending_cancellation:
# We perform the deferred cancellation
# if it was previously scheduled
self.cancel(self.current_task)
if self.current_task.done():
return
self._running = True
_runner = self.current_task.run
_data = [self.data.pop(self.current_task, None)]
if exc := self.current_task.pending_exception:
self.current_task.pending_exception = None
_runner = partial(self.current_task.throw, exc)
_data = []
# Some debugging and internal chatter here
self.current_task.steps += 1
self.current_task.state = TaskState.RUN
self.debugger.before_task_step(self.current_task)
if self._sigint_handled:
self._sigint_handled = False
self.current_task.throw(KeyboardInterrupt())
_runner = partial(self.current_task.throw, KeyboardInterrupt)
_data = []
elif exc := self.current_task.pending_exception:
self.current_task.pending_exception = None
_runner = partial(self.current_task.throw, exc)
_data = []
# Run a single step with the calculation (i.e. until a yield
# somewhere)
method, args, kwargs = _runner(*_data)
@ -456,7 +447,9 @@ class FIFOKernel:
else:
task = self.current_task
"""
self._sigint_handled = False
task = self.entry_point
task.pending_exception = KeyboardInterrupt()
self.run_ready.appendleft(task)
self.handle_errors(self.run_task_step)
elif not self.run_ready:
@ -579,14 +572,14 @@ class FIFOKernel:
it fails
"""
if not task.scope or task.scope.cancellable:
self.paused.discard(task)
self.io_release_task(task)
self.run_ready.append(task)
self.handle_errors(partial(task.throw, Cancelled(task)), task)
if task.state != TaskState.CANCELLED:
task.pending_cancellation = True
self.reschedule_running()
self.paused.discard(task)
self.io_release_task(task)
self.run_ready.appendleft(task)
self.handle_errors(partial(task.throw, Cancelled()), task)
self.handle_errors(self.run_task_step)
if task.state != TaskState.CANCELLED:
task.pending_exception = Cancelled()
def throw(self, task, error):
"""
@ -682,7 +675,7 @@ class FIFOKernel:
"""
task = Task(func.__name__ or repr(func), func(*args, **kwargs))
# We inject our magic secret variable into the coroutine's stack frame so
# We inject our magic secret variable into the coroutine's stack frame, so
# we can look it up later
task.coroutine.cr_frame.f_locals.setdefault(CTRLC_PROTECTION_ENABLED, False)
task.scope = self.current_scope
@ -736,7 +729,8 @@ class FIFOKernel:
return
elif self.current_task.last_io[1] == resource:
# If the event to listen for has changed we just modify it
self.selector.modify(resource, evt_type, {evt_type: self.current_task})
key = self.selector.get_key(resource)
self.selector.modify(resource, evt_type | key.events, key.data.update({evt_type: self.current_task}))
self.current_task.last_io = (evt_type, resource)
self.debugger.on_io_schedule(resource, evt_type)
elif not self.current_task.last_io or self.current_task.last_io[1] != resource:

15
tests/deadlock.py Normal file
View File

@ -0,0 +1,15 @@
import aiosched
async def deadlock():
await aiosched.Event().wait()
async def parent():
async with aiosched.skip_after(5):
await deadlock()
print("Done")
aiosched.run(parent)
print("Exited")

View File

@ -32,4 +32,8 @@ async def main():
print("Two-way proxy shutting down")
aiosched.run(main)
try:
aiosched.run(main)
except KeyboardInterrupt:
print(f"Ctrl+C caught")