Revise low level fiber semantics to play nicer with schedulers.
Now that I'm starting to write a real async scheduler on top of Wren's basic fiber API, I have a better feel for what it needs. It turns out run() is not it. - Remove run() methods. - Add transfer() which leaves the caller of the invoked fiber alone. - Add suspend() to return control to the host application. - Add Timer.schedule() to start a new independently scheduled fiber. - Change Timer.sleep() so that it only transfers control to explicitly scheduled fibers, not any one.
This commit is contained in:
@@ -19,6 +19,14 @@ fiber is run. Does not immediately start running the fiber.
|
||||
|
||||
The currently executing fiber.
|
||||
|
||||
### Fiber.**suspend**()
|
||||
|
||||
Pauses the current fiber, and stops the interpreter. Control returns to the
|
||||
host application.
|
||||
|
||||
To resume execution, the host application will need to invoke the interpreter
|
||||
again. If there is still a reference to the suspended fiber, it can be resumed.
|
||||
|
||||
### Fiber.**yield**()
|
||||
|
||||
Pauses the current fiber and transfers control to the parent fiber. "Parent"
|
||||
@@ -119,10 +127,10 @@ Invokes the fiber or resumes the fiber if it is in a paused state and sets
|
||||
Whether the fiber's main function has completed and the fiber can no longer be
|
||||
run. This returns `false` if the fiber is currently running or has yielded.
|
||||
|
||||
### **run**()
|
||||
### **transfer**()
|
||||
|
||||
**TODO**
|
||||
|
||||
### **run**(value)
|
||||
### **transfer**(value)
|
||||
|
||||
**TODO**
|
||||
|
||||
@@ -158,17 +158,12 @@ Fibers have one more trick up their sleeves. When you execute a fiber using
|
||||
lets you build up a chain of fiber calls that will eventually unwind back to
|
||||
the main fiber when all of the called ones yield or finish.
|
||||
|
||||
This works fine for most uses, but sometimes you want something a little more
|
||||
freeform. For example, you may be creating a [state
|
||||
machine](http://en.wikipedia.org/wiki/Finite-state_machine) where each state is
|
||||
a fiber. When you switch from one state to the next, you *don't* want to build
|
||||
an implicit stack of fibers to return to. There is no "returning" in this case.
|
||||
You just want to *transfer* to the next fiber and forget about the previous one
|
||||
entirely. (This is analogous to [tail call
|
||||
elimination](http://en.wikipedia.org/wiki/Tail_call) for regular function
|
||||
calls.)
|
||||
This is almost always what you want. But if you're doing something really low
|
||||
level, like writing your own scheduler to manage a pool of fibers, you may not
|
||||
want to treat them explicitly like a stack.
|
||||
|
||||
To enable this, fibers also have a `run()` method. This begins executing that
|
||||
fiber, and "forgets" the previous one. If the running fiber yields or ends, it
|
||||
will transfer control back to the last *called* one. (If there are no called
|
||||
fibers, it will end execution.)
|
||||
For rare cases like that, fibers also have a `transfer()` method. This switches
|
||||
execution immediately to the transferred fiber. The previous one is suspended,
|
||||
leaving it in whatever state it was in. You can resume the previous fiber by
|
||||
transferring back to it, or even calling it. If you don't, execution stops when
|
||||
the last transferred fiber returns.
|
||||
|
||||
Reference in New Issue
Block a user