There's lots of stuff to do.
scheme@(guile-user)> ,fibers
fiber state
----- -----
1 runnable
2 waiting on #<input-port ...> to become readable
3 waiting on #<channel > to become readable
4 waiting on #<channel > to become writable
5 sleeping for another 3.423s
...
Right now we just get "waiting", "finished", or the like. Usefully representing what a thread is waiting on is tricky though. Since this information is already present in the continuation, probably we should not include any additional fields in the `' data type. If you just give the file and the line, probably that file is in (fibers internal) somewhere; you could traverse the stack until you leave fibers files, but then there's the possibility that there's user-level abstractions like RPC wrappers that the user would like to skip as well. A library should probably be able to hook into this pretty-printing process. Probably it can be done in such a way that we can just mark certain return addresses as never interesting, and in that case cache that value so that the user code doesn't have to be very performant.
scheme@(guile-user)> ,fkill 1
Also ,fcancel
I guess, the difference being that killing raises an
exception and cancelling is like SIGKILL.
scheme@(guile-user)> ,fiber 2
Pausing fiber 2 (was: sleeping for another 3.2s).
Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
scheme@(guile-user) [1]> ,bt
[backtrace for fiber]
How would this work, I wonder? It's easy to get a backtrace because we have the suspended continuation for paused fibers, but you'd want to get the dynamic bindings too, methinks...
Currently fibers have no priority. Does that matter?
Currently there is no ability to join a fiber. I don't know if this matters or not though. Certainly you can build this facility by wrapping the fiber's continuation when you create it.
What if you are waiting on a channel but also want to get woken if the remote process dies? Probably in this case `select()' over two channels would be sufficient. At the same time, something like what Concurrent ML does by making events first-class solves this problem nicely.
In batch mode, probably the exception should be caught by the scheduler, the fiber marked as finished-with-exception, and the key and args stored as the fiber data. If that fiber is the root fiber for the scheduler, then perhaps the scheduler should end early? In any case when the scheduler ends and the root fiber threw an exception, probably that exception should be propagated.
I guess in general uncaught exceptions should be propagated to join-fiber callers. If nobody is joining, then perhaps a backtrace should be printed? There are situations where you want a backtrace to be printed but I don't know what they are.
Finally there are also situations when you would like to enter a
debugger. I don't know what these situations are. For that I guess
we can see what kind of solution to make once ,fiber
is working.
We need to provide API for things like:
Currently the REPL runs in a blocking mode that basically takes over
the thread. That would be fine if the REPL could suspend; can we find
a way to make it suspend, integrating readline and Scheme read' and Scheme
write' into fibers? Probably not in the short term, so we
will have to use kernel threads. One REPL on a thread to interact
with the user, and fibers run in other threads. We need to package
this up so that a user can have a nice experience.
Change the HTTP library in Guile to always use suspendable operations instead of `display' et al.
"lightweight concurrency in guile with fibers" or something.