Goblin (suspendable) ports & O_NONBLOCK

Hello,

Goblins is using fibers as far as I understand. Fibers says that O_NONBLOCK should be set to every file descriptor being read or written to, for a fiber to correctly suspend.

The Guile manual on the other hand says that (ice-9 suspendable-ports) may be used for IO that suspends (to prompt) instead of blocking.

Can you please clarify what the correct order of doing things is? Should I use both O_NONBLOCK and suspendable ports together? I don’t see either fibers nor goblin use install-suspendable-ports!, except in tests/repl-driver.scm. I don’t understand how ^io works without using O_NONBLOCK. On the other hand, all the test I see in goblins that uses O_NONBLOCK relates to sockets; but what about the current input/output/error ports? For example, in an ncurses UI program, which is what I’m doing now…

Since Guile does not seem to use O_NONBLOCK in the Scheme source code of (ice-9 suspendable-ports) and since it does require a C shim as well, I assume that it’s the C-side that sets up O_NONBLOCK on stdin/stdout/stderr. So perhaps that suffices? But then, why is goblins not using suspendable-ports in ^io?

Edit: I believe that the answer is coming from “Non-Blocking I/O” in the Guile manual, but essentially it is this:

  1. Use (ice-9 suspendable-ports) and call (install-suspendable-ports).
  2. Set O_NONBLOCK to current input/output/error (if desired) and to every subsequent port you open.
  3. Now you can use ^io with them and/or fibers.

I think this should be documented a bit more carefully in the ^io page, is there a reason why it’s not? I can only guess that maybe the hope was that goblins would support more than the fibers scheduler?

Edit 2: The Guile manual on non-blocking I/O also mentions at the end that Guile does not currently include an implementation of the facility to suspend the current thread, and links to 8sync, has that been superseded by Fibers? I see the latest commit is from 2021. I wonder if the Guile manual should be changed in that section? @cwebber

Edit 3: Apparently I should have ncurses I/O in a dedicated thread because it wouldn’t work right with O_NONBLOCK on stdin; or I need to figure out an alternative to correctly suspend. A bit overwhelming right now, I would appreciate all hints.

1 Like

Hi, I’ll try to unpack this a bit.

First, regarding (ice-9 suspendable-ports) and install-suspendable-ports!, this is taken care of by fibers so users of fibers (you and I) don’t have to worry about it.

Next, even with suspendable ports activated, the O_NONBLOCK flag still needs to be set on file descriptors that you are managing yourself since that is a low-level interface and Guile doesn’t implicitly set any flags for you. I’m not 100% sure but I think this applies to stdin/stdout, as well.

I think that the ^io docs could be improved with more examples since integrating actors with fibers has a number of subtleties. It is important that you perform port I/O from something like ^io otherwise you run the risk of suspending a vat’s fiber and breaking your Goblins program.

And yes, the Guile manual is out-of-date. It should recommend fibers instead.

Hope this has helped clear things up somewhat!

1 Like

Thanks for clarifying!

I’ll try to update some of the docs and proceed with your advice. As for stdin/stdout, yes you’re right except that with ncurses there’s some issues and it’s probably safest to run it on its own thread without O_NONBLOCK.