archie/tcl7.6/mac/tclMacInterupt.c
2024-05-27 16:40:40 +02:00

290 lines
6.8 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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;
}
}
}