3

I am writing a bytecode interpreter in C for a simple programming language.

I want to add GUI capabilities to the language. As a first step, I decided to bake into the interpreter a wrapper for the GTK library. It is exposed to user code as a builtin module.

My problem is that GTK works by taking control of the thread: once you call the C function g_application_run, the thread enters an endless listening loop inside GTK.

Why is this a problem? Because while we are "stuck" in this GTK loop, the bytecode interpretation loop of the interpreter is frozen. Psuedo bytecode to demonstrate:

0 SOME OPCODE
1 SOME OTHER OPCODE
2 OPCODE INVOKING GTK WRAPPER FUNCTION <-- GTK invoked in C level and enters an endless loop
3 MORE OPCODES  <-------- This is never executed

My first thought to combat this, was to design my GTK wrapper in a "close to 1:1 mirroring" style to the way the C library is supposed to be used. For example in psuedo code:

import gtk
func app_code() {
    # ... app code ...
}
gtk.application_run(app_code)

This supposedly solves the problem - we don't care that we never exit the GTK endless loop inside g_application_run, because it is now its responsibility to invoke our own user code.

The reason this won't work: the way user functions are invoked inside the interpreter, is by

  1. Pushing a new stack frame on the call stack
  2. Setting the instruction pointer to point to the beginning of the called functions bytecode
  3. In the next iteration of the bytecode interpretation loop, the new function will naturally start running

The GTK wrapper can easily do steps 1 and 2. But - step 3 will never happen, because we are stuck inside the GTK infinite loop. The interpreter loop never begins a new iteration.

So my question is: what are the possible options to solve this issue? Preferably, what are examples of how this issue is dealt with in existing projects?

  • Start the GTK loop on a different C level thread?
  • Forsake GTK and look for a less "framework-y" and more "library-y" type of GUI toolkit, that doesn't take thread control?
  • Any other options?
2
  • 1
    My pick would be to make the interpreter event driven, i.e. callable for a specific function invocation and use GTK's recommended approach. Haven't Javascript and Python been used with GTK? Maybe a look at those implementations would help.
    – joshp
    Mar 15, 2020 at 19:04
  • I’d consider passing the interpreter into GTK and telling it to kick the interpreter back off (in its current state) in whatever sub-thread setup GTK is happy with.
    – Telastyn
    Mar 16, 2020 at 1:00

1 Answer 1

2

once you call the C function g_application_run, the thread enters an endless listening loop inside GTK.

That is only part of what happens. What you have to do here first is to register callbacks for events, for example, using g_signal_connect, so GTK will call them (first, at program start, or later, when some user action like pressing a mouse button will fire the event). Those callbacks have to be C functions, but you probably want to map those calls to functions written in your own interpreted language.

So what you have to do here is

  • Implement some commands in your language for event registering in GTK. These commands need to wrap the actual calls to methods like g_signal_connect.

  • The wrappers need to pass the address of a fixed dispatcher method of your interpreter as the actual callback to the gtk method.

  • The data parameter of g_signal_connect has to contain an object holding a reference to the interpreter's state, as well as the equivalent of a function callback adress in your programming language.

Now, when the event fires, GTK will call the dispatcher method with that data object, and the dispatcher method will have take out the "callback adress" from there, initialize the instruction pointer accordingly and start the interpreter loop. The interpreter loop will end whenever the code for the specific event is completely executed. So what you get is not "one huge infinite interpreter loop", but several short-living interpreter invocations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.