home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / tcl / tclsrc / c / tclAsync < prev    next >
Text File  |  1994-12-18  |  6KB  |  243 lines

  1. /* 
  2.  * tclAsync.c --
  3.  *
  4.  *    This file provides low-level support needed to invoke signal
  5.  *    handlers in a safe way.  The code here doesn't actually handle
  6.  *    signals, though.  This code is based on proposals made by
  7.  *    Mark Diekhans and Don Libes.
  8.  *
  9.  * Copyright (c) 1993 The Regents of the University of California.
  10.  * Copyright (c) 1994 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  */
  15.  
  16. #ifndef lint
  17. static char sccsid[] = "@(#) tclAsync.c 1.4 94/12/17 16:14:04";
  18. #endif /* not lint */
  19.  
  20. #include "tclInt.h"
  21.  
  22. /*
  23.  * One of the following structures exists for each asynchronous
  24.  * handler:
  25.  */
  26.  
  27. typedef struct AsyncHandler {
  28.     int ready;                /* Non-zero means this handler should
  29.                      * be invoked in the next call to
  30.                      * Tcl_AsyncInvoke. */
  31.     struct AsyncHandler *nextPtr;    /* Next in list of all handlers for
  32.                      * the process. */
  33.     Tcl_AsyncProc *proc;        /* Procedure to call when handler
  34.                      * is invoked. */
  35.     ClientData clientData;        /* Value to pass to handler when it
  36.                      * is invoked. */
  37. } AsyncHandler;
  38.  
  39. /*
  40.  * The variables below maintain a list of all existing handlers.
  41.  */
  42.  
  43. static AsyncHandler *firstHandler;    /* First handler defined for process,
  44.                      * or NULL if none. */
  45. static AsyncHandler *lastHandler;    /* Last handler or NULL. */
  46.  
  47. /*
  48.  * The variable below is set to 1 whenever a handler becomes ready and
  49.  * it is cleared to zero whenever Tcl_AsyncInvoke is called.  It can be
  50.  * checked elsewhere in the application to see if Tcl_AsyncInvoke
  51.  * should be invoked.
  52.  */
  53.  
  54. int tcl_AsyncReady = 0;
  55.  
  56. /*
  57.  * The variable below indicates whether Tcl_AsyncInvoke is currently
  58.  * working.  If so then we won't set tcl_AsyncReady again until
  59.  * Tcl_AsyncInvoke returns.
  60.  */
  61.  
  62. static int asyncActive = 0;
  63.  
  64. /*
  65.  *----------------------------------------------------------------------
  66.  *
  67.  * Tcl_AsyncCreate --
  68.  *
  69.  *    This procedure creates the data structures for an asynchronous
  70.  *    handler, so that no memory has to be allocated when the handler
  71.  *    is activated.
  72.  *
  73.  * Results:
  74.  *    The return value is a token for the handler, which can be used
  75.  *    to activate it later on.
  76.  *
  77.  * Side effects:
  78.  *    Information about the handler is recorded.
  79.  *
  80.  *----------------------------------------------------------------------
  81.  */
  82.  
  83. Tcl_AsyncHandler
  84. Tcl_AsyncCreate(proc, clientData)
  85.     Tcl_AsyncProc *proc;        /* Procedure to call when handler
  86.                      * is invoked. */
  87.     ClientData clientData;        /* Argument to pass to handler. */
  88. {
  89.     AsyncHandler *asyncPtr;
  90.  
  91.     asyncPtr = (AsyncHandler *) ckalloc(sizeof(AsyncHandler));
  92.     asyncPtr->ready = 0;
  93.     asyncPtr->nextPtr = NULL;
  94.     asyncPtr->proc = proc;
  95.     asyncPtr->clientData = clientData;
  96.     if (firstHandler == NULL) {
  97.     firstHandler = asyncPtr;
  98.     } else {
  99.     lastHandler->nextPtr = asyncPtr;
  100.     }
  101.     lastHandler = asyncPtr;
  102.     return (Tcl_AsyncHandler) asyncPtr;
  103. }
  104.  
  105. /*
  106.  *----------------------------------------------------------------------
  107.  *
  108.  * Tcl_AsyncMark --
  109.  *
  110.  *    This procedure is called to request that an asynchronous handler
  111.  *    be invoked as soon as possible.  It's typically called from
  112.  *    an interrupt handler, where it isn't safe to do anything that
  113.  *    depends on or modifies application state.
  114.  *
  115.  * Results:
  116.  *    None.
  117.  *
  118.  * Side effects:
  119.  *    The handler gets marked for invocation later.
  120.  *
  121.  *----------------------------------------------------------------------
  122.  */
  123.  
  124. void
  125. Tcl_AsyncMark(async)
  126.     Tcl_AsyncHandler async;        /* Token for handler. */
  127. {
  128.     ((AsyncHandler *) async)->ready = 1;
  129.     if (!asyncActive) {
  130.     tcl_AsyncReady = 1;
  131.     }
  132. }
  133.  
  134. /*
  135.  *----------------------------------------------------------------------
  136.  *
  137.  * Tcl_AsyncInvoke --
  138.  *
  139.  *    This procedure is called at a "safe" time at background level
  140.  *    to invoke any active asynchronous handlers.
  141.  *
  142.  * Results:
  143.  *    The return value is a normal Tcl result, which is intended to
  144.  *    replace the code argument as the current completion code for
  145.  *    interp.
  146.  *
  147.  * Side effects:
  148.  *    Depends on the handlers that are active.
  149.  *
  150.  *----------------------------------------------------------------------
  151.  */
  152.  
  153. int
  154. Tcl_AsyncInvoke(interp, code)
  155.     Tcl_Interp *interp;            /* If invoked from Tcl_Eval just after
  156.                      * completing a command, points to
  157.                      * interpreter.  Otherwise it is
  158.                      * NULL. */
  159.     int code;                 /* If interp is non-NULL, this gives
  160.                      * completion code from command that
  161.                      * just completed. */
  162. {
  163.     AsyncHandler *asyncPtr;
  164.  
  165.     if (tcl_AsyncReady == 0) {
  166.     return code;
  167.     }
  168.     tcl_AsyncReady = 0;
  169.     asyncActive = 1;
  170.     if (interp == NULL) {
  171.     code = 0;
  172.     }
  173.  
  174.     /*
  175.      * Make one or more passes over the list of handlers, invoking
  176.      * at most one handler in each pass.  After invoking a handler,
  177.      * go back to the start of the list again so that (a) if a new
  178.      * higher-priority handler gets marked while executing a lower
  179.      * priority handler, we execute the higher-priority handler
  180.      * next, and (b) if a handler gets deleted during the execution
  181.      * of a handler, then the list structure may change so it isn't
  182.      * safe to continue down the list anyway.
  183.      */
  184.  
  185.     while (1) {
  186.     for (asyncPtr = firstHandler; asyncPtr != NULL;
  187.         asyncPtr = asyncPtr->nextPtr) {
  188.         if (asyncPtr->ready) {
  189.         break;
  190.         }
  191.     }
  192.     if (asyncPtr == NULL) {
  193.         break;
  194.     }
  195.     asyncPtr->ready = 0;
  196.     code = (*asyncPtr->proc)(asyncPtr->clientData, interp, code);
  197.     }
  198.     asyncActive = 0;
  199.     return code;
  200. }
  201.  
  202. /*
  203.  *----------------------------------------------------------------------
  204.  *
  205.  * Tcl_AsyncDelete --
  206.  *
  207.  *    Frees up all the state for an asynchronous handler.  The handler
  208.  *    should never be used again.
  209.  *
  210.  * Results:
  211.  *    None.
  212.  *
  213.  * Side effects:
  214.  *    The state associated with the handler is deleted.
  215.  *
  216.  *----------------------------------------------------------------------
  217.  */
  218.  
  219. void
  220. Tcl_AsyncDelete(async)
  221.     Tcl_AsyncHandler async;        /* Token for handler to delete. */
  222. {
  223.     AsyncHandler *asyncPtr = (AsyncHandler *) async;
  224.     AsyncHandler *prevPtr;
  225.  
  226.     if (firstHandler == asyncPtr) {
  227.     firstHandler = asyncPtr->nextPtr;
  228.     if (firstHandler == NULL) {
  229.         lastHandler = NULL;
  230.     }
  231.     } else {
  232.     prevPtr = firstHandler;
  233.     while (prevPtr->nextPtr != asyncPtr) {
  234.         prevPtr = prevPtr->nextPtr;
  235.     }
  236.     prevPtr->nextPtr = asyncPtr->nextPtr;
  237.     if (lastHandler == asyncPtr) {
  238.         lastHandler = prevPtr;
  239.     }
  240.     }
  241.     ckfree((char *) asyncPtr);
  242. }
  243.