Logo Search packages:      
Sourcecode: tcl8.3 version File versions  Download package

tclMacInterupt.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.
 *
 * RCS: @(#) $Id: tclMacInterupt.c,v 1.2 1998/09/14 18:40:05 stanton Exp $
 */

#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;
      }
    }
}

Generated by  Doxygen 1.6.0   Back to index