Important: The information in this document is obsolete and should not be used for new development.
Accessing Application Global Variables in a VBL Task
The Operating System stores the address of the boundary between the current application's global variables and its application parameters in the microprocessor's A5 register. For this reason, most compilers generate references to application global variables as offsets from the address contained in the A5 register. Therefore, if the value in register A5 does not point to the boundary between your application's global variables and its application parameters, your attempts to access your application's global variables will fail.Ordinarily, applications do not need to keep track of the value in the A5 register. Although all applications share the register, the Process Manager keeps track of the address of your application's A5 world when a major or minor switch causes your application to yield the CPU to other processes, and it restores that value when your application regains access to the CPU. The A5 register is guaranteed to be correct for all code that your application executes directly (that is, for all code that is not executed in response to an interrupt or by a Toolbox or Operating System routine).
Because VBL tasks are interrupt routines, they might be executed when the value in the A5 register does not point to the A5 world of your application. As a result, if you want to access your application's global variables in a VBL task, you need to set the A5 register to its correct value when your VBL task begins executing and restore the previous value upon exit.
The solution to this problem is to find a memory location that both the main program and the VBL task can access. The main program can store the value of register A5
- Note
- For a more complete discussion of the A5 register, see the chapter "Memory Management Utilities" in Inside Macintosh: Memory. ·
there, and the VBL task can set A5 correctly by reading that value. The functionsSetCurrentA5
andSetA5
can be used for this purpose. The application can store the value of its A5 register by callingSetCurrentA5
. Then, at interrupt time, the task can begin by callingSetA5
to set the register to that value and end by callingSetA5
again, this time to restore the register to its initial value, the one used by the main program.The only memory location that a VBL task has access to is the address of the task record, as explained in the previous section, "Accessing a Task Record at Interrupt Time." So, if your application stores the value of A5 directly following the task record in memory, it can locate the value of A5 by first locating the task record. You can do this by defining a new data type (called
VBLRec
in Listing 4-6) whose first field contains the VBL task and whose second field contains a long integer specifying the value of the A5 register.Listing 4-6 Storing the value of the A5 register directly after the task record in memory
TYPE VBLRec = RECORD myVBLTask: VBLTask; {the actual VBL task record} vblA5: LongInt; {saved value of application's A5} END; VBLRecPtr = ^VBLRec;Now you can modify the application-defined procedure that installs a VBL task so that it stores the value of register A5 in thevblA5
field of theVBLRec
, as illustrated in
Listing 4-7.Listing 4-7 Saving the value of the A5 register when installing a VBL task
FUNCTION InstallVBL: OSErr; CONST kInterval = 6; {frequency in interrupts} BEGIN WITH gMyVBLRec.myVBLTask DO {initialize the VBL task} BEGIN qType := ORD(vType); {set queue type} vblAddr := @DoVBL; {set address of VBL task} vblCount := kInterval; {set task frequency} vblPhase := 0; {no phase} END; myVBLRec.vblA5 := SetCurrentA5; {get our A5} InstallVBL := VInstall(@gMyVBLRec.myVBLTask); END;You must also modify the VBL task so that it sets and restores the value of register A5 correctly. Listing 4-8 illustrates a simple VBL task that increments the global variablegCounter
and then resets itself to run again after the specified number of interrupts.Listing 4-8 Setting up the A5 register and modifying a global variable in a VBL task
PROCEDURE DoVBL; CONST kInterval = 6; {frequency in interrupts} VAR curA5: LongInt; {stored value of A5} recPtr: VBLRecPtr; {pointer to task record} BEGIN recPtr := VBLRecPtr(GetVBLRec); {get address of task record} curA5 := SetA5(recPtr^.vblA5); {set our application's A5 } { and store old A5 in curA5} gCounter := gCounter + 1; {modify a global variable} {Reset vblCount so that this procedure executes again.} recPtr^.myVBLTask.vblCount := kInterval; curA5 := SetA5(curA5); {restore the old A5 value} END;Because of the optimizations performed by some compilers, the actual work of the VBL task and the setting and restoring of the A5 register might have to be placed in separate procedures. If necessary, you can define a routineDoVBL
that loads the proper value of A5, calls another routine calledRunVBL
, and then restores the old value of A5. TheRunVBL
routine does the work of the VBL task and resets the task record'svblCount
field so that theDoVBL
routine executes again. Listing 4-9 illustrates a sample definition of theRunVBL
function that modifies an application global variable.Listing 4-9 Modifying application global variables in a VBL task
PROCEDURE RunVBL (aRecPtr: VBLRecPtr); CONST kInterval = 6; {frequency in interrupts} BEGIN gCounter := gCounter + 1; {modify global variable} {Reset vblCount so that this procedure executes again.} aRecPtr^.myVBLTask.vblCount := kInterval; END;Listing 4-10 shows how to callRunVBL
from the VBL task.Listing 4-10 Setting up and restoring the A5 register in a VBL task
PROCEDURE DoVBL; VAR curA5: LongInt; {stored value of A5} recPtr: VBLRecPtr; {pointer to task record} BEGIN recPtr := VBLRecPtr(GetVBLRec); {get address of task record} curA5 := SetA5(recPtr^.vblA5); {set our application's A5 } { and store old A5 in curA5} RunVBL(recPtr); {run the actual VBL task} curA5 := SetA5(curA5); {restore the old A5 value} END;If this separation of routines is necessary, you must make sure that the two routines (DoVBL
andRunVBL
) are in the same code segment.