Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Processes
Chapter 3 - Time Manager / Using the Time Manager


Using Application Global Variables in Tasks

When a Time Manager task executes, the A5 world of the application that installed the corresponding task record into the Time Manager queue might not be valid (for example, the task might execute at interrupt time when that application is not the current application). If so, an attempt to read the application's global variables returns erroneous results because the A5 register points to the application global variables of some other application. When a Time Manager task uses an application's global variables, you must ensure that register A5 contains the address of the boundary between the application global variables and the application parameters of the application that launched it. You must also restore register A5 to its original value before the task exits.

It is relatively straightforward to read the current value of the A5 register when a Time Manager task begins to execute (using the SetCurrentA5 function) and to restore it before exiting (using the SetA5 function). It is more complicated, however, to pass to a Time Manager task the value to which it should set A5 before accessing its application's global variables. The problem is that neither the original nor the extended Time Manager task record contains an unused field in which your application could pass this information to the task. The situation here is unlike the situation with Notification Manager tasks or Sound Manager callback routines (both of which provide an easy way to pass the address of the application's A5 world to the task), but it is similar to the situation with vertical retrace tasks.

Note
For a more detailed discussion of setting and restoring your application's A5 world, see the chapter "Memory Management Utilities" in Inside Macintosh: Memory. ·
One way to gain access to the global variables of the application that launched a Time Manager task is to pass to InsTime (or InsXTime) and PrimeTime the address of a structure, the first segment of which is simply the corresponding Time Manager task record and the remaining segment of which contains the address of the application's A5 world. For example, you can define a new data structure, a Time Manager information record, as follows:

TYPE TMInfo =              {Time Manager information record}
   RECORD
      myTMTask:   TMTask;  {original and revised TM task record}
      tmRefCon:   LongInt; {space to pass address of A5 world}
   END;
TMInfoPtr = ^TMInfo;
Note
The TMInfo record defined above is intended for use with the extended Time Manager. ·
Then you can install and activate your Time Manager task as illustrated in Listing 3-2. The global variable gTMInfo is an information record of type TMInfo.

Listing 3-2 Passing the address of the application's A5 world to a Time Manager task

PROCEDURE InstallTMTask;
CONST
   kDelay = 2000;                      {delay value}
BEGIN
   gTMInfo.myTMTask.tmAddr := @MyTask; {get address of task}
   gTMInfo.myTMTask.tmWakeUp := 0;     {initialize tmWakeUp}
   gTMInfo.myTMTask.tmReserved := 0;   {initialize tmReserved}
   gTMInfo.tmRefCon := SetCurrentA5;   {store address of A5 }
                                       { world}
   InsTime(@gTMInfo);                  {install the info record}
   PrimeTime(@gTMInfo, kDelay);        {activate the info record}
END;
With the revised and extended Time Managers, the task is called with register A1 containing the address passed to InsTime (or InsXTime) and PrimeTime. Thus, the Time Manager task simply needs to retrieve the TMInfo record and extract the appropriate value of the application's A5 world. Listing 3-3 illustrates a task definition for this purpose.

Listing 3-3 Defining a Time Manager task that can manipulate global variables

FUNCTION GetTMInfo: TMInfoPtr;
   INLINE $2E89;                       {MOVE.L A1,(SP)}

PROCEDURE MyTask;
VAR
   oldA5:   LongInt;                   {A5 when task is called}
   recPtr:  TMInfoPtr;
BEGIN
   recPtr := GetTMInfo;                {first get your record}
   oldA5 := SetA5(recPtr^.tmRefCon);   {set A5 to app's A5 world}

   {Do something with the application's globals here.}

   oldA5 := SetA5(oldA5);              {restore original A5 }
                                       { and ignore result}
END;
This technique works primarily because the revised and extended Time Managers do not care if the record whose address is passed to InsTime (or InsXTime) and PrimeTime is larger than expected. If you use this technique, however, be sure to retrieve the address of the task record from register A1 as soon as you enter the Time Manager task (because some compilers generate code that uses registers A0 and A1 to dereference structures).

IMPORTANT
You cannot use the technique illustrated in Listing 3-3 with the original Time Manager because it does not pass the address of the task record in register A1. To gain access to your application's global variables when using the original Time Manager, you would need to store your application's A5 value in one of the application's code segments (in particular, in the code segment that contains the Time Manager task). This technique involves the use of self-modifying code segments and is not in general recommended. Applications that attempt to modify their own 'CODE' resources may crash in operating environments (for example, A/UX) that restrict an application's access to its own code segments. ·


Previous Book Contents Book Index Next

© Apple Computer, Inc.
17 JUN 1996