In addition to some simple GUI controls for debugging microcode, I want a command-line debugging interface. I plan to use Tcl and Readline, as I’ve done in Altogether, my Xerox Alto simulator. However now I want this command-line interface to be inside a window along with a menu bar and possibly other widgets. So the first step is to find a GTK terminal widget.
Turns out there are two of them, ZVT and VTE.
While ZVT has been around longer, it appears that VTE is now preferred. Fedora Core 1 includes both. Neither one does exactly what I want, but I’ve chosen VTE.
Both ZVT and VTE support two modes of operation:
- output-only, with no child process
- forking a child process to run a command, with input and output from the terminal widget
I need both input and output, but I don’t want a child process. I want both sides of the PTY to attach to the same process. To understand why, a brief explanation of how CASMSIM is structured might be helpful.
The initial thread of the process is responsible for the GUI. It creates the widgets, initializes the simulator, then falls into gtk_main(). I call this the GUI thread.
The simulation core runs in a separate thread that is created when the GUI thread is starting up. The simulation thread is responsible for executing the microinstructions and maintaining the simulation state.
The GUI and simulation threads communicate by using the thread synchronization facilities provided by Glib. There is a GMutex protecting the simulation state. When the simulation is idle and can accept a command from the GUI thread, it releases the mutex.
While the simulation is running, it periodically sleeps in order to operate in real time. Otherwise the simulation would run many times faster than the real calculator. When it sleeps, it releases the mutex. This allows the GUI thread an opportunity to tell the simulator to halt or examine its state.
While running, the simulator has to occasionally cause the display to update. Unfortunately I have not come up with any particularly good way to pass an asynchronous event like this from the simulation thread to the GUI thread. One approach would be to use a pipe or FIFO, with the main thread using gtk_input_add() in order to have a callback execute when the simulator thread writes to the pipe. This would be fairly clean on Linux, but I don’t think it would be portable to Windows, so I’ve chosen not to do it that way. I think Glib and GTK should provide a way for this type of notification to be implemented more abstractly. For instance, there might be a gtk_thread_event_add() function to register for a callback, and a Glib function to assert the thread event. Internally this could be implemented using gtk_input_add() on Posix systems, and using some other mechanism on Windows.
Because I’m not using the method described above, currently the display is implemented by a direct callback function, so the display update is actually performed in the simulation thread context. This is the only time that GTK operations are done by the simulation thread.
The plan for the debugger is to run it in a third thread. The debugger thread would run Tcl and Readline, parse commands, and execute them. The execution of most commands would involve communication with the simulation thread, so it would use the GCond and GMutex variables in the same was as the GUI thread.
So the VTE Widget running in the GUI thread would hold the file descriptor for the master side of a PTY, and the debugger thread would do I/O to the slave side of the same PTY (using the slave file descriptor).
This PTY scheme is not portable to Windows except perhaps if the Microsoft Windows Services for Unix is installed. At least it is now a no-fee download. But I don’t mind if the debugger is simply #ifdef’d out on Windows, as I’ll personally only run it on Linux.
vte_terminal_new() creates a VTE widget, but does not associate it with a PTY. At this point you can do output to the terminal display using vte_terminal_feed(). The function vte_terminal_fork_command() will open the PTY, fork a child, and has the child process exec a specified program. What I want is a function that does not fork or exec. It could either return both the master and slave file descriptors for the PTY, or it could accept the PTY master file descriptor as an argument.
I’ve patched VTE to implement the latter. I added a function vte_terminal_add_pty(), which attaches a user-supplied master PTY file descriptor to the widget. It turned out to only need a half-dozen lines of code. I’m probably overlooking some details such as signal handling, but it basically works.
I’ve sent the patch to Nalin Dahyabhai, the author of VTE, and hope that this feature will be included in a future release of VTE.
In the mean time, I’ll put the patch as well as RPMs for Fecora Core 1 on this web page.
After I did this, I discovered that the Gnome version of Genius, a nifty calculator program by George Lebl, also uses VTE with Readline. George’s approach was to run a helper application as the child process, which then uses a FIFO to communicate the input stream back to the parent process. If you need to use the stock VTE widget, this is a better approach.