Does anyone have any insight into what he was talking about here?
Does anyone have any insight into what he was talking about here?
NeWS has multiple PostScript threads, which must be able to block and re-start in the middle of parsing PostScript expressions or anything else that might block, so the entire interpreter has a switch statement for dispatching PostScript operators, and any of those operators which might block have "goto" labels so the interpreter can jump back into the middle of the operator when the threads gets switched back in.
The most complicated operator is the PostScript parser itself (the "file_execution" operator), which blocks in many places, and whose C source code was broken out into a .h file with the comment "be charitable and think of this as a procedure call".
This is actually quite similar to how C# and other languages implement co-routines under the hood. It's just written by hand in portable C.
Here's the comment explaining it:
/*
* The PostScript interpreter has a fairly simple basic structure:
*
* while (1) { 1. Pick up an object to interpret 2. Execute it }
*
* Part 1, picking up an object to interpret is handled by the statement that
* starts "switch (es->type)". es points to the top of the execution stack: a
* stack of sources of executable objects. The switch determines what kind of
* thing the object is being fetched from: an array, a string, ...
*
* Part 2, executing an object, is handled by the code that starts with the label
* "execute_top". It does some tests and switches on the type of the object
* being executed.
*
* All of this is complicated by the mechanism for blocking. If the process
* needs to block, say by needing to read a new buffer from a socket or by
* needing to wait for a message, then the interpreter needs to stop working
* on this process and leave information around that lets it restart. This is
* the "restart_state" variable: it is used as the index to a switch statement
* that is executed when the interpreter starts up, so it won't necessarily be
* intering the main loop of the interpreter at the top. There are cleaner
* ways of doing this, but they can't be written in C!
*/