New to curio ... help understanding curio traps


I’m still new here, and still trying to understand this curio internally.
I’m seeing the traps module (…Actually, i can understand the terms of coroutine, yield, return and some asynchronous related constructs.

I see some code, for example:

def _get_current():
    Get the currently executing task
    return (yield (_trap_get_current,)

and some others code

def _read_wait(fileobj):
    Wait until reading can be performed.
    yield (_trap_io, fileobj, EVENT_READ, 'READ_WAIT')

The questions is, what the technical differences and behaviour between two of coroutine construct above ? one using yield directly and using return (yield bla) construct …

Is there any significant impact ?

Thanks for attentions, maybe continued on others questions


There’s no difference between the two constructs. Coroutines are allowed to return a value so the version using return is doing that. The _read_wait() trap doesn’t return a value. The extra set of parentheses in the return version is required to avoid a syntax error. return yield n is a syntax error, but return (yield n) is okay.


Thanks for quick response…

so, if i can say in simpler understandable words, correct me if i’m wrong, …
“The first form tell to yield the signal/syscall to the kernel, and get the result back where the second form just yield signal to kernel”.

How it related with kernel response and scheduler process works ?



The second form could have been written as return (yield (_trap_io, fileobj, EVENT_READ, 'READ_WAIT')) . However, the underlying trap in the kernel returns None. So, there’s no point in using return–a function with no return statement returns None already. None of this has anything to do with the internal operation of the kernel and/or scheduler.

Certain traps are handled differently internally according to whether or not they’re going to block or not. For example, _trap_get_current always returns immediately whereas _trap_io might block. There are decorators and comments in the curio/ file that would discuss and control this.


Okey i look at how traps was handled by curio kernel, there are @blocking and @nonblocking decorator with very brief description, thanks …its help me a lot.
So, if we look at how the traps get handled, for example, _trap_io

def _trap_io(fileobj, event, state):
            # See comment about deferred unregister in run().  If the requested
            # I/O operation is *different* than the last I/O operation that was
            # performed by the task, we need to unregister the last I/O resource used
            # and register a new one with the selector.
            if current._last_io != (fileobj, event):
                if current._last_io:
                    _register_event(fileobj, event, current)
                except CurioError as e:
                    _reschedule_task(current, exc=e)
                    return (current.state, None)

            # This step indicates that we have managed any deferred I/O management
            # for the task.  Otherwise the run() method will perform an unregistration step.
            current._last_io = None
            return (state, lambda: _unregister_event(fileobj, event))

so, and the ‘_read_wait’ in module, was using yield (bla) construct, because it was blocking trap …and we dont need return directly … is this was right words ? cmiiw

Thanks for describes this basic fundamental way, how traps in curio kernel works and implemented …

Sorry for noob questions


The use of the return statement in combination with yield really has no relationship to the blocking/nonblocking handling. Some traps have a return value and some don’t. For example, _trap_sleep is a blocking trap that returns a value. _trap_unset_timeout is a nonblocking trap that doesn’t return a value.


Ah, sorry for my crazy lol :unamused:

I think i get the basic understanding based on yours great descriptions, and so many thanks.

I hope i can ask more and more again about curio at later time.