Change:
// * Execution Functions - Core Loop Logic <del> // The model for this function is that you continue through it // until you either use the scheduler while performing a schedule // action, in which case you give it away and return early, or // you reach the end and sleep. In the case that a scheduler // action is performed the loop is evented such that this function // is called again. </del> <ins> // This function is run from the idle callback on the uv loop, indicating // that there are no I/O events pending. When this function returns, we will // fall back to epoll() in the uv event loop, waiting for more things to // happen. We may come right back off epoll() if the idle callback is still // active, in which case we're truly just polling to see if I/O events are // complete. // // The model for this function is to execute as much work as possible while // still fairly considering I/O tasks. Falling back to epoll() frequently is // often quite expensive, so we attempt to avoid it as much as possible. If // we have any active I/O on the event loop, then we're forced to fall back // to epoll() in order to provide fairness, but as long as we're doing work // and there's no active I/O, we can continue to do work. // // If we try really hard to do some work, but no work is available to be // done, then we fall back to epoll() to block this thread waiting for more // work (instead of busy waiting). </ins> fn run_sched_once(mut ~self, stask: ~GreenTask) { // Make sure that we're not lying in that the `stask` argument is indeed // the scheduler task for this scheduler.

Discussion:
In the current design the scheduler takes one scheduling action, registers a callback to wake up in the runschedonce function, and then blocks on the event loop. This "block" is implemented as just finishing the execution associated with the runschedonce callback. As there is a callback registered it immediately wakes up and repeats the process. This should be unnecessary. The drop back to the event loop is a very long process relative to a task context swap, so this is likely very bad for performance. A better solution would be to keep the scheduler active until it runs out of stuff to do, and then block on the event loop. To do this we should have a "live" flag for the scheduler. If the flag is set the scheduler is guarenteed to check for messages and likely work before going to sleep. While active the scheduler algorithm becomes: 1) Call run on the event loop with the NOWAIT flag set. This will make it so that if there are no events, the function returns immediately instead of blocking. 2) Find a task to run, and run it. Repeat a small number of times to get better task throughput. 3) If the live flag is false, call a blocking run. 4) If no work has been done this round, set the live flag to false. 5) Goto (1) The libuv "uvrun" function has three modes. UVRUNDEFAULT is what we have been using, a blocking "do stuff until the program is done" use of the event loop. UVRUNNOWAIT polls for new events and then does not block if there are no events ready. This is the style that we want for the non-blocking run case. UVRUNONCE is how we would perform blocking runs. It will block until it handles a single event, and then return how many pending events there are. To wake up the scheduler while it is "sleeping", the old idle-callback is used. Except now the function provided simply modifies the live flag to "awake", and the scheduler loop logic takes over. In any case where an idle callback would be registered and the live flag is set the callback can be skipped.
This builds on somewhat as it also changes how idle callbacks work in the scheduler.

As far as I can tell the structure you suggest isn't about eliminating 'blocking' per se - if there are events to be run then the loop doesn't block - but is a proposal to improve performance by using polling instead of events. From the description I believe that the performance win you expect to get here is from not using the idle callback. I'm skeptical that calling the idle callback is a significant amount of the work that the event loop is doing though. The work imposed by an idle callback on is the following (from loop-watcher.c): That is, traversing an element of a linked list and calling a function pointer. This structure has a downside that it would impose more requirements on our generic event loop, and that it is more complicated. I'm not inclined to make this change without evidence that the current callback-based structure is a problem.
no longer relevant to the standard libraries ()