home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tcl2-73c.zip / tcl7.3 / tclAsync.c < prev    next >
C/C++ Source or Header  |  1993-09-02  |  7KB  |  257 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.  * All rights reserved.
  11.  *
  12.  * Permission is hereby granted, without written agreement and without
  13.  * license or royalty fees, to use, copy, modify, and distribute this
  14.  * software and its documentation for any purpose, provided that the
  15.  * above copyright notice and the following two paragraphs appear in
  16.  * all copies of this software.
  17.  * 
  18.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  19.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  20.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  21.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22.  *
  23.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  24.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  25.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  26.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  27.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  28.  */
  29.  
  30. #ifndef lint
  31. static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclAsync.c,v 1.3 93/09/02 16:02:42 ouster Exp $ SPRITE (Berkeley)";
  32. #endif /* not lint */
  33.  
  34. #include "tclInt.h"
  35.  
  36. /*
  37.  * One of the following structures exists for each asynchronous
  38.  * handler:
  39.  */
  40.  
  41. typedef struct AsyncHandler {
  42.     int ready;                /* Non-zero means this handler should
  43.                      * be invoked in the next call to
  44.                      * Tcl_AsyncInvoke. */
  45.     struct AsyncHandler *nextPtr;    /* Next in list of all handlers for
  46.                      * the process. */
  47.     Tcl_AsyncProc *proc;        /* Procedure to call when handler
  48.                      * is invoked. */
  49.     ClientData clientData;        /* Value to pass to handler when it
  50.                      * is invoked. */
  51. } AsyncHandler;
  52.  
  53. /*
  54.  * The variables below maintain a list of all existing handlers.
  55.  */
  56.  
  57. static AsyncHandler *firstHandler;    /* First handler defined for process,
  58.                      * or NULL if none. */
  59. static AsyncHandler *lastHandler;    /* Last handler or NULL. */
  60.  
  61. /*
  62.  * The variable below is set to 1 whenever a handler becomes ready and
  63.  * it is cleared to zero whenever Tcl_AsyncInvoke is called.  It can be
  64.  * checked elsewhere in the application to see if Tcl_AsyncInvoke
  65.  * should be invoked.
  66.  */
  67.  
  68. int tcl_AsyncReady = 0;
  69.  
  70. /*
  71.  * The variable below indicates whether Tcl_AsyncInvoke is currently
  72.  * working.  If so then we won't set tcl_AsyncReady again until
  73.  * Tcl_AsyncInvoke returns.
  74.  */
  75.  
  76. static int asyncActive = 0;
  77.  
  78. /*
  79.  *----------------------------------------------------------------------
  80.  *
  81.  * Tcl_AsyncCreate --
  82.  *
  83.  *    This procedure creates the data structures for an asynchronous
  84.  *    handler, so that no memory has to be allocated when the handler
  85.  *    is activated.
  86.  *
  87.  * Results:
  88.  *    The return value is a token for the handler, which can be used
  89.  *    to activate it later on.
  90.  *
  91.  * Side effects:
  92.  *    Information about the handler is recorded.
  93.  *
  94.  *----------------------------------------------------------------------
  95.  */
  96.  
  97. Tcl_AsyncHandler
  98. Tcl_AsyncCreate(proc, clientData)
  99.     Tcl_AsyncProc *proc;        /* Procedure to call when handler
  100.                      * is invoked. */
  101.     ClientData clientData;        /* Argument to pass to handler. */
  102. {
  103.     AsyncHandler *asyncPtr;
  104.  
  105.     asyncPtr = (AsyncHandler *) ckalloc(sizeof(AsyncHandler));
  106.     asyncPtr->ready = 0;
  107.     asyncPtr->nextPtr = NULL;
  108.     asyncPtr->proc = proc;
  109.     asyncPtr->clientData = clientData;
  110.     if (firstHandler == NULL) {
  111.     firstHandler = asyncPtr;
  112.     } else {
  113.     lastHandler->nextPtr = asyncPtr;
  114.     }
  115.     lastHandler = asyncPtr;
  116.     return (Tcl_AsyncHandler) asyncPtr;
  117. }
  118.  
  119. /*
  120.  *----------------------------------------------------------------------
  121.  *
  122.  * Tcl_AsyncMark --
  123.  *
  124.  *    This procedure is called to request that an asynchronous handler
  125.  *    be invoked as soon as possible.  It's typically called from
  126.  *    an interrupt handler, where it isn't safe to do anything that
  127.  *    depends on or modifies application state.
  128.  *
  129.  * Results:
  130.  *    None.
  131.  *
  132.  * Side effects:
  133.  *    The handler gets marked for invocation later.
  134.  *
  135.  *----------------------------------------------------------------------
  136.  */
  137.  
  138. void
  139. Tcl_AsyncMark(async)
  140.     Tcl_AsyncHandler async;        /* Token for handler. */
  141. {
  142.     ((AsyncHandler *) async)->ready = 1;
  143.     if (!asyncActive) {
  144.     tcl_AsyncReady = 1;
  145.     }
  146. }
  147.  
  148. /*
  149.  *----------------------------------------------------------------------
  150.  *
  151.  * Tcl_AsyncInvoke --
  152.  *
  153.  *    This procedure is called at a "safe" time at background level
  154.  *    to invoke any active asynchronous handlers.
  155.  *
  156.  * Results:
  157.  *    The return value is a normal Tcl result, which is intended to
  158.  *    replace the code argument as the current completion code for
  159.  *    interp.
  160.  *
  161.  * Side effects:
  162.  *    Depends on the handlers that are active.
  163.  *
  164.  *----------------------------------------------------------------------
  165.  */
  166.  
  167. int
  168. Tcl_AsyncInvoke(interp, code)
  169.     Tcl_Interp *interp;            /* If invoked from Tcl_Eval just after
  170.                      * completing a command, points to
  171.                      * interpreter.  Otherwise it is
  172.                      * NULL. */
  173.     int code;                 /* If interp is non-NULL, this gives
  174.                      * completion code from command that
  175.                      * just completed. */
  176. {
  177.     AsyncHandler *asyncPtr;
  178.  
  179.     if (tcl_AsyncReady == 0) {
  180.     return code;
  181.     }
  182.     tcl_AsyncReady = 0;
  183.     asyncActive = 1;
  184.     if (interp == NULL) {
  185.     code = 0;
  186.     }
  187.  
  188.     /*
  189.      * Make one or more passes over the list of handlers, invoking
  190.      * at most one handler in each pass.  After invoking a handler,
  191.      * go back to the start of the list again so that (a) if a new
  192.      * higher-priority handler gets marked while executing a lower
  193.      * priority handler, we execute the higher-priority handler
  194.      * next, and (b) if a handler gets deleted during the execution
  195.      * of a handler, then the list structure may change so it isn't
  196.      * safe to continue down the list anyway.
  197.      */
  198.  
  199.     while (1) {
  200.     for (asyncPtr = firstHandler; asyncPtr != NULL;
  201.         asyncPtr = asyncPtr->nextPtr) {
  202.         if (asyncPtr->ready) {
  203.         break;
  204.         }
  205.     }
  206.     if (asyncPtr == NULL) {
  207.         break;
  208.     }
  209.     asyncPtr->ready = 0;
  210.     code = (*asyncPtr->proc)(asyncPtr->clientData, interp, code);
  211.     }
  212.     asyncActive = 0;
  213.     return code;
  214. }
  215.  
  216. /*
  217.  *----------------------------------------------------------------------
  218.  *
  219.  * Tcl_AsyncDelete --
  220.  *
  221.  *    Frees up all the state for an asynchronous handler.  The handler
  222.  *    should never be used again.
  223.  *
  224.  * Results:
  225.  *    None.
  226.  *
  227.  * Side effects:
  228.  *    The state associated with the handler is deleted.
  229.  *
  230.  *----------------------------------------------------------------------
  231.  */
  232.  
  233. void
  234. Tcl_AsyncDelete(async)
  235.     Tcl_AsyncHandler async;        /* Token for handler to delete. */
  236. {
  237.     AsyncHandler *asyncPtr = (AsyncHandler *) async;
  238.     AsyncHandler *prevPtr;
  239.  
  240.     if (firstHandler == asyncPtr) {
  241.     firstHandler = asyncPtr->nextPtr;
  242.     if (firstHandler == NULL) {
  243.         lastHandler = NULL;
  244.     }
  245.     } else {
  246.     prevPtr = firstHandler;
  247.     while (prevPtr->nextPtr != asyncPtr) {
  248.         prevPtr = prevPtr->nextPtr;
  249.     }
  250.     prevPtr->nextPtr = asyncPtr->nextPtr;
  251.     if (lastHandler == asyncPtr) {
  252.         lastHandler = prevPtr;
  253.     }
  254.     }
  255.     ckfree((char *) asyncPtr);
  256. }
  257.