On 1/24/22 8:31 PM, Jaime wrote:
**The lede**:
Can I, for instance, safely call Fiber.yield in a C callback that I know
will be run in a Fiber?
The stack will look like:
Thread
|- Fiber in D runtime
| |- Call into a C API (stays on same thread)
| | |- Extern (C) callback (stays on same thread)
| | | |- Fiber.yield <-- Is this OK?
Also, in general, is there a convenient way to know or test if
particular C callbacks are safe? Or is it just case by case?
**The context I was gonna bury the lede in but thought better of it**:
So, I am a big lame novice. Don't worry, I know this already.
I'm trying to use gtk-d, but I don't even know how to use gtk, so I'm
learning them both at once. Probably not a good idea, I know.
From what I can tell so far, it seems like the way gtk works is you
write your whole application in terms of gtk's event loop. I really
don't want to do that, so -- and I realize this is probably an even
worse idea, but I don't know the right thing to do -- I decided I'd try
writing a worker thread class -- "Rope" -- and run gtk's event loop in a
Rope.
A Rope runs its given task in a new Fiber in a new thread, and that
thread repeatedly resumes the fiber and terminates when the fiber
terminates, but, in the meantime, takes some time to act as an executor
each time the fiber suspends, accepting work in std.concurrency messages
and running it on the same thread as its main fiber. My thought was that
this way, I can call gtk-d's API from any thread, and still have all the
calls happen on the same thread that the event loop is running on, as
the API requires.
All I needed, then, was some way to make gtk-d suspend the fiber it's
running on, to give its rope some time to service external work. My
first thought was to use glib.Timeout.Timeout.add and put Fiber.yield in
the timeout callback. The potential problem: the timeout callback, of
course, has to be extern (C).
Now, I could just drop the more general concept of Rope and rewrite it
specifically for gtk, and drop the whole Fiber part, and instead
directly put the calls to std.concurrency.receiveTimeout in the
glib.Timeout.Timeout.add callback. Assuming, of course, receiveTimeout
would be any safer to call from extern (C) than Fiber.yield would. But
that's just the trouble, I can't guess which would be safer, and even a
minimal test for this question seems daunting.
I would *imagine* it's fine, all the fiber context switch is doing (WRT
the stack) is swapping out the fiber portion of the stack (i.e. back to
the `Fiber.call` invokation), which should include the C stack portions
as well.
There's a lot of low-level details in the Fiber.d file itself:
https://github.com/dlang/druntime/blob/e390ba7e0a1f80f15e72ca773fca7252057ba4c5/src/core/thread/fiber.d#L387
-Steve