What is safe to do in an extern (C) function and how can I test this?

Steven Schveighoffer schveiguy at gmail.com
Tue Jan 25 01:41:03 UTC 2022


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


More information about the Digitalmars-d-learn mailing list