home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / µSim 1.1 / FabLibsƒ / FabTaskManager.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-03  |  9.1 KB  |  438 lines  |  [TEXT/CWIE]

  1. #include    "FabTaskManager.h"
  2. #include    "FabWmemman.h"
  3.  
  4. enum {
  5. fabSysQueueType = 25,
  6. fabTimerQueueType
  7. };
  8.  
  9. typedef struct SysTaskInfo SysTaskInfo, *SysTaskInfoPtr;
  10.  
  11. struct SysTaskInfo {
  12.     QElemPtr    link;
  13.     short    qType;
  14.     Boolean    autoDestroy;
  15.     void    *parameter;
  16.     void (*tmProc)(void *);
  17. #if    !GENERATINGCFM
  18.     long    savedA5;
  19. #endif
  20.     };
  21.  
  22.  
  23. struct TimerTaskInfo {
  24.     TMTask    theTask;
  25.     void    *parameter;
  26.     void (*tmProc)(void *);
  27. #if    !GENERATINGCFM
  28.     long    savedA5;
  29. #endif
  30.     };
  31.  
  32. typedef struct TimerTaskInfo TimerTaskInfo, *TimerTaskInfoPtr;
  33.  
  34.  
  35. struct NewTimerTaskInfo {
  36.     QElemPtr        qLink;
  37.     int            qType;
  38.     Boolean            autoDestroy;
  39. //    long            tmCount;
  40.     UInt32            timeWakeUp;
  41.     void            *parameter;
  42.     void        (*tmProc)(void *);
  43. /*
  44. #if    !GENERATINGCFM
  45.     long    savedA5;
  46. #endif
  47. */
  48.     };
  49.  
  50. typedef struct NewTimerTaskInfo NewTimerTaskInfo, *NewTimerTaskInfoPtr;
  51.  
  52.  
  53. static QHdr    sSysQueueHdr = { 0, nil, nil};
  54. static QHdr    sTimerQueueHdr = { 0, nil, nil};
  55.  
  56.  
  57. static OSErr    gTimerTrigger_Held = -1;
  58.  
  59.  
  60. static void ExecuteSystemTask(SysTaskInfoPtr theTaskPtr);
  61. static void ExecuteTimerTask(NewTimerTaskInfoPtr theTaskPtr, UInt32 currentTime);
  62.  
  63.  
  64. #if GENERATINGCFM
  65. static TimerUPP    gTriggerUPP;
  66.  
  67. static void TimerTrigger(TMTaskPtr theTaskPtr);
  68. #else
  69. #pragma parameter TimerTrigger68K(__A1)
  70. static asm void TimerTrigger68K(TMTaskPtr tPtr);
  71. #endif
  72.  
  73.  
  74. void ExecuteSystemTask(SysTaskInfoPtr theTaskPtr)
  75. {
  76. void (*proc)(void *);
  77. void    *param;
  78.  
  79. (void) Dequeue((QElemPtr)theTaskPtr, &sSysQueueHdr);
  80. param = theTaskPtr->parameter;
  81. proc = theTaskPtr->tmProc;
  82. if (theTaskPtr->autoDestroy)
  83.     Fab_DestroySystemTask(theTaskPtr);
  84. proc(param);
  85. }
  86.  
  87. void ExecuteTimerTask(NewTimerTaskInfoPtr theTaskPtr, UInt32 currentTime)
  88. {
  89. void (*proc)(void *);
  90. void    *param;
  91.  
  92. if (theTaskPtr->qType < 0 &&
  93.         currentTime > theTaskPtr->timeWakeUp) {    // no need to be atomic here, runs at idle time
  94.     theTaskPtr->qType &= (~0U >> 1);    // portable form; turns off sign bit
  95.     param = theTaskPtr->parameter;
  96.     proc = theTaskPtr->tmProc;
  97.     if (theTaskPtr->autoDestroy)
  98.         Fab_DestroyTimerTask(theTaskPtr);
  99.     proc(param);
  100.     }
  101. }
  102.  
  103.  
  104. #define    kTimerTask68KClassicSize    20
  105. #define    kTimerTaskPPCSize    48
  106.  
  107. void InitFabTaskManager_OldTimers(void)
  108. {
  109. long    Gresp;
  110.  
  111. #if    GENERATINGCFM
  112. gTriggerUPP = NewTimerProc(TimerTrigger);
  113. #endif
  114.  
  115. if (Gestalt(gestaltVMAttr, &Gresp) == noErr && (Gresp & (1L << gestaltVMPresent))) {
  116.     gTimerTrigger_Held = HoldMemory(
  117. #if    GENERATINGCFM
  118. TimerTrigger, kTimerTaskPPCSize
  119. #else
  120. TimerTrigger68K, kTimerTask68KClassicSize
  121. #endif
  122.         );
  123.     }
  124. }
  125.  
  126. void CleanupFabTaskManager_OldTimers(void)
  127. {
  128. if (noErr == gTimerTrigger_Held)
  129.     (void) UnholdMemory(
  130. #if    GENERATINGCFM
  131. TimerTrigger, kTimerTaskPPCSize
  132. #else
  133. TimerTrigger68K, kTimerTask68KClassicSize
  134. #endif
  135.         );
  136. }
  137.  
  138.  
  139. void Fab_ScheduleSystemTask(void *theTaskPtr)
  140. {
  141. #if    !GENERATINGCFM
  142. long    oldA5;
  143.  
  144. oldA5 = SetA5(((SysTaskInfoPtr)theTaskPtr)->savedA5);
  145. #endif
  146.  
  147. Enqueue((QElemPtr)theTaskPtr, &sSysQueueHdr);
  148.  
  149. // CW 11 (68K) generates an A5-relative reference for the following
  150. // automatic initializer; had we placed this at the very beginning
  151. // of this function, before the SetA5 call,
  152. // we'd have crashed non-reproducibly (as Masatsugu Nagata, the first and only victim...)
  153. {
  154. ProcessSerialNumber myself = { 0, kCurrentProcess };
  155.  
  156. (void) WakeUpProcess(&myself);
  157. }
  158.  
  159. #if    !GENERATINGCFM
  160. (void) SetA5(oldA5);
  161. #endif
  162. }
  163.  
  164.  
  165. void Fab_DestroySystemTask(void *theTaskPtr)
  166. {
  167. if (theTaskPtr)
  168.     ffree(theTaskPtr);
  169. }
  170.  
  171.  
  172. void *Fab_CreateSystemTask(void (*theProc)(void *), void *param, Boolean autoDestroy)
  173. {
  174. SysTaskInfoPtr    theTaskPtr;
  175.  
  176. theTaskPtr = fmalloc(sizeof(SysTaskInfo));
  177. if (theTaskPtr) {
  178.     theTaskPtr->qType = fabSysQueueType;
  179.     theTaskPtr->autoDestroy = autoDestroy;
  180.     theTaskPtr->parameter = param;
  181.     theTaskPtr->tmProc = theProc;
  182.  
  183. #if    !GENERATINGCFM
  184.     theTaskPtr->savedA5 = (long)LMGetCurrentA5();
  185. #endif
  186.     }
  187. return theTaskPtr;
  188. }
  189.  
  190. void CheckCallQueue(void)
  191. {
  192. SysTaskInfoPtr    sHead;
  193. NewTimerTaskInfoPtr    tHead, tNext;
  194. UInt32    ticks;
  195.  
  196. while (sHead = (SysTaskInfoPtr)sSysQueueHdr.qHead)
  197.     ExecuteSystemTask(sHead);
  198.  
  199. ticks = TickCount();
  200. tHead = (NewTimerTaskInfoPtr)sTimerQueueHdr.qHead;
  201. if (tHead) {
  202.     do {
  203.         tNext = (NewTimerTaskInfoPtr)tHead->qLink;
  204.         ExecuteTimerTask(tHead, ticks);
  205.         tHead = tNext;
  206.         }
  207.     while (tNext);
  208.     }
  209. }
  210.  
  211.  
  212. void *Fab_CreateTimerTask(void (*theProc)(void *), void *param, Boolean autoDestroy)
  213. {
  214. NewTimerTaskInfoPtr    theTaskPtr;
  215.  
  216. theTaskPtr = fmalloc(sizeof(NewTimerTaskInfo));
  217. if (theTaskPtr) {
  218.     theTaskPtr->qType = fabTimerQueueType;
  219.     theTaskPtr->autoDestroy = autoDestroy;
  220.     theTaskPtr->parameter = param;
  221.     theTaskPtr->tmProc = theProc;
  222.  
  223. /*
  224. #if    !GENERATINGCFM
  225.     theTaskPtr->savedA5 = (long)LMGetCurrentA5();
  226. #endif
  227. */    
  228.     Enqueue((QElemPtr)theTaskPtr, &sTimerQueueHdr);
  229.     }
  230. return theTaskPtr;
  231. }
  232.  
  233. void Fab_DestroyTimerTask(void *theTaskPtr)
  234. {
  235. if (theTaskPtr) {
  236.     (void) Dequeue((QElemPtr)theTaskPtr, &sTimerQueueHdr);
  237.     ffree(theTaskPtr);
  238.     }
  239. }
  240.  
  241. // Note that we use LMGetTicks() instead of TickCount() because calling the latter
  242. // at interrupt time may lead to exciting debugging sessions.
  243. // I vaguely remember that the Ticks low mem global doesn't work under A/UX 2.
  244. // Let's hope it works under A/UX 3.
  245.  
  246. #if    !GENERATING68K
  247.  
  248. // we use 16 instead of 17 for speed (vs. accuracy)
  249. #define    msecs2ticks(m)    ((m) / 16)
  250.  
  251. void Fab_ScheduleTimerTask(void *theTaskPtr, UInt32 millisecs)
  252. {
  253. ProcessSerialNumber myself = { 0, kCurrentProcess };
  254. NewTimerTaskInfoPtr    tptr = theTaskPtr;
  255. UInt32    ticksToGo;
  256.  
  257. if (tptr && tptr->qType > 0) {    // not already scheduled
  258.     tptr->qType |= ~(~0U >> 1);    // portable form; turns on sign bit
  259.     ticksToGo = msecs2ticks(millisecs);
  260.     tptr->timeWakeUp = LMGetTicks() + ticksToGo;
  261.     if (ticksToGo == 0)
  262.         (void) WakeUpProcess(&myself);
  263.     }
  264. }
  265.  
  266. void Fab_RescheduleTimerTask(void *theTaskPtr, UInt32 millisecs)
  267. {
  268. ProcessSerialNumber myself = { 0, kCurrentProcess };
  269. NewTimerTaskInfoPtr    tptr = theTaskPtr;
  270. UInt32    ticksToGo;
  271.  
  272. if (tptr) {    // we don't care if it's already scheduled
  273.     tptr->qType |= ~(~0U >> 1);    // portable form; turns on sign bit
  274.     ticksToGo = msecs2ticks(millisecs);
  275.     tptr->timeWakeUp = LMGetTicks() + ticksToGo;
  276.     if (ticksToGo == 0)
  277.         (void) WakeUpProcess(&myself);
  278.     }
  279. }
  280.  
  281. void Fab_CancelTimerTask(void *theTaskPtr)
  282. {
  283. if (theTaskPtr) {
  284.     ((NewTimerTaskInfoPtr)theTaskPtr)->qType &= (~0U >> 1);    // portable form; turns off sign bit
  285.     }
  286. }
  287.  
  288. #else
  289.  
  290. asm void Fab_ScheduleTimerTask(void *tPtr:__A0, UInt32 millisecs:__D0)
  291. {
  292.     move.l    a0,d1    // test for null pointer
  293.     beq.s    outofhere
  294.     bset    #7,struct (NewTimerTaskInfo.qType)(A0)    // atomic test and set -- cool isn't it?
  295.     bne.s    outofhere    // it was already scheduled
  296.     LSR.L    #4,D0    // msecs2ticks
  297.     MOVE.L    D0,D1
  298.     ADD.L    0x016A,D0    // LMGetTicks()
  299.     MOVE.L    D0,struct (NewTimerTaskInfo.timeWakeUp)(A0)
  300.     TST.L    D1
  301.     BNE.S    outofhere
  302.     PEA        kCurrentProcess
  303.     CLR.L    -(SP)
  304. //    MOVEA.L    SP,A0
  305.     SUBQ.L    #2,SP
  306.     PEA        2(SP)    // current process
  307. //    _WakeUpProcess
  308.     MOVE.W    #0x3C,-(SP)
  309.     _OSDispatch
  310.     LEA        10(SP),SP
  311. outofhere:
  312.     rts
  313. }
  314.  
  315. asm void Fab_RescheduleTimerTask(void *tPtr:__A0, UInt32 millisecs:__D0)
  316. {
  317.     move.l    a0,d1    // test for null pointer
  318.     beq.s    outofhere
  319.     bset    #7,struct (NewTimerTaskInfo.qType)(A0)    // atomic test and set -- cool isn't it?
  320.     LSR.L    #4,D0    // msecs2ticks
  321.     MOVE.L    D0,D1
  322.     ADD.L    0x016A,D0    // LMGetTicks()
  323.     MOVE.L    D0,struct (NewTimerTaskInfo.timeWakeUp)(A0)
  324.     TST.L    D1
  325.     BNE.S    outofhere
  326.     PEA        kCurrentProcess
  327.     CLR.L    -(SP)
  328. //    MOVEA.L    SP,A0
  329.     SUBQ.L    #2,SP
  330.     PEA        2(SP)    // current process
  331. //    _WakeUpProcess
  332.     MOVE.W    #0x3C,-(SP)
  333.     _OSDispatch
  334.     LEA        10(SP),SP
  335. outofhere:
  336.     rts
  337. }
  338.  
  339. asm void Fab_CancelTimerTask(void *tPtr:__A0)
  340. {
  341.     move.l    a0,d0    // test for null pointer
  342.     beq.s    outofhere
  343.     bclr    #7,struct (NewTimerTaskInfo.qType)(A0)
  344. outofhere:
  345.     rts
  346. }
  347.  
  348. #endif
  349.  
  350.  
  351.  
  352. static unsigned int    gFabTimerTasks = 0;
  353.  
  354. void *FabOld_CreateTimerTask(void (*theProc)(void *), void *param)
  355. {
  356. TimerTaskInfoPtr    theTaskPtr;
  357.  
  358. theTaskPtr = gFabTimerTasks > 50 ? nil: ffcalloc(sizeof(TimerTaskInfo));
  359. if (theTaskPtr) {
  360.     ++gFabTimerTasks;
  361.     ((TMTaskPtr)theTaskPtr)->tmAddr =
  362. #if    GENERATINGCFM
  363.         gTriggerUPP
  364. #else
  365.         (TimerUPP)TimerTrigger68K
  366. #endif
  367.         ;
  368.     theTaskPtr->parameter = param;
  369.     theTaskPtr->tmProc = theProc;
  370.     
  371. #if    !GENERATINGCFM
  372.     theTaskPtr->savedA5 = (long)LMGetCurrentA5();
  373. #endif
  374.     InsXTime((QElemPtr)theTaskPtr);
  375.     }
  376.  
  377. return theTaskPtr;
  378. }
  379.  
  380. #if    GENERATINGCFM
  381.  
  382. void TimerTrigger(TMTaskPtr tPtr)
  383. {
  384. TimerTaskInfoPtr    theTaskPtr = (TimerTaskInfoPtr)tPtr;
  385. void (*proc)(void *);
  386. void    *param;
  387.  
  388. param = theTaskPtr->parameter;
  389. proc = theTaskPtr->tmProc;
  390. proc(param);
  391. }
  392.  
  393. #else
  394.  
  395. asm void TimerTrigger68K(TMTaskPtr tPtr:__A1)
  396. {
  397. // we save A5 to A3
  398. // this is fine because we can trash A0-A3 and D0-D3
  399. // we JSR (A0) to a client that is written in C or Pascal
  400. // and thus our A3 will be preserved
  401.     movea.l    a5,a3    // save current A5
  402.     
  403.     movea.l    struct (TimerTaskInfo.savedA5)(A1),a5    // set "right" A5
  404.     move.l    struct (TimerTaskInfo.parameter)(A1),-(sp)    // push parameter
  405.     movea.l    struct (TimerTaskInfo.tmProc)(A1),a0
  406.     jsr        (a0)
  407.     addq.l    #4,sp    // remove parameter, C calling conventions
  408.     
  409.     movea.l    a3,a5    // restore A5
  410.     rts
  411. }
  412.  
  413. #endif
  414.  
  415. void FabOld_DestroyTimerTask(void *theTaskPtr)
  416. {
  417. if (theTaskPtr) {
  418.     --gFabTimerTasks;
  419.     RmvTime((QElemPtr)theTaskPtr);
  420.     ffree(theTaskPtr);
  421.     }
  422. }
  423.  
  424. void FabOld_ScheduleTimerTask(void *theTaskPtr, long millisecs)
  425. {
  426. if (theTaskPtr && ((TMTaskPtr)theTaskPtr)->qType > 0)    // not already scheduled
  427.     PrimeTime((QElemPtr)theTaskPtr, millisecs);
  428. }
  429.  
  430. void FabOld_CancelTimerTask(void *theTaskPtr)
  431. {
  432. if (theTaskPtr) {
  433.     RmvTime((QElemPtr)theTaskPtr);
  434.     InsXTime((QElemPtr)theTaskPtr);
  435.     }
  436. }
  437.  
  438.