Very helpful. I have modified my code to use callbacks and everything is working as expected. It is interesting that everything was working fine with my racket_apply and racket_eval hacks, as well.
I have gotten my communication with racket down to one put and one get closure, wrapping a call to place-channel-put and place-channel-get. I think this is working well and the c client module is now mostly oblivious to racket, it just thinks it is using standard c function pointers so that is good. I do still have to Sactivate_thread and Sdeactivate_thread to construct my values and call the procs but that is ok, it is nice now. The cast works properly for me, i thought i had tried that already but it works fine. I didn't realize `cast` works for source values that are already racket values but it makes sense that it could detect racket values and just not call c-to-racket, i guess. Nate On Mon, Nov 23, 2020 at 7:01 AM Matthew Flatt <[email protected]> wrote: > At Mon, 23 Nov 2020 00:14:56 -0600, Nate Griswold wrote: > > Hello. I have a few questions: > > > > 1) Why do the docs say that racket_eval and racket_apply eval and apply > in > > the “initial” or “original” racket thread? I have verified that the > thread > > id returned from pthread_self when using racket_apply in c code called > from > > a racket place is different from the thread id of the thread i called > > racket_boot on. > > The `racket_apply` function was intended for use only in the OS thread > where Racket is booted, and only "outside" to get Racket started. It's > not intended for use in callbacks from Racket. > > That's generally true for functions listed in sections 4-6 of "Inside", > and I see that the intent is not remotely clear there. I'll improve the > documentation. > > To call back to Racket from C code, you should use the Racket FFI, > where a Racket function that's passed to C gets converted to a function > pointer for the C side. When you call that callback (as a regular C > function call), various bits of Scheme and Racket state get > configured/restored in a consistent way before jumping to the wrapped > Racket code as a callback. > > For simple things, it turns out that `Scall0`, etc. would work to > invoke a callback within the Racket context that had called into C, but > there are many pitfalls, so you shouldn't do that. > > You definitely should not use `racket_apply` or `racket_eval` from C > that was called from Racket. It will... well, do something. Take the > uncertainly of using `Scall0` and multiply by 100, since functions like > `racket_apply` specifically attempt to interact with the thread > scheduler. > > > 2) I noticed that if i racket_eval in c code called by a racket place, i > > can’t evaluate things that would otherwise (in racket code) be available > in > > the place’s namespace. What is the correct way to get at things in the > > place’s racket namespace from c code? Is my problem unique to using a > > place, or would i have this problem in a non-place scenario as well? > > I think it's probably not just about places, but let me answer the > "correct way" question with the next bullet. > > > 3) (related to 2) I want to be able to put and get from a place channel > > from a long-running c function. If i just pass a place channel to the > > function, that is wrong because if i am correct in my thinking (and in > what > > i have witnessed) there is a chance that when i go to use that channel in > > the future, it will have been moved by the garbage collector. Is there > any > > way to prevent a specific value from being garbage collected, at least > for > > the lifetime of my place? This is related to (2) because i actually don’t > > need this functionality if i can just racket_eval to get at the place > > channel from the namespace of the place’s module in the middle of a > > Sactivate_thread / Sdeactivate_thread session. > > The best approach here is to hand the C code a callback, which it will > see as plain old C functions. Maybe there's one callback to get from > the channel and another to put to the channel --- where the channel is > in the closure of the function, although the C side has no idea about > closures. If you go that route, then as long as you retain a reference > to the callback closure on the Racket side, the callback function > itself won't move. > > Overall, reasoning about the interaction between Racket/Scheme and C > interaction from the C side is very difficult. The more you can arrange > for the C code to oblivious to Racket, the easier things get, because > the Racket-side tools for interacting with C are much better. > > > 3) Is there any way to pass a c callback function into racket so that > > racket can call that function? I defined a ctype for the function, but i > > couldn’t think of a way to cast a pointer value passed into racket from c > > to an instance of my ctype (the `cast` function takes existing ctypes and > > not numeric values). Is there any way to manually make a value for my > > function ctype using an existing pointer value? > > You can cast from a numeric value by casting from `_intptr` to a > pointer type. For example, this expression creates a function that > tries to jump to address 16 (and crashes, but in gdb you'd see it > crashing with the instruction pointer at address 16): > > (cast 16 _intptr (_fun -> _void)) > > > Matthew > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/CAM-xLPq3V05-OGOS2AC0EA_wSO7oWWVWMOzpsOAyP42MSUvwxw%40mail.gmail.com.

