author | sl@SLION-WIN7.fritz.box |
Fri, 15 Jun 2012 03:10:57 +0200 | |
changeset 0 | bde4ae8d615e |
permissions | -rw-r--r-- |
sl@0 | 1 |
/* |
sl@0 | 2 |
* tclMacInterupt.c -- |
sl@0 | 3 |
* |
sl@0 | 4 |
* This file contains routines that deal with the Macintosh's low level |
sl@0 | 5 |
* time manager. This code provides a better resolution timer than what |
sl@0 | 6 |
* can be provided by WaitNextEvent. |
sl@0 | 7 |
* |
sl@0 | 8 |
* Copyright (c) 1996 Sun Microsystems, Inc. |
sl@0 | 9 |
* |
sl@0 | 10 |
* See the file "license.terms" for information on usage and redistribution |
sl@0 | 11 |
* of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
sl@0 | 12 |
* |
sl@0 | 13 |
* RCS: @(#) $Id: tclMacInterupt.c,v 1.2 1998/09/14 18:40:05 stanton Exp $ |
sl@0 | 14 |
*/ |
sl@0 | 15 |
|
sl@0 | 16 |
#include "tclInt.h" |
sl@0 | 17 |
#include "tclMacInt.h" |
sl@0 | 18 |
#include <LowMem.h> |
sl@0 | 19 |
#include <Processes.h> |
sl@0 | 20 |
#include <Timer.h> |
sl@0 | 21 |
|
sl@0 | 22 |
/* |
sl@0 | 23 |
* Data structure for timer tasks. |
sl@0 | 24 |
*/ |
sl@0 | 25 |
typedef struct TMInfo { |
sl@0 | 26 |
TMTask tmTask; |
sl@0 | 27 |
ProcessSerialNumber psn; |
sl@0 | 28 |
Point lastPoint; |
sl@0 | 29 |
Point newPoint; |
sl@0 | 30 |
long currentA5; |
sl@0 | 31 |
long ourA5; |
sl@0 | 32 |
int installed; |
sl@0 | 33 |
} TMInfo; |
sl@0 | 34 |
|
sl@0 | 35 |
/* |
sl@0 | 36 |
* Globals used within this file. |
sl@0 | 37 |
*/ |
sl@0 | 38 |
|
sl@0 | 39 |
static TimerUPP sleepTimerProc = NULL; |
sl@0 | 40 |
static int interuptsInited = false; |
sl@0 | 41 |
static ProcessSerialNumber applicationPSN; |
sl@0 | 42 |
#define MAX_TIMER_ARRAY_SIZE 16 |
sl@0 | 43 |
static TMInfo timerInfoArray[MAX_TIMER_ARRAY_SIZE]; |
sl@0 | 44 |
static int topTimerElement = 0; |
sl@0 | 45 |
|
sl@0 | 46 |
/* |
sl@0 | 47 |
* Prototypes for procedures that are referenced only in this file: |
sl@0 | 48 |
*/ |
sl@0 | 49 |
|
sl@0 | 50 |
#if !GENERATINGCFM |
sl@0 | 51 |
static TMInfo * GetTMInfo(void) ONEWORDINLINE(0x2E89); /* MOVE.L A1,(SP) */ |
sl@0 | 52 |
#endif |
sl@0 | 53 |
static void SleepTimerProc _ANSI_ARGS_((void)); |
sl@0 | 54 |
static pascal void CleanUpExitProc _ANSI_ARGS_((void)); |
sl@0 | 55 |
static void InitInteruptSystem _ANSI_ARGS_((void)); |
sl@0 | 56 |
|
sl@0 | 57 |
/* |
sl@0 | 58 |
*---------------------------------------------------------------------- |
sl@0 | 59 |
* |
sl@0 | 60 |
* InitInteruptSystem -- |
sl@0 | 61 |
* |
sl@0 | 62 |
* Does various initialization for the functions used in this |
sl@0 | 63 |
* file. Sets up Universial Pricedure Pointers, installs a trap |
sl@0 | 64 |
* patch for ExitToShell, etc. |
sl@0 | 65 |
* |
sl@0 | 66 |
* Results: |
sl@0 | 67 |
* None. |
sl@0 | 68 |
* |
sl@0 | 69 |
* Side effects: |
sl@0 | 70 |
* Various initialization. |
sl@0 | 71 |
* |
sl@0 | 72 |
*---------------------------------------------------------------------- |
sl@0 | 73 |
*/ |
sl@0 | 74 |
|
sl@0 | 75 |
void |
sl@0 | 76 |
InitInteruptSystem() |
sl@0 | 77 |
{ |
sl@0 | 78 |
int i; |
sl@0 | 79 |
|
sl@0 | 80 |
sleepTimerProc = NewTimerProc(SleepTimerProc); |
sl@0 | 81 |
GetCurrentProcess(&applicationPSN); |
sl@0 | 82 |
for (i = 0; i < MAX_TIMER_ARRAY_SIZE; i++) { |
sl@0 | 83 |
timerInfoArray[i].installed = false; |
sl@0 | 84 |
} |
sl@0 | 85 |
|
sl@0 | 86 |
/* |
sl@0 | 87 |
* Install the ExitToShell patch. We use this patch instead |
sl@0 | 88 |
* of the Tcl exit mechanism because we need to ensure that |
sl@0 | 89 |
* these routines are cleaned up even if we crash or are forced |
sl@0 | 90 |
* to quit. There are some circumstances when the Tcl exit |
sl@0 | 91 |
* handlers may not fire. |
sl@0 | 92 |
*/ |
sl@0 | 93 |
|
sl@0 | 94 |
TclMacInstallExitToShellPatch(CleanUpExitProc); |
sl@0 | 95 |
interuptsInited = true; |
sl@0 | 96 |
} |
sl@0 | 97 |
|
sl@0 | 98 |
/* |
sl@0 | 99 |
*---------------------------------------------------------------------- |
sl@0 | 100 |
* |
sl@0 | 101 |
* TclMacStartTimer -- |
sl@0 | 102 |
* |
sl@0 | 103 |
* Install a Time Manager task to wake our process up in the |
sl@0 | 104 |
* future. The process should get a NULL event after ms |
sl@0 | 105 |
* milliseconds. |
sl@0 | 106 |
* |
sl@0 | 107 |
* Results: |
sl@0 | 108 |
* None. |
sl@0 | 109 |
* |
sl@0 | 110 |
* Side effects: |
sl@0 | 111 |
* Schedules our process to wake up. |
sl@0 | 112 |
* |
sl@0 | 113 |
*---------------------------------------------------------------------- |
sl@0 | 114 |
*/ |
sl@0 | 115 |
|
sl@0 | 116 |
void * |
sl@0 | 117 |
TclMacStartTimer( |
sl@0 | 118 |
long ms) /* Milliseconds. */ |
sl@0 | 119 |
{ |
sl@0 | 120 |
TMInfo *timerInfoPtr; |
sl@0 | 121 |
|
sl@0 | 122 |
if (!interuptsInited) { |
sl@0 | 123 |
InitInteruptSystem(); |
sl@0 | 124 |
} |
sl@0 | 125 |
|
sl@0 | 126 |
/* |
sl@0 | 127 |
* Obtain a pointer for the timer. We only allocate up |
sl@0 | 128 |
* to MAX_TIMER_ARRAY_SIZE timers. If we are past that |
sl@0 | 129 |
* max we return NULL. |
sl@0 | 130 |
*/ |
sl@0 | 131 |
if (topTimerElement < MAX_TIMER_ARRAY_SIZE) { |
sl@0 | 132 |
timerInfoPtr = &timerInfoArray[topTimerElement]; |
sl@0 | 133 |
topTimerElement++; |
sl@0 | 134 |
} else { |
sl@0 | 135 |
return NULL; |
sl@0 | 136 |
} |
sl@0 | 137 |
|
sl@0 | 138 |
/* |
sl@0 | 139 |
* Install timer to wake process in ms milliseconds. |
sl@0 | 140 |
*/ |
sl@0 | 141 |
timerInfoPtr->tmTask.tmAddr = sleepTimerProc; |
sl@0 | 142 |
timerInfoPtr->tmTask.tmWakeUp = 0; |
sl@0 | 143 |
timerInfoPtr->tmTask.tmReserved = 0; |
sl@0 | 144 |
timerInfoPtr->psn = applicationPSN; |
sl@0 | 145 |
timerInfoPtr->installed = true; |
sl@0 | 146 |
|
sl@0 | 147 |
InsTime((QElemPtr) timerInfoPtr); |
sl@0 | 148 |
PrimeTime((QElemPtr) timerInfoPtr, (long) ms); |
sl@0 | 149 |
|
sl@0 | 150 |
return (void *) timerInfoPtr; |
sl@0 | 151 |
} |
sl@0 | 152 |
|
sl@0 | 153 |
/* |
sl@0 | 154 |
*---------------------------------------------------------------------- |
sl@0 | 155 |
* |
sl@0 | 156 |
* TclMacRemoveTimer -- |
sl@0 | 157 |
* |
sl@0 | 158 |
* Remove the timer event from the Time Manager. |
sl@0 | 159 |
* |
sl@0 | 160 |
* Results: |
sl@0 | 161 |
* None. |
sl@0 | 162 |
* |
sl@0 | 163 |
* Side effects: |
sl@0 | 164 |
* A scheduled timer would be removed. |
sl@0 | 165 |
* |
sl@0 | 166 |
*---------------------------------------------------------------------- |
sl@0 | 167 |
*/ |
sl@0 | 168 |
|
sl@0 | 169 |
void |
sl@0 | 170 |
TclMacRemoveTimer( |
sl@0 | 171 |
void * timerToken) /* Token got from start timer. */ |
sl@0 | 172 |
{ |
sl@0 | 173 |
TMInfo *timerInfoPtr = (TMInfo *) timerToken; |
sl@0 | 174 |
|
sl@0 | 175 |
if (timerInfoPtr == NULL) { |
sl@0 | 176 |
return; |
sl@0 | 177 |
} |
sl@0 | 178 |
|
sl@0 | 179 |
RmvTime((QElemPtr) timerInfoPtr); |
sl@0 | 180 |
timerInfoPtr->installed = false; |
sl@0 | 181 |
topTimerElement--; |
sl@0 | 182 |
} |
sl@0 | 183 |
|
sl@0 | 184 |
/* |
sl@0 | 185 |
*---------------------------------------------------------------------- |
sl@0 | 186 |
* |
sl@0 | 187 |
* TclMacTimerExpired -- |
sl@0 | 188 |
* |
sl@0 | 189 |
* Check to see if the installed timer has expired. |
sl@0 | 190 |
* |
sl@0 | 191 |
* Results: |
sl@0 | 192 |
* True if timer has expired, false otherwise. |
sl@0 | 193 |
* |
sl@0 | 194 |
* Side effects: |
sl@0 | 195 |
* None. |
sl@0 | 196 |
* |
sl@0 | 197 |
*---------------------------------------------------------------------- |
sl@0 | 198 |
*/ |
sl@0 | 199 |
|
sl@0 | 200 |
int |
sl@0 | 201 |
TclMacTimerExpired( |
sl@0 | 202 |
void * timerToken) /* Our token again. */ |
sl@0 | 203 |
{ |
sl@0 | 204 |
TMInfo *timerInfoPtr = (TMInfo *) timerToken; |
sl@0 | 205 |
|
sl@0 | 206 |
if ((timerInfoPtr == NULL) || |
sl@0 | 207 |
!(timerInfoPtr->tmTask.qType & kTMTaskActive)) { |
sl@0 | 208 |
return true; |
sl@0 | 209 |
} else { |
sl@0 | 210 |
return false; |
sl@0 | 211 |
} |
sl@0 | 212 |
} |
sl@0 | 213 |
|
sl@0 | 214 |
/* |
sl@0 | 215 |
*---------------------------------------------------------------------- |
sl@0 | 216 |
* |
sl@0 | 217 |
* SleepTimerProc -- |
sl@0 | 218 |
* |
sl@0 | 219 |
* Time proc is called by the is a callback routine placed in the |
sl@0 | 220 |
* system by Tcl_Sleep. The routine is called at interupt time |
sl@0 | 221 |
* and threrfor can not move or allocate memory. This call will |
sl@0 | 222 |
* schedule our process to wake up the next time the process gets |
sl@0 | 223 |
* around to consider running it. |
sl@0 | 224 |
* |
sl@0 | 225 |
* Results: |
sl@0 | 226 |
* None. |
sl@0 | 227 |
* |
sl@0 | 228 |
* Side effects: |
sl@0 | 229 |
* Schedules our process to wake up. |
sl@0 | 230 |
* |
sl@0 | 231 |
*---------------------------------------------------------------------- |
sl@0 | 232 |
*/ |
sl@0 | 233 |
|
sl@0 | 234 |
static void |
sl@0 | 235 |
SleepTimerProc() |
sl@0 | 236 |
{ |
sl@0 | 237 |
/* |
sl@0 | 238 |
* In CFM code we can access our code directly. In 68k code that |
sl@0 | 239 |
* isn't based on CFM we must do a glorious hack. The function |
sl@0 | 240 |
* GetTMInfo is an inline assembler call that moves the pointer |
sl@0 | 241 |
* at A1 to the top of the stack. The Time Manager keeps the TMTask |
sl@0 | 242 |
* info record there before calling this call back. In order for |
sl@0 | 243 |
* this to work the infoPtr argument must be the *last* item on the |
sl@0 | 244 |
* stack. If we "piggyback" our data to the TMTask info record we |
sl@0 | 245 |
* can get access to the information we need. While this is really |
sl@0 | 246 |
* ugly - it's the way Apple recomends it be done - go figure... |
sl@0 | 247 |
*/ |
sl@0 | 248 |
|
sl@0 | 249 |
#if GENERATINGCFM |
sl@0 | 250 |
WakeUpProcess(&applicationPSN); |
sl@0 | 251 |
#else |
sl@0 | 252 |
TMInfo * infoPtr; |
sl@0 | 253 |
|
sl@0 | 254 |
infoPtr = GetTMInfo(); |
sl@0 | 255 |
WakeUpProcess(&infoPtr->psn); |
sl@0 | 256 |
#endif |
sl@0 | 257 |
} |
sl@0 | 258 |
|
sl@0 | 259 |
/* |
sl@0 | 260 |
*---------------------------------------------------------------------- |
sl@0 | 261 |
* |
sl@0 | 262 |
* CleanUpExitProc -- |
sl@0 | 263 |
* |
sl@0 | 264 |
* This procedure is invoked as an exit handler when ExitToShell |
sl@0 | 265 |
* is called. It removes the system level timer handler if it |
sl@0 | 266 |
* is installed. This must be called or the Mac OS will more than |
sl@0 | 267 |
* likely crash. |
sl@0 | 268 |
* |
sl@0 | 269 |
* Results: |
sl@0 | 270 |
* None. |
sl@0 | 271 |
* |
sl@0 | 272 |
* Side effects: |
sl@0 | 273 |
* None. |
sl@0 | 274 |
* |
sl@0 | 275 |
*---------------------------------------------------------------------- |
sl@0 | 276 |
*/ |
sl@0 | 277 |
|
sl@0 | 278 |
static pascal void |
sl@0 | 279 |
CleanUpExitProc() |
sl@0 | 280 |
{ |
sl@0 | 281 |
int i; |
sl@0 | 282 |
|
sl@0 | 283 |
for (i = 0; i < MAX_TIMER_ARRAY_SIZE; i++) { |
sl@0 | 284 |
if (timerInfoArray[i].installed) { |
sl@0 | 285 |
RmvTime((QElemPtr) &timerInfoArray[i]); |
sl@0 | 286 |
timerInfoArray[i].installed = false; |
sl@0 | 287 |
} |
sl@0 | 288 |
} |
sl@0 | 289 |
} |