summaryrefslogtreecommitdiffstats
path: root/mac/tclMacInterupt.c
diff options
context:
space:
mode:
Diffstat (limited to 'mac/tclMacInterupt.c')
-rw-r--r--mac/tclMacInterupt.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/mac/tclMacInterupt.c b/mac/tclMacInterupt.c
new file mode 100644
index 0000000..97620f8
--- /dev/null
+++ b/mac/tclMacInterupt.c
@@ -0,0 +1,289 @@
+/*
+ * 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.16 96/12/12 19:22:01
+ */
+
+#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(
+ long ms) /* Milliseconds. */
+{
+ 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(
+ void * timerToken) /* Token got from start timer. */
+{
+ 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(
+ void * timerToken) /* Our token again. */
+{
+ 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;
+ }
+ }
+}