Defining the Problem
Before discussing some of the techniques you can use for communicating between interrupt time code and task level code, it's important to note that the Mac OS supports three execution levels:
In common parlance, hardware interrupt and deferred task time are collectively referred to as "interrupt time." Application developers usually encounter interrupt time when writing ioCompletion routines, which typically run at deferred task time.
The most important consequence of these different execution levels is that you can only call a limited set of Mac OS routines from interrupt time. For example, you might have an application that issues an asynchronous call to read some data off the network. The call completes and executes your
Techniques for Solving the Problem
Over time, a number of techniques have been used to solve the problem of calling task level code from interrupt time. Some, but not all, of them are described here, along with an analysis of the pros and cons of each approach.
All of the solutions that follow, essentially, take the same approach. The program contains two threads of execution, one that runs at interrupt time and the other that runs at task level time. When it executes, the interrupt time code queues a request (using the queue management routines described in Inside Macintosh: Operating System Utilities ) on to some global queue. The task level code then polls this queue and processes any requests it finds.
The following snippets demonstrate this technique. First, we declare two queues, one that contains a pool of free queue elements (
Populating the free queue is left as an exercise for the reader.
Oh, and just for the sake of completeness, the
So the original problem can now be restated as "How do I get periodic time in order to process requests?"
Approach #1: Patching SystemTask, Installing a jGNEFilter, et al
One obvious approach is to patch some commonly called trap (for example,
The drawback to this approach is that it involves either patching or changing low memory globals, both of which are considered bad. Still, if you have already written an extension that installs a
Approach #2: Installing a Device Driver in the Device Manager's Unit Table
Another commonly used technique is to install a device driver in the Device Manager's unit table and set the
This technique has a number of drawbacks. First, it requires you to install a driver into the unit table, something that is tricky and may involve walking on low memory globals another compatibility liability.
The second drawback is a bit more obscure. If another device driver (or desk accessory) brings up a modal dialog in its
Incidentally, the other main point of Technote DV 19 -- that traditional Mac OS device drivers should be careful about which heap they're allocating their storage in -- is still very relevant.
The third drawback is that device drivers of type
In summary, this approach is only appropriate if you're working on a traditional Mac OS device driver of type
Approach #3: Posting a Notification Request
This technique is hinted at in Inside Macintosh: Devices and further described in Macintosh Technical Q &A NW 13. The gist of the idea is to use NMInstall to post a notification request with a response procedure but no sound, icon, string or mark. The Notification Manager polls its internal queue of notification requests at task level and calls your response procedure.
The technique works well. Contrary to popular belief, the Notification Manager does not serialize all requests and so your response procedure will be called even if there is another notification dialog up.
One caveat is that your notification response procedure is called in the context of some other application. You should tread lightly! Be careful about allocating too much memory and don't make assumptions about the current resource chain.
About the only problem with this approach is that it works against the spirit of the Notification Manager, which is meant as a simple method for notifying users about asynchronous tasks, not as a Poor Droid's Scheduling System. Before using this technique, make sure you read Technical Note TB 39 "Toolbox Karma."
Approach #4: Application Processing Requests
This technique uses an application to process the queued requests in its main event loop. Your interrupt routine puts the request onto a queue in the application's globals and wakes up the application using WakeUpProcess. When the application runs, it looks at the global queue and processes any requests on it.
If you don't have a suitable application handy, you can just create a background-only application (BOA) dedicated to this function. You can even put an INIT resource in BOA, as described in Technical Note PS 2 - "Background-Only Applications."
This technique is the best general-purpose method for solving the problem. It involves no trap patches and it doesn't touch low memory.
The only drawback to this approach is the memory requirements (approximately 50K) if you need a dedicated BOA to process requests. However, if you already have an application running, this technique is definitely the way to go.
Approach #5: Open Transport
Open Transport provides a good technique for scheduling task level time from interrupt time, namely
However, using OpenTransport restricts the systems your code will operate on. The decision as to whether to use this technique, and hence make your software dependent on OpenTransport, is for you to make based on both technical and marketing considerations.
Approach #6: Software Interrupts
Another approach that will be available in the future is the software interrupt routines, currently provided as part of the PCI driver services library. See Technote 1001, "On Power Macintosh Interrupt Management," for details.
There are a variety of techniques you can use to process requests received at interrupt time. The technique you choose depends on a number of factors outlined in this Technote. An application processing the requests on behalf of your interrupt code is the best general-purpose method for solving the problem because it represents the least compatibility liability.
Inside Macintosh: Operating System Utilities
Inside Macintosh: Devices
Inside Macintosh: Processes
Designing PCI Cards and Drivers for Power Macintosh Computers
"Be Our Guest: Background-Only Applications in System 7" in develop Issue 9.
PCI Device Driver article in develop (May 1995)
Contact ADC | ADC Site Map | ADC Advanced Search
|For information about Apple Products, please visit Apple.com.|
Contact Apple | Privacy Notice
Copyright © 2002 Apple Computer, Inc. All rights reserved.