Threaded Apple Events
Volume Number: 12
Issue Number: 4
Column Tag: Toolbox Techniques
Threading Apple Events 
Or: How I Learned to Stop Worrying and Love to Bomb
By Grant Neufeld, InfoDesign Corporation
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
As Jon Wiederspan points out elsewhere in this issue, threading is becoming a serious
problem for webmasters intent on getting speed out of their servers. In C the problem
is compounded because the AppleEvent Manager does not handle multiple simultaneous
events (and Apple events are used to communicate with CGI applications). Grant
Neufeld has developed a solution to this problem and distributes a CGI framework that
implements it for you. In this article, he shows us how it’s done.
On the Thread Manager, see also:
http://www.mactech.com/Articles/Vol.10/
10.11/Thread-Manager.bhtml#Thread-Manager
http://www.mactech.com/Articles/Vol.10/ 10.11/Threading.bhtml#Threading
For Frontier as a possible solution to threading difficulties, see MacTech Magazine
12.1 (January 1966) 63-65; see also the technologies discussed by Jon in our
MacWorld Expo report. On writing your CGI in C, see MacTech Magazine 11.9
(September 1995) 33-42.
The Problem of Reentrancy
As I recently discovered, trying to combine Apple events with the Thread Manager is an
awkward and mind-altering experience. There are some fundamental - and obscure -
requirements that are easy to miss (or so I’d like everyone to believe, so that I don’t
have to be so embarrassed by my own oversight).
you call it, you can’t call it again until the event finishes processing. I didn’t know
this when I originally designed the threading for my CGI framework, so I happily set
before finishing the first call - all through the glory of the Thread Manager. My
incorrect code looked like:
/* warning: bad code! Don’t try this at home! */
/* Called from main event loop when a high level event arrived. */
void doHighLevelEvent ( EventRecord *theEvent )
OSErr theErr;
ThreadID theThread;
// MyNewThreadFromPool is just a custom method to simplify
// using threads from a pool.
// Remember: this particular example of Apple event threading
// is wrong - don’t do it this way!
theErr = MyNewThreadFromPool ( doAEThread, theEvent,
(void**)nil, &theThread );
}
if ( !gHasThreadMgr || (theErr != noErr) ) {
// If threading isn’t available, or the attempt to thread failed,
// process the Apple event without threading.
theErr = AEProcessAppleEvent ( theEvent );
}
}
/* The thread entry function that was used to process the Apple event. */
pascal void * doAEThread ( void *theEvent )
OSErr theErr;
ThreadID currentThread;
theErr = AEProcessAppleEvent ( (EventRecord *)theEvent );
GetCurrentThread ( ¤tThread );
DisposeThread ( currentThread, (void *)theErr, true );
return (void *)theErr;
}
The amazing thing is that nobody - including me - caught the error until Wayne
K. Walrath took a look at the code (in the eleventh release) and noticed my mistake. By
then, programs were already shipping and in commercial use - including my own
Random URL CGI.
So, why didn’t anyone notice the code crashing? The code we all had in our
threads happened to be fast enough to finish before new Apple events came in. This
doesn’t mean it would never crash; given a situation where two Apple events came in
almost simultaneously, the code would certainly flop.
Thankfully, I had the prescience to include a suitable disclaimer and label the
code “beta” and “subject to errors” to cover my legal posterior. However, my public
esteem was in jeopardy! Worse still, I couldn’t touch the code for a few days after
receiving the bug report because of job obligations. Actually, that was a good thing
because the time spent thinking about the code gave me a good basis to start from when
I did actually get down to work.
Moral: Think before you code. (Carefully reading the documentation isn’t a bad
idea either!)
Suspending Apple Events
My original code attempted to thread every Apple event. This is not the case with the
corrected code. A new thread should only be initiated within the context of an
Suspension of Apple events involves calls to the functions
If the Apple event does not suspend, you can’t make any further calls to
finishes. If you want to be creative, you can write your own Apple event dispatcher to
allow reentrancy, thereby making it easier to deal with threads. People might call you
crazy, but you can do it.
Which brings us to the obligatory complaint about lack of sufficient (and clear)
documentation (which is part of the reason I’m writing this). Inside Macintosh:
calls and provides no sample code for suspending Apple events (see IM:IAC 4.85-88).
Hopefully, this article helps fill that gap.
The CGI Apple event is the only one I’m concerned about threading for my
framework, so I didn’t bother with any of the other events. I handle the Apple event