System Queues
Volume Number: 5
Issue Number: 1
Column Tag: Forth Forum
By Jörg Langowski, MacTutor Editorial Board
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
“Looking at system queues”
The utility that I’m going to describe this month can be used to look at various
queues of the Macintosh operating system. I was always curious to know what’s going
on in the background of my machine while I’m working away; that’s how this example
came to be. At the same time, the program contains another example of popup menus
(for which the correct trap call has been added in Mach2.14), and how to use the
userData field in the user variable area to display messages in a task window.
A number of queues are maintained by the Mac operating system; the example
won’t list all of them, but some of the more important ones. Queues are linked lists of
information blocks. Each block contains the address of the next list element in its first
four bytes, a 16-bit number indicating the queue type in its next 2 bytes, and variable
length information thereafter, as indicated below:
Fig.1: general structure of a Macintosh queue
The first element of a queue is called the queue header and the last one the queue
tail. The queue tail has a link address of zero, meaning no more elements will follow.
One can access the elements of a queue through a pointer to its header which is usually
kept in a low memory global variable. For some of the queues the tail’s location is kept
in another global variable for faster access.
The low memory addresses of the queues that our utility will display - vertical
blanking queue, volume control block queue, drive queue, file system queue, event
queue, deferred task queue and time manager queue - are defined at the beginning of the
listing. (Since the address of the TM queue is not given in IM, I dug it out of a
disassembly of the _InsTime trap.)
Structure of the program
We’ll set up a Mach 2 terminal task that contains the usual Apple, File and Edit
menus (for desk accessories). The task window will contain a bar display for each
queue which gives a visual indication of the size of the queue. The display bars are
‘click-sensitive’; when the mouse is clicked on one of them, a popup menu is displayed
which shows the name of the queue. When this name is selected, a second window will
be opened with information about the queue elements. That second window will
disappear on a mouse click.
Inter-task communication in Mach2
I was happily hacking away on the example, got the rectangles drawn in the right
places, the popup menus setup (note the slight difference in the interface that’s used
here - built-in - from my code in MT V4#4), when I got a row of bad bombs trying to
write text into a second window from the queue-monitoring task. Just ADDing a new
window, then doing a _SetPort and using the Mach2 text I/O routines wouldn’t work at
all. When it finally dawned on me what was I actually doing? The main task detects a
mouse down in the content region of its window and calls the content handler (see
listing) to find out which rectangle it has been clicked in, which menu to display, and
to output the text in the second window. Now that is a totally trivial piece of code in a
single task program like one would write in C or Pascal most of the time. In Mach2,
things are different.
The mouse down event is not detected by the task that is supposed to handle it, but
by the (in)famous I-O task, present in any Mach2 application. That task calls
WaitNextEvent, detects which window the mouse was clicked in, and calls the event
handler of the task that owns the window. So while we’re executing the event handler,
we’re actually in the context of the I-O task! The standard Mach2 console output would
be sent to the window associated with the I-O task. Unfortunately, there is no such
window - therefore bomb.
The bottom line is that you can’t use the Forth text I-O routines from event
handlers that are called through the I-O task. You have to rely on the means that Mach2
provides to do inter-task communication and make a terminal task do the text output.
Mach2 text output from event handlers
How is this achieved? The User area of a Mach2 task contains two locations,
UserData and UserVector. When a non-zero value is stored in UserData, the routine
pointed to by UserVector will be executed. So all we need to do is define a user vector
handling routine, and have the content handler of the task store some message in
UserData.
The content handler of our main window simply stores the menu ID of the selected
popup menu in UserData. The user vector handler finds this menu ID (it gets passed on
the stack), and calls the corresponding queue display routine.
The queue display routines use a second window, qInfo. In order to have the output
appear in that window and not on top of our bar display, we have to change the task
window pointer momentarily; this is done by storing the qInfo window pointer in the
user variable taskWindowPointer, doing the output and later restoring the original
pointer.
Queues displayed
The utility displays seven queues (and you can easily add more): vertical
blanking, volume control block, drive, event, file system, deferred task, and time