290 lines
6.8 KiB
C
290 lines
6.8 KiB
C
|
/*
|
|||
|
* tclMacInterupt.c --
|
|||
|
*
|
|||
|
* This file contains routines that deal with the Macintosh's low level
|
|||
|
* time manager. This code provides a better resolution timer than what
|
|||
|
* can be provided by WaitNextEvent.
|
|||
|
*
|
|||
|
* Copyright (c) 1996 Sun Microsystems, Inc.
|
|||
|
*
|
|||
|
* See the file "license.terms" for information on usage and redistribution
|
|||
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|||
|
*
|
|||
|
* SCCS: @(#) tclMacInterupt.c 1.15 96/06/24 17:22:35
|
|||
|
*/
|
|||
|
|
|||
|
#include "tclInt.h"
|
|||
|
#include "tclMacInt.h"
|
|||
|
#include <LowMem.h>
|
|||
|
#include <Processes.h>
|
|||
|
#include <Timer.h>
|
|||
|
|
|||
|
/*
|
|||
|
* Data structure for timer tasks.
|
|||
|
*/
|
|||
|
typedef struct TMInfo {
|
|||
|
TMTask tmTask;
|
|||
|
ProcessSerialNumber psn;
|
|||
|
Point lastPoint;
|
|||
|
Point newPoint;
|
|||
|
long currentA5;
|
|||
|
long ourA5;
|
|||
|
int installed;
|
|||
|
} TMInfo;
|
|||
|
|
|||
|
/*
|
|||
|
* Globals used within this file.
|
|||
|
*/
|
|||
|
|
|||
|
static TimerUPP sleepTimerProc = NULL;
|
|||
|
static int interuptsInited = false;
|
|||
|
static ProcessSerialNumber applicationPSN;
|
|||
|
#define MAX_TIMER_ARRAY_SIZE 16
|
|||
|
static TMInfo timerInfoArray[MAX_TIMER_ARRAY_SIZE];
|
|||
|
static int topTimerElement = 0;
|
|||
|
|
|||
|
/*
|
|||
|
* Prototypes for procedures that are referenced only in this file:
|
|||
|
*/
|
|||
|
|
|||
|
#if !GENERATINGCFM
|
|||
|
static TMInfo * GetTMInfo(void) ONEWORDINLINE(0x2E89); /* MOVE.L A1,(SP) */
|
|||
|
#endif
|
|||
|
static void SleepTimerProc _ANSI_ARGS_((void));
|
|||
|
static pascal void CleanUpExitProc _ANSI_ARGS_((void));
|
|||
|
static void InitInteruptSystem _ANSI_ARGS_((void));
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* InitInteruptSystem --
|
|||
|
*
|
|||
|
* Does various initialization for the functions used in this
|
|||
|
* file. Sets up Universial Pricedure Pointers, installs a trap
|
|||
|
* patch for ExitToShell, etc.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Various initialization.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
InitInteruptSystem()
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
sleepTimerProc = NewTimerProc(SleepTimerProc);
|
|||
|
GetCurrentProcess(&applicationPSN);
|
|||
|
for (i = 0; i < MAX_TIMER_ARRAY_SIZE; i++) {
|
|||
|
timerInfoArray[i].installed = false;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Install the ExitToShell patch. We use this patch instead
|
|||
|
* of the Tcl exit mechanism because we need to ensure that
|
|||
|
* these routines are cleaned up even if we crash or are forced
|
|||
|
* to quit. There are some circumstances when the Tcl exit
|
|||
|
* handlers may not fire.
|
|||
|
*/
|
|||
|
|
|||
|
TclMacInstallExitToShellPatch(CleanUpExitProc);
|
|||
|
interuptsInited = true;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclMacStartTimer --
|
|||
|
*
|
|||
|
* Install a Time Manager task to wake our process up in the
|
|||
|
* future. The process should get a NULL event after ms
|
|||
|
* milliseconds.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Schedules our process to wake up.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
void *
|
|||
|
TclMacStartTimer(ms)
|
|||
|
long ms;
|
|||
|
{
|
|||
|
TMInfo *timerInfoPtr;
|
|||
|
|
|||
|
if (!interuptsInited) {
|
|||
|
InitInteruptSystem();
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Obtain a pointer for the timer. We only allocate up
|
|||
|
* to MAX_TIMER_ARRAY_SIZE timers. If we are past that
|
|||
|
* max we return NULL.
|
|||
|
*/
|
|||
|
if (topTimerElement < MAX_TIMER_ARRAY_SIZE) {
|
|||
|
timerInfoPtr = &timerInfoArray[topTimerElement];
|
|||
|
topTimerElement++;
|
|||
|
} else {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Install timer to wake process in ms milliseconds.
|
|||
|
*/
|
|||
|
timerInfoPtr->tmTask.tmAddr = sleepTimerProc;
|
|||
|
timerInfoPtr->tmTask.tmWakeUp = 0;
|
|||
|
timerInfoPtr->tmTask.tmReserved = 0;
|
|||
|
timerInfoPtr->psn = applicationPSN;
|
|||
|
timerInfoPtr->installed = true;
|
|||
|
|
|||
|
InsTime((QElemPtr) timerInfoPtr);
|
|||
|
PrimeTime((QElemPtr) timerInfoPtr, (long) ms);
|
|||
|
|
|||
|
return (void *) timerInfoPtr;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclMacRemoveTimer --
|
|||
|
*
|
|||
|
* Remove the timer event from the Time Manager.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* A scheduled timer would be removed.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
TclMacRemoveTimer(timerToken)
|
|||
|
void * timerToken;
|
|||
|
{
|
|||
|
TMInfo *timerInfoPtr = (TMInfo *) timerToken;
|
|||
|
|
|||
|
if (timerInfoPtr == NULL) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
RmvTime((QElemPtr) timerInfoPtr);
|
|||
|
timerInfoPtr->installed = false;
|
|||
|
topTimerElement--;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclMacTimerExpired --
|
|||
|
*
|
|||
|
* Check to see if the installed timer has expired.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* True if timer has expired, false otherwise.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
int
|
|||
|
TclMacTimerExpired(timerToken)
|
|||
|
void * timerToken;
|
|||
|
{
|
|||
|
TMInfo *timerInfoPtr = (TMInfo *) timerToken;
|
|||
|
|
|||
|
if ((timerInfoPtr == NULL) ||
|
|||
|
!(timerInfoPtr->tmTask.qType & kTMTaskActive)) {
|
|||
|
return true;
|
|||
|
} else {
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* SleepTimerProc --
|
|||
|
*
|
|||
|
* Time proc is called by the is a callback routine placed in the
|
|||
|
* system by Tcl_Sleep. The routine is called at interupt time
|
|||
|
* and threrfor can not move or allocate memory. This call will
|
|||
|
* schedule our process to wake up the next time the process gets
|
|||
|
* around to consider running it.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Schedules our process to wake up.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
SleepTimerProc()
|
|||
|
{
|
|||
|
/*
|
|||
|
* In CFM code we can access our code directly. In 68k code that
|
|||
|
* isn't based on CFM we must do a glorious hack. The function
|
|||
|
* GetTMInfo is an inline assembler call that moves the pointer
|
|||
|
* at A1 to the top of the stack. The Time Manager keeps the TMTask
|
|||
|
* info record there before calling this call back. In order for
|
|||
|
* this to work the infoPtr argument must be the *last* item on the
|
|||
|
* stack. If we "piggyback" our data to the TMTask info record we
|
|||
|
* can get access to the information we need. While this is really
|
|||
|
* ugly - it's the way Apple recomends it be done - go figure...
|
|||
|
*/
|
|||
|
|
|||
|
#if GENERATINGCFM
|
|||
|
WakeUpProcess(&applicationPSN);
|
|||
|
#else
|
|||
|
TMInfo * infoPtr;
|
|||
|
|
|||
|
infoPtr = GetTMInfo();
|
|||
|
WakeUpProcess(&infoPtr->psn);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* CleanUpExitProc --
|
|||
|
*
|
|||
|
* This procedure is invoked as an exit handler when ExitToShell
|
|||
|
* is called. It removes the system level timer handler if it
|
|||
|
* is installed. This must be called or the Mac OS will more than
|
|||
|
* likely crash.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
static pascal void
|
|||
|
CleanUpExitProc()
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
for (i = 0; i < MAX_TIMER_ARRAY_SIZE; i++) {
|
|||
|
if (timerInfoArray[i].installed) {
|
|||
|
RmvTime((QElemPtr) &timerInfoArray[i]);
|
|||
|
timerInfoArray[i].installed = false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|