I'm implementing a simple windowing library as a Ruby C extension. Windows have a handle_events! method that enters their native event loop.
The problem is that I want one event loop per window and the method blocks. I'd like the method to return immediately and let the loop run in a separate thread. What would be the best way to achieve this?
I tried using rb_thread_call_without_gvl to call the event loop function, and then use rb_thread_call_with_gvl in order to call the window's callbacks, which are Procs. Full source code can be found here.
It still works, but not as I intended: the method still blocks. Is this even possible with Ruby's threading model?
I had the very same problem to solve. And as rb_thread_call_with_gvl() was marked as experimental in 1.9.2 and it was not an exported symbol, I toke a different approach:
I called the blocking handle_event! function from a separate thread. I used a second ruby thread, that blocked on a message queue. While blocking on the message queue, the gvl was released with rb_thread_blocking_region().
If now the thread calling handle_event! was unblocked due to an event, it pulled all required information for the Proc's upcall together in a queue element and pushed that element onto the queue. The ruby thread received the element, returned from rb_thread_blocking_region() and thus reacquired the gvl and call the Proc with the information from the received element.
Kind regards Torsten