Technote 1104Interrupt-Safe RoutinesApple Computer, Inc. devsupport@apple.com |
CONTENTSIntroduction |
Traditional Mac OS has a badly defined set of extremely heterogeneous programming environments. In some of these environments, your code can access some system services but not others. The names given to these environments are often overloaded and confusing. This results in a lot of programmer confusion. This technote attempts to clear up this confusion by assigning each of the execution levels a unique name, describing how and why your code might find itself running at a particular execution level, and outlining the restrictions your code might face when running at that level. |
Execution LevelsTraditional Mac OS supports the following execution levels:
The native device driver model defines the following levels in addition to those listed above:
These execution levels are modeled after the Mac OS 8 execution levels and correspond roughly with their traditional counterparts. However, the distinction is important in certain circumstances.
|
Interrupts: 68K and PowerPCNote that this discussion does not discuss the PowerPC native interrupt mechanism. On Power Macintosh computers running traditional Mac OS, the PowerPC native interrupts are handled by a nanokernel, which routes the interrupt through the 68K emulator. Where this note references 68K-specific concepts, you can safely assume that this behavior is emulated by the low-level PowerPC system software on machines with PowerPC processors. Note that the execution level is to some extent independent of the processor interrupt mask, i.e. the value stored in the 680x0 SR register. In some cases interrupts can be enabled during an interrupt (i.e. while running a deferred task); in some cases interrupts can be disabled at SystemTask time (i.e. Enqueue disables interrupts to guarantee mutual exclusion). Level DescriptionThis section describes each of the execution levels in detail. Hardware InterruptWhat it is Deferred TaskWhat it is SystemTaskWhat it is Native Hardware InterruptWhat it is Secondary InterruptWhat it is TaskWhat it is |
Execution Levels in Other DocumentationVirtual MemoryThe virtual memory documentation (i.e. chapter 3 of Inside Macintosh: Memory and Technote ME 09, "Coping with VM and Memory Mappings") says that page faults are not allowed at "interrupt time". This has caused a lot of confusion amongst programmers who have heard that, for example, Device Manager completion routines are "interrupt time", and hence assume that paging is unsafe in MacTCP completion routines. In the light of the above description, it's easy to clear up that confusion. As far as virtual memory is concerned, "interrupt time"
means any hardware interrupt that hasn't been deferred by VM
itself or using It's also important to stress the difference between
Deferred Task Time, and a hardware interrupt that's been
deferred using Open TransportThe Open Transport documentation caused much confusion by saying that Open Transport could not be called at "interrupt time". What this means is that you can only call Open Transport from System Task time, or Deferred Task level. So you can call Open Transport at execution levels that would normally be considered "interrupt time" (i.e. from a Deferred Task), as long as you don't call it from hardware interrupt level. [Or native hardware interrupt level, or secondary interrupt level.] ToolboxMost toolbox routines cannot be called at "interrupt time". Unlike the two cases described above, in this case "interrupt time" refers to any non-SystemTask execution level. Also note that there are many different reasons why toolbox routines can not be called at interrupt time. Some routines, like the Memory Manager, rely on global data structures that are not interrupt-safe. Other routines might move or purge unlocked handles. Still others, like synchronous calls to the Device Manager, are architecturally inaccessible. Still others, like ReadDateTime, rely on interrupts in order to complete, and hence cannot be called when interrupts are disabled. |
Operating System UtilitiesEnqueue and Dequeue are interrupt-safe, and may be used at any time. FormatRecToString (formerly Format2Str), StringToExtended (formerly FormatX2Str), and ExtendedToString (formerly FormatStr2X) are interrupt-safe as well.
|
Device ManagerAsynchronous Prime, Control or Status driver calls are interrupt-safe and must remain so. It should always be possible to call a driver with a Prime, Control or Status call asynchronously at interrupt time. It should never be possible to call a driver synchronously at interrupt time. One confusing point is the use of the Open and Close calls. These calls are shared with the file system. Any Open call to the device manager (even asynchronous calls) can move or allocate memory, and therefore cannot be made at interrupt time. Similarly a Close call to the device manager may deallocate memory, and cannot be made at interrupt time. Open and Close can be called asynchronously if the calls are made to the file manager. The current Open/Close code decides that a call is for the device manager if
From the viewpoint of writing a driver, you cannot move or allocate memory
in your driver if your driver is called asynchronously OR synchronously.
You should only move or allocate memory in your driver in response to an immediate
call from a client that you know is running at SystemTask, for example
the For more information about why moving or allocating memory while handling a synchronous call is bad, consult Technote 1067: "Traditional Device Drivers: Sync or Swim" From the viewpoint of using a driver, you should always assume that any synchronous call to a driver may move or allocate memory. |
NetworkingClassic AppleTalk is implemented as a set of device
drivers, and hence may be called at interrupt time as long
as the calls are made asynchronously. MacTCP is split into
two parts. The core TCP, UDP, and ICMP support is
implemented as a device driver, and hence may be called at
interrupt time as long as the calls are made asynchronously.
The Domain Name Resolver (DNR) is implemented as glue that
you should avoid calling at interrupt time. The |
Open Transport and Interrupt RoutinesOpen Transport also defines many support routines that clients can use to deal with the communications environments. These are described in the Utility routine section toward the end of this document. The Open Transport API is intended to provide
high-performance communications services to client
applications. In keeping with this goal, most Open Transport
functions may not be called at interrupt time. This includes
any interrupt routine from an external device, VBL tasks, or
Time Manager. Open Transport functions may only be called at
primary task time (also called System Task time, or at
Deferred Task time (also called Secondary Interrupt level)
scheduled by using either the Open Transport functions
In order to support calling at primary interrupt time,
Open Transport would have to be able to turn interrupts on
and off to protect critical resources. On PowerPC machines,
this requires a costly mixed-mode switch. Open Transport
provides the functions After having said this, many of the Open Transport utilities routines are usable at primary interrupt time. Refer to Appendix F of "Open Transport Client Note" for a list of those functions. |
Power ManagerInstalling and removing a sleep queue entry (using SleepQInstall and SleepQRemove) is safe. BatteryStatus and SetWUTime are interrupt safe.
|
Notification ManagerYou may call NMInstall and NMRemove at interrupt time.
|
Desktop ManagerAll the asynchronous calls are safe. PBDTAddAPPLAsync, etc. call be called at interrupt time. |
File SystemAny asynchronous file system call is interrupt-safe. This includes:
|
GestaltYou should not call Gestalt at interrupt time unless you know that the Gestalt selector is interrupt-safe. This generally applies only for those Gestalt selectors which you yourself have installed. In Inside Macintosh: Operating System Utilities on page 1-31 there is a long description of when it might or might not be safe to call Gestalt. This description may be summarized as follows: When passed one of the Apple-defined selector codes, the Gestalt function does not move or purge memory and therefore may be called at any time, even at interrupt time. However, selector functions associated with non-Apple selector codes might move or purge memory, and third-party software can alter the Apple-defined selector functions. In practice, Apple has not consistently conformed to this restriction when creating new Gestalt selectors. Apple-supplied Gestalt selectors may move or purge memory. Therefore, it is safest always to assume that Gestalt could move or purge memory. To repeat: you should not call Gestalt at interrupt time unless you know that the Gestalt selector is interrupt-safe. This generally applies only for those Gestalt selectors which you yourself have installed |
Sound ManagerMACEVersion, SndGetSysBeepState, SndManagerStatus,
SndPauseFilePlay, SndSetSysBeepState, and
SndSoundManagerVersion are all interrupt-safe.
|
Process ManagerGetFrontProcess, GetCurrentProcess, GetNextProcess, SameProcess, and WakeUpProcess are interrupt safe. |
Time ManagerInsTime, InsXTime, PrimeTime and RmvTime are interrupt-safe. |
Process to Process Communications ToolboxAll asynchronous PPCToolbox calls are interrupt-safe. |
Deferred Task ManagerDeferred task initialization via DTInstall is interrupt safe. Because the deferred task is executed during a hardware interrupt cycle, it should not allocate, move, or purge memory (either directly or indirectly) and should not depend on the validity of handles to unlock blocks. |
Vertical Retrace ManagerSlotVInstall, VRemove, SlotVRemove, AttachVBL, DoVBLTask, and GetVBLQHdr are all interrupt safe. |
Libraries
Anything in <PLStringFuncs.h> is safe, as long as the implementations do not reside in an unloaded segment. |
PackagesDo not call any routine in a Package at interrupt time. Any routine found in a Package (e.g. StandardFile, International Utilities) is not interrupt-safe, since the package may not be in memory at that time. |
Routines Which May Be Called At Interrupt TimeThis is a summary list of routines which may be called at interrupt time. Those routines with an asterisk (*) have restrictions on their use; see the main body of this Technote for details. AddrToName* AttachVBL BatteryStatus BlockMove Close* PBControlAsync DebuggerEnter DebuggerExit DebuggerGetMax DebuggerLockMemory DebuggerPoll DebuggerUnlockMemory DeferUserFN Dequeue DoVBLTask Enqueue ExtendedToString Format2Str FormatRecToString FormatStr2X FormatX2Str GetCurrentProcess GetFrontProcess GetNextProcess GetPageState GetPhysical GetVBLQHdr HInfo* InsTime InsXTime LockMemory* LockMemoryContiguous MACEVersion MXInfo* NMInstall NMRemove OTCreateDeferredTask OTDestroyDeferredTask OTScheduleDeferredTask OTScheduleInterruptTask Open* PBCatSearchAsync PBCloseAsync* PBCreateFileIDRefAsync PBDTAddAPPLAsync PBDeleteFileIDRefAsync PBExchangeFilesAsync PBGetForeignPrivs PBGetVolMountInfo PBGetVolMountInfoSize PBHGetVolParmsAsync PBHOpenAsync* PBHOpenDFAsync* PBHOpenDenyAsync* PBHOpenRFAsync* PBMakeFSSpecAsync PBOpenAsync* PBOpenDFAsync* PBOpenRFAsync* PBReadAsync PBResolveFileIDRefAsync PBSetForeignPrivAsync PBWriteAsync PageFaultFatal Prime PrimeTime RmvTime SameProcess SetWUTime SleepQInstall SleepQRemove SlotVInstall SlotVRemove SndDoCommand* SndGetSysBeepState SndManagerStatus SndPauseFilePlay SndSetSysBeepState SndSoundManagerVersion PBStatusAsync StrToAddr* StringToExtended StripAddress SwapMMUMode Translate24to32 UnholdMemory UnlockMemory VRemove WakeUpProcess |
Thanks to Jim Luther, Cameron Esfahani, Matt Mora, Pete Gontier, Jim Murphy, Dave Lyons, and Peter N. Lewis.
Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help