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:
Bob Nystrom
2015-08-30 22:15:37 -07:00
parent 91af02ac81
commit 556af50f83
49 changed files with 469 additions and 350 deletions
+23 -3
View File
@@ -14,16 +14,36 @@ static const char* timerLibSource =
" if (!(milliseconds is Num)) Fiber.abort(\"Milliseconds must be a number.\")\n"
" if (milliseconds < 0) Fiber.abort(\"Milliseconds cannot be negative.\")\n"
" startTimer_(milliseconds, Fiber.current)\n"
" Fiber.yield()\n"
"\n"
" runNextScheduled_()\n"
" }\n"
"\n"
" // TODO: Once the CLI modules are more fleshed out, find a better place to\n"
" // put this.\n"
" static schedule(callable) {\n"
" if (__scheduled == null) __scheduled = []\n"
" __scheduled.add(Fiber.new {\n"
" callable.call()\n"
" runNextScheduled_()\n"
" })\n"
" }\n"
"\n"
" foreign static startTimer_(milliseconds, fiber)\n"
"\n"
" // Called by native code.\n"
" static resumeTimer_(fiber) {\n"
" fiber.run()\n"
" fiber.transfer()\n"
" }\n"
"}\n";
"\n"
" static runNextScheduled_() {\n"
" if (__scheduled == null || __scheduled.isEmpty) {\n"
" Fiber.suspend()\n"
" } else {\n"
" __scheduled.removeAt(0).transfer()\n"
" }\n"
" }\n"
"}\n"
"\n";
// The Wren method to call when a timer has completed.
static WrenMethod* resumeTimer;
+22 -2
View File
@@ -3,13 +3,33 @@ class Timer {
if (!(milliseconds is Num)) Fiber.abort("Milliseconds must be a number.")
if (milliseconds < 0) Fiber.abort("Milliseconds cannot be negative.")
startTimer_(milliseconds, Fiber.current)
Fiber.yield()
runNextScheduled_()
}
// TODO: Once the CLI modules are more fleshed out, find a better place to
// put this.
static schedule(callable) {
if (__scheduled == null) __scheduled = []
__scheduled.add(Fiber.new {
callable.call()
runNextScheduled_()
})
}
foreign static startTimer_(milliseconds, fiber)
// Called by native code.
static resumeTimer_(fiber) {
fiber.run()
fiber.transfer()
}
static runNextScheduled_() {
if (__scheduled == null || __scheduled.isEmpty) {
Fiber.suspend()
} else {
__scheduled.removeAt(0).transfer()
}
}
}