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 6 - Deferred Task Manager / Using the Deferred Task Manager


Deferring a Slot-Based VBL Task

As indicated earlier in this chapter, you are most likely to use the Deferred Task Manager when dealing with slot interrupts. All slot interrupts, including slot-based VBL interrupts, disable all other slot interrupts. For this reason, as a slot-interrupt routine (installed using SIntInstall) or a slot-based VBL interrupt routine (installed using SlotVInstall) runs to completion, interrupts at that level and below are disabled. You can help improve interrupt handling by using the Deferred Task Manager to defer your slot-interrupt processing until interrupts have been reenabled.

Listing 6-5 provides another example of how to use the Deferred Task Manager. The program defined there defers the cursor updating that would normally occur as a slot-based VBL task. The time required to update the cursor can range from about 700 to 900 microseconds for monitors having a screen depth of 1 to 8 bits. Because the cursor updating is done at slot-based VBL time, all other slot interrupts are put off
until updating is finished. This might adversely affect interrupt processing by your application. Accordingly, it is useful to defer the cursor updating to noninterrupt time by installing the updating as a deferred task.

The program defined in Listing 6-5 replaces the cursor-updating routine pointed at by the system global variable jCrsrTask with a different routine. This new routine installs the original routine as a deferred task.

Listing 6-5 Deferring cursor updating to noninterrupt time

*** MyDefTask
TaskBegin
MyDefTask
   DC.L        0                 ;qLink   (handled by OS)
   DC.W        0                 ;qType   (queue type: dtQType)
   DC.W        0                 ;dtFlags (reserved)
   DC.L        0                 ;dtAddr  (pointer to routine to be executed)
   DC.L        0                 ;dtParm  (optional parameter; not used here)
   DC.L        0                 ;dtReserved (should be zero)
SysCrsrTask
   DC.L        0                 ;pointer to system jCrsrTask
DefCrsrFlag
   DC.W        0                 ;1 if using a deferred task, 0 otherwise
PendingFlag
   DC.W        0                 ;1 if a jCrsrTask is pending, 0 otherwise

*** MyjCrsrTask
MyjCrsrTask
   MOVEM.L     A0/A1/D0,-(SP)
   LEA         PendingFlag,A0    ;see if a deferred jCrsrTask task is pending
   TST.W       (A0)
   BNE.S       bailOut           ;if yes, exit
   MOVE.W      #1,(A0)           ;if no, set the pending flag
   LEA         MyDefTask,A0      ;point to our deferred task element
   LEA         DefjCrsrTask,A1   ;get address of deferred task routine
   MOVE.L      A1,dtAddr(A0)     ;set up pointer to routine
   MOVE.W      #dtQType,dtType(A0)     ;set queue type
   _DTInstall                    ;install the task
   MOVEM.L     (SP)+,A0/A1/D0
   RTS
bailOut
   MOVEM.L     (SP)+,A0/A1/D0
   RTS
DefjCrsrTask
   MOVEM.L     A0,-(SP)
   LEA         SysCrsrTask,A0    ;get system cursor task address
   MOVEA.L     (A0),A0
   JSR         (A0)              ;and call it
   LEA         PendingFlag,A0    ;clear pending call flag
   CLR.W       (A0)
   MOVEM.L     (SP)+,A0
   RTS
TaskEnd

*** Entry
TaskSize       EQU   TaskEnd-TaskBegin

Entry
   MOVE.L      #TaskSize,D0      ;put TaskSize into D0
   _NewPtr     SYS,CLEAR         ;make a block in the system heap
   BNE.S       Quit              ;no room in system heap, so quit
   MOVE.L      0,A2              ;got a good pointer; keep a copy
   MOVE.L      A0,A1             ;set up registers for BlockMove
   LEA         MyDefTask,A0   
   MOVE.W      #TaskSize,D0
   _BlockMove                    ;copy the task etc. into system heap
   LEA         dtQElSize(A2),A0  ;move original task pointer into our 
   MOVE.L      jCrsrTask,(A0)    ; pointer holder
   LEA         dtQElSize+4(A2),A0;replace jCrsrTask pointer with a pointer
   MOVE.L      A0,jCrsrTask      ; to our jCrsrTask

Quit
   RTS                           ;exit the program
END
This code allocates a block of memory in the system heap. The allocated block is large enough to hold a deferred task element, a pointer to the original cursor-updating routine, and the replacement routine. The replacement routine simply retrieves the relevant information (namely, the deferred task element and the saved address of the original cursor-updating routine) stored in that block of memory and calls _DTInstall to install a deferred task. The address of the replacement routine is placed into the low-memory global variable jCrsrTask, whose original contents are stored in the system heap.

Once the program defined in Listing 6-5 is run, the cursor-updating routine is subsequently performed with interrupts enabled, thereby allowing other interrupts. Because the cursor-updating routine is run with interrupts enabled, you may see a slight flickering of the cursor when using this technique.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
17 JUN 1996