tclEvent.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:34k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclEvent.c --
  3.  *
  4.  * This file implements some general event related interfaces including
  5.  * background errors, exit handlers, and the "vwait" and "update"
  6.  * command procedures. 
  7.  *
  8.  * Copyright (c) 1990-1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1998 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tclEvent.c,v 1.28.2.15 2007/03/19 17:06:25 dgp Exp $
  15.  */
  16. #include "tclInt.h"
  17. #include "tclPort.h"
  18. /*
  19.  * The data structure below is used to report background errors.  One
  20.  * such structure is allocated for each error;  it holds information
  21.  * about the interpreter and the error until bgerror can be invoked
  22.  * later as an idle handler.
  23.  */
  24. typedef struct BgError {
  25.     Tcl_Interp *interp; /* Interpreter in which error occurred.  NULL
  26.  * means this error report has been cancelled
  27.  * (a previous report generated a break). */
  28.     char *errorMsg; /* Copy of the error message (the interp's
  29.  * result when the error occurred).
  30.  * Malloc-ed. */
  31.     char *errorInfo; /* Value of the errorInfo variable
  32.  * (malloc-ed). */
  33.     char *errorCode; /* Value of the errorCode variable
  34.  * (malloc-ed). */
  35.     struct BgError *nextPtr; /* Next in list of all pending error
  36.  * reports for this interpreter, or NULL
  37.  * for end of list. */
  38. } BgError;
  39. /*
  40.  * One of the structures below is associated with the "tclBgError"
  41.  * assoc data for each interpreter.  It keeps track of the head and
  42.  * tail of the list of pending background errors for the interpreter.
  43.  */
  44. typedef struct ErrAssocData {
  45.     BgError *firstBgPtr; /* First in list of all background errors
  46.  * waiting to be processed for this
  47.  * interpreter (NULL if none). */
  48.     BgError *lastBgPtr; /* Last in list of all background errors
  49.  * waiting to be processed for this
  50.  * interpreter (NULL if none). */
  51. } ErrAssocData;
  52. /*
  53.  * For each exit handler created with a call to Tcl_CreateExitHandler
  54.  * there is a structure of the following type:
  55.  */
  56. typedef struct ExitHandler {
  57.     Tcl_ExitProc *proc; /* Procedure to call when process exits. */
  58.     ClientData clientData; /* One word of information to pass to proc. */
  59.     struct ExitHandler *nextPtr;/* Next in list of all exit handlers for
  60.  * this application, or NULL for end of list. */
  61. } ExitHandler;
  62. /*
  63.  * There is both per-process and per-thread exit handlers.
  64.  * The first list is controlled by a mutex.  The other is in
  65.  * thread local storage.
  66.  */
  67. static ExitHandler *firstExitPtr = NULL;
  68. /* First in list of all exit handlers for
  69.  * application. */
  70. TCL_DECLARE_MUTEX(exitMutex)
  71. /*
  72.  * This variable is set to 1 when Tcl_Finalize is called, and at the end of
  73.  * its work, it is reset to 0. The variable is checked by TclInExit() to
  74.  * allow different behavior for exit-time processing, e.g. in closing of
  75.  * files and pipes.
  76.  */
  77. static int inFinalize = 0;
  78. static int subsystemsInitialized = 0;
  79. typedef struct ThreadSpecificData {
  80.     ExitHandler *firstExitPtr;  /* First in list of all exit handlers for
  81.  * this thread. */
  82.     int inExit; /* True when this thread is exiting. This
  83.  * is used as a hack to decide to close
  84.  * the standard channels. */
  85.     Tcl_Obj *tclLibraryPath; /* Path(s) to the Tcl library */
  86. } ThreadSpecificData;
  87. static Tcl_ThreadDataKey dataKey;
  88. /*
  89.  * Common string for the library path for sharing across threads.
  90.  * This is ckalloc'd and cleared in Tcl_Finalize.
  91.  */
  92. static char *tclLibraryPathStr = NULL;
  93. #ifdef TCL_THREADS
  94. typedef struct {
  95.     Tcl_ThreadCreateProc *proc; /* Main() function of the thread */
  96.     ClientData clientData; /* The one argument to Main() */
  97. } ThreadClientData;
  98. static Tcl_ThreadCreateType NewThreadProc _ANSI_ARGS_((
  99.            ClientData clientData));
  100. #endif
  101. /*
  102.  * Prototypes for procedures referenced only in this file:
  103.  */
  104. static void BgErrorDeleteProc _ANSI_ARGS_((ClientData clientData,
  105.     Tcl_Interp *interp));
  106. static void HandleBgErrors _ANSI_ARGS_((ClientData clientData));
  107. static char * VwaitVarProc _ANSI_ARGS_((ClientData clientData,
  108.     Tcl_Interp *interp, CONST char *name1, 
  109.     CONST char *name2, int flags));
  110. /*
  111.  *----------------------------------------------------------------------
  112.  *
  113.  * Tcl_BackgroundError --
  114.  *
  115.  * This procedure is invoked to handle errors that occur in Tcl
  116.  * commands that are invoked in "background" (e.g. from event or
  117.  * timer bindings).
  118.  *
  119.  * Results:
  120.  * None.
  121.  *
  122.  * Side effects:
  123.  * The command "bgerror" is invoked later as an idle handler to
  124.  * process the error, passing it the error message.  If that fails,
  125.  * then an error message is output on stderr.
  126.  *
  127.  *----------------------------------------------------------------------
  128.  */
  129. void
  130. Tcl_BackgroundError(interp)
  131.     Tcl_Interp *interp; /* Interpreter in which an error has
  132.  * occurred. */
  133. {
  134.     BgError *errPtr;
  135.     CONST char *errResult, *varValue;
  136.     ErrAssocData *assocPtr;
  137.     int length;
  138.     /*
  139.      * The Tcl_AddErrorInfo call below (with an empty string) ensures that
  140.      * errorInfo gets properly set.  It's needed in cases where the error
  141.      * came from a utility procedure like Tcl_GetVar instead of Tcl_Eval;
  142.      * in these cases errorInfo still won't have been set when this
  143.      * procedure is called.
  144.      */
  145.     Tcl_AddErrorInfo(interp, "");
  146.     errResult = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &length);
  147.     errPtr = (BgError *) ckalloc(sizeof(BgError));
  148.     errPtr->interp = interp;
  149.     errPtr->errorMsg = (char *) ckalloc((unsigned) (length + 1));
  150.     memcpy(errPtr->errorMsg, errResult, (size_t) (length + 1));
  151.     varValue = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
  152.     if (varValue == NULL) {
  153. varValue = errPtr->errorMsg;
  154.     }
  155.     errPtr->errorInfo = (char *) ckalloc((unsigned) (strlen(varValue) + 1));
  156.     strcpy(errPtr->errorInfo, varValue);
  157.     varValue = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY);
  158.     if (varValue == NULL) {
  159. varValue = "";
  160.     }
  161.     errPtr->errorCode = (char *) ckalloc((unsigned) (strlen(varValue) + 1));
  162.     strcpy(errPtr->errorCode, varValue);
  163.     errPtr->nextPtr = NULL;
  164.     assocPtr = (ErrAssocData *) Tcl_GetAssocData(interp, "tclBgError",
  165.     (Tcl_InterpDeleteProc **) NULL);
  166.     if (assocPtr == NULL) {
  167. /*
  168.  * This is the first time a background error has occurred in
  169.  * this interpreter.  Create associated data to keep track of
  170.  * pending error reports.
  171.  */
  172. assocPtr = (ErrAssocData *) ckalloc(sizeof(ErrAssocData));
  173. assocPtr->firstBgPtr = NULL;
  174. assocPtr->lastBgPtr = NULL;
  175. Tcl_SetAssocData(interp, "tclBgError", BgErrorDeleteProc,
  176. (ClientData) assocPtr);
  177.     }
  178.     if (assocPtr->firstBgPtr == NULL) {
  179. assocPtr->firstBgPtr = errPtr;
  180. Tcl_DoWhenIdle(HandleBgErrors, (ClientData) assocPtr);
  181.     } else {
  182. assocPtr->lastBgPtr->nextPtr = errPtr;
  183.     }
  184.     assocPtr->lastBgPtr = errPtr;
  185.     Tcl_ResetResult(interp);
  186. }
  187. /*
  188.  *----------------------------------------------------------------------
  189.  *
  190.  * HandleBgErrors --
  191.  *
  192.  * This procedure is invoked as an idle handler to process all of
  193.  * the accumulated background errors.
  194.  *
  195.  * Results:
  196.  * None.
  197.  *
  198.  * Side effects:
  199.  * Depends on what actions "bgerror" takes for the errors.
  200.  *
  201.  *----------------------------------------------------------------------
  202.  */
  203. static void
  204. HandleBgErrors(clientData)
  205.     ClientData clientData; /* Pointer to ErrAssocData structure. */
  206. {
  207.     Tcl_Interp *interp;
  208.     CONST char *argv[2];
  209.     int code;
  210.     BgError *errPtr;
  211.     ErrAssocData *assocPtr = (ErrAssocData *) clientData;
  212.     Tcl_Channel errChannel;
  213.     Tcl_Preserve((ClientData) assocPtr);
  214.     
  215.     while (assocPtr->firstBgPtr != NULL) {
  216. interp = assocPtr->firstBgPtr->interp;
  217. if (interp == NULL) {
  218.     goto doneWithInterp;
  219. }
  220. /*
  221.  * Restore important state variables to what they were at
  222.  * the time the error occurred.
  223.  */
  224. Tcl_SetVar(interp, "errorInfo", assocPtr->firstBgPtr->errorInfo,
  225. TCL_GLOBAL_ONLY);
  226. Tcl_SetVar(interp, "errorCode", assocPtr->firstBgPtr->errorCode,
  227. TCL_GLOBAL_ONLY);
  228. /*
  229.  * Create and invoke the bgerror command.
  230.  */
  231. argv[0] = "bgerror";
  232. argv[1] = assocPtr->firstBgPtr->errorMsg;
  233. Tcl_AllowExceptions(interp);
  234.         Tcl_Preserve((ClientData) interp);
  235. code = TclGlobalInvoke(interp, 2, argv, 0);
  236. if (code == TCL_ERROR) {
  237.             /*
  238.              * If the interpreter is safe, we look for a hidden command
  239.              * named "bgerror" and call that with the error information.
  240.              * Otherwise, simply ignore the error. The rationale is that
  241.              * this could be an error caused by a malicious applet trying
  242.              * to cause an infinite barrage of error messages. The hidden
  243.              * "bgerror" command can be used by a security policy to
  244.              * interpose on such attacks and e.g. kill the applet after a
  245.              * few attempts.
  246.              */
  247.             if (Tcl_IsSafe(interp)) {
  248. Tcl_SavedResult save;
  249. Tcl_SaveResult(interp, &save);
  250.                 TclGlobalInvoke(interp, 2, argv, TCL_INVOKE_HIDDEN);
  251. Tcl_RestoreResult(interp, &save);
  252.                 goto doneWithInterp;
  253.             } 
  254.             /*
  255.              * We have to get the error output channel at the latest possible
  256.              * time, because the eval (above) might have changed the channel.
  257.              */
  258.             
  259.             errChannel = Tcl_GetStdChannel(TCL_STDERR);
  260.             if (errChannel != (Tcl_Channel) NULL) {
  261. char *string;
  262. int len;
  263. string = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &len);
  264. if (Tcl_FindCommand(interp, "bgerror", NULL, TCL_GLOBAL_ONLY) == NULL) {
  265.                     Tcl_WriteChars(errChannel, assocPtr->firstBgPtr->errorInfo, -1);
  266.                     Tcl_WriteChars(errChannel, "n", -1);
  267.                 } else {
  268.                     Tcl_WriteChars(errChannel,
  269.                             "bgerror failed to handle background error.n",
  270.                             -1);
  271.                     Tcl_WriteChars(errChannel, "    Original error: ", -1);
  272.                     Tcl_WriteChars(errChannel, assocPtr->firstBgPtr->errorMsg,
  273.                             -1);
  274.                     Tcl_WriteChars(errChannel, "n", -1);
  275.                     Tcl_WriteChars(errChannel, "    Error in bgerror: ", -1);
  276.                     Tcl_WriteChars(errChannel, string, len);
  277.                     Tcl_WriteChars(errChannel, "n", -1);
  278.                 }
  279.                 Tcl_Flush(errChannel);
  280.             }
  281. } else if (code == TCL_BREAK) {
  282.     /*
  283.      * Break means cancel any remaining error reports for this
  284.      * interpreter.
  285.      */
  286.     for (errPtr = assocPtr->firstBgPtr; errPtr != NULL;
  287.     errPtr = errPtr->nextPtr) {
  288. if (errPtr->interp == interp) {
  289.     errPtr->interp = NULL;
  290. }
  291.     }
  292. }
  293. /*
  294.  * Discard the command and the information about the error report.
  295.  */
  296. doneWithInterp:
  297. if (assocPtr->firstBgPtr) {
  298.     ckfree(assocPtr->firstBgPtr->errorMsg);
  299.     ckfree(assocPtr->firstBgPtr->errorInfo);
  300.     ckfree(assocPtr->firstBgPtr->errorCode);
  301.     errPtr = assocPtr->firstBgPtr->nextPtr;
  302.     ckfree((char *) assocPtr->firstBgPtr);
  303.     assocPtr->firstBgPtr = errPtr;
  304. }
  305.         
  306.         if (interp != NULL) {
  307.             Tcl_Release((ClientData) interp);
  308.         }
  309.     }
  310.     assocPtr->lastBgPtr = NULL;
  311.     Tcl_Release((ClientData) assocPtr);
  312. }
  313. /*
  314.  *----------------------------------------------------------------------
  315.  *
  316.  * BgErrorDeleteProc --
  317.  *
  318.  * This procedure is associated with the "tclBgError" assoc data
  319.  * for an interpreter;  it is invoked when the interpreter is
  320.  * deleted in order to free the information assoicated with any
  321.  * pending error reports.
  322.  *
  323.  * Results:
  324.  * None.
  325.  *
  326.  * Side effects:
  327.  * Background error information is freed: if there were any
  328.  * pending error reports, they are cancelled.
  329.  *
  330.  *----------------------------------------------------------------------
  331.  */
  332. static void
  333. BgErrorDeleteProc(clientData, interp)
  334.     ClientData clientData; /* Pointer to ErrAssocData structure. */
  335.     Tcl_Interp *interp; /* Interpreter being deleted. */
  336. {
  337.     ErrAssocData *assocPtr = (ErrAssocData *) clientData;
  338.     BgError *errPtr;
  339.     while (assocPtr->firstBgPtr != NULL) {
  340. errPtr = assocPtr->firstBgPtr;
  341. assocPtr->firstBgPtr = errPtr->nextPtr;
  342. ckfree(errPtr->errorMsg);
  343. ckfree(errPtr->errorInfo);
  344. ckfree(errPtr->errorCode);
  345. ckfree((char *) errPtr);
  346.     }
  347.     Tcl_CancelIdleCall(HandleBgErrors, (ClientData) assocPtr);
  348.     Tcl_EventuallyFree((ClientData) assocPtr, TCL_DYNAMIC);
  349. }
  350. /*
  351.  *----------------------------------------------------------------------
  352.  *
  353.  * Tcl_CreateExitHandler --
  354.  *
  355.  * Arrange for a given procedure to be invoked just before the
  356.  * application exits.
  357.  *
  358.  * Results:
  359.  * None.
  360.  *
  361.  * Side effects:
  362.  * Proc will be invoked with clientData as argument when the
  363.  * application exits.
  364.  *
  365.  *----------------------------------------------------------------------
  366.  */
  367. void
  368. Tcl_CreateExitHandler(proc, clientData)
  369.     Tcl_ExitProc *proc; /* Procedure to invoke. */
  370.     ClientData clientData; /* Arbitrary value to pass to proc. */
  371. {
  372.     ExitHandler *exitPtr;
  373.     exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler));
  374.     exitPtr->proc = proc;
  375.     exitPtr->clientData = clientData;
  376.     Tcl_MutexLock(&exitMutex);
  377.     exitPtr->nextPtr = firstExitPtr;
  378.     firstExitPtr = exitPtr;
  379.     Tcl_MutexUnlock(&exitMutex);
  380. }
  381. /*
  382.  *----------------------------------------------------------------------
  383.  *
  384.  * Tcl_DeleteExitHandler --
  385.  *
  386.  * This procedure cancels an existing exit handler matching proc
  387.  * and clientData, if such a handler exits.
  388.  *
  389.  * Results:
  390.  * None.
  391.  *
  392.  * Side effects:
  393.  * If there is an exit handler corresponding to proc and clientData
  394.  * then it is cancelled;  if no such handler exists then nothing
  395.  * happens.
  396.  *
  397.  *----------------------------------------------------------------------
  398.  */
  399. void
  400. Tcl_DeleteExitHandler(proc, clientData)
  401.     Tcl_ExitProc *proc; /* Procedure that was previously registered. */
  402.     ClientData clientData; /* Arbitrary value to pass to proc. */
  403. {
  404.     ExitHandler *exitPtr, *prevPtr;
  405.     Tcl_MutexLock(&exitMutex);
  406.     for (prevPtr = NULL, exitPtr = firstExitPtr; exitPtr != NULL;
  407.     prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) {
  408. if ((exitPtr->proc == proc)
  409. && (exitPtr->clientData == clientData)) {
  410.     if (prevPtr == NULL) {
  411. firstExitPtr = exitPtr->nextPtr;
  412.     } else {
  413. prevPtr->nextPtr = exitPtr->nextPtr;
  414.     }
  415.     ckfree((char *) exitPtr);
  416.     break;
  417. }
  418.     }
  419.     Tcl_MutexUnlock(&exitMutex);
  420.     return;
  421. }
  422. /*
  423.  *----------------------------------------------------------------------
  424.  *
  425.  * Tcl_CreateThreadExitHandler --
  426.  *
  427.  * Arrange for a given procedure to be invoked just before the
  428.  * current thread exits.
  429.  *
  430.  * Results:
  431.  * None.
  432.  *
  433.  * Side effects:
  434.  * Proc will be invoked with clientData as argument when the
  435.  * application exits.
  436.  *
  437.  *----------------------------------------------------------------------
  438.  */
  439. void
  440. Tcl_CreateThreadExitHandler(proc, clientData)
  441.     Tcl_ExitProc *proc; /* Procedure to invoke. */
  442.     ClientData clientData; /* Arbitrary value to pass to proc. */
  443. {
  444.     ExitHandler *exitPtr;
  445.     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  446.     exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler));
  447.     exitPtr->proc = proc;
  448.     exitPtr->clientData = clientData;
  449.     exitPtr->nextPtr = tsdPtr->firstExitPtr;
  450.     tsdPtr->firstExitPtr = exitPtr;
  451. }
  452. /*
  453.  *----------------------------------------------------------------------
  454.  *
  455.  * Tcl_DeleteThreadExitHandler --
  456.  *
  457.  * This procedure cancels an existing exit handler matching proc
  458.  * and clientData, if such a handler exits.
  459.  *
  460.  * Results:
  461.  * None.
  462.  *
  463.  * Side effects:
  464.  * If there is an exit handler corresponding to proc and clientData
  465.  * then it is cancelled;  if no such handler exists then nothing
  466.  * happens.
  467.  *
  468.  *----------------------------------------------------------------------
  469.  */
  470. void
  471. Tcl_DeleteThreadExitHandler(proc, clientData)
  472.     Tcl_ExitProc *proc; /* Procedure that was previously registered. */
  473.     ClientData clientData; /* Arbitrary value to pass to proc. */
  474. {
  475.     ExitHandler *exitPtr, *prevPtr;
  476.     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  477.     for (prevPtr = NULL, exitPtr = tsdPtr->firstExitPtr; exitPtr != NULL;
  478.     prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) {
  479. if ((exitPtr->proc == proc)
  480. && (exitPtr->clientData == clientData)) {
  481.     if (prevPtr == NULL) {
  482. tsdPtr->firstExitPtr = exitPtr->nextPtr;
  483.     } else {
  484. prevPtr->nextPtr = exitPtr->nextPtr;
  485.     }
  486.     ckfree((char *) exitPtr);
  487.     return;
  488. }
  489.     }
  490. }
  491. /*
  492.  *----------------------------------------------------------------------
  493.  *
  494.  * Tcl_Exit --
  495.  *
  496.  * This procedure is called to terminate the application.
  497.  *
  498.  * Results:
  499.  * None.
  500.  *
  501.  * Side effects:
  502.  * All existing exit handlers are invoked, then the application
  503.  * ends.
  504.  *
  505.  *----------------------------------------------------------------------
  506.  */
  507. void
  508. Tcl_Exit(status)
  509.     int status; /* Exit status for application;  typically
  510.  * 0 for normal return, 1 for error return. */
  511. {
  512.     Tcl_Finalize();
  513.     TclpExit(status);
  514. }
  515. /*
  516.  *-------------------------------------------------------------------------
  517.  * 
  518.  * TclSetLibraryPath --
  519.  *
  520.  * Set the path that will be used for searching for init.tcl and 
  521.  * encodings when an interp is being created.
  522.  *
  523.  * Results:
  524.  * None.
  525.  *
  526.  * Side effects:
  527.  * Changing the library path will affect what directories are
  528.  * examined when looking for encodings for all interps from that
  529.  * point forward.
  530.  *
  531.  * The refcount of the new library path is incremented and the 
  532.  * refcount of the old path is decremented.
  533.  *
  534.  *-------------------------------------------------------------------------
  535.  */
  536. void
  537. TclSetLibraryPath(pathPtr)
  538.     Tcl_Obj *pathPtr; /* A Tcl list object whose elements are
  539.  * the new library path. */
  540. {
  541.     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  542.     const char *toDupe;
  543.     int size;
  544.     if (pathPtr != NULL) {
  545. Tcl_IncrRefCount(pathPtr);
  546.     }
  547.     if (tsdPtr->tclLibraryPath != NULL) {
  548. Tcl_DecrRefCount(tsdPtr->tclLibraryPath);
  549.     }
  550.     tsdPtr->tclLibraryPath = pathPtr;
  551.     /*
  552.      *  No mutex locking is needed here as up the stack we're within
  553.      *  TclpInitLock().
  554.      */
  555.     if (tclLibraryPathStr != NULL) {
  556. ckfree(tclLibraryPathStr);
  557.     }
  558.     toDupe = Tcl_GetStringFromObj(pathPtr, &size);
  559.     tclLibraryPathStr = ckalloc((unsigned)size+1);
  560.     memcpy(tclLibraryPathStr, toDupe, (unsigned)size+1);
  561. }
  562. /*
  563.  *-------------------------------------------------------------------------
  564.  *
  565.  * TclGetLibraryPath --
  566.  *
  567.  * Return a Tcl list object whose elements are the library path.
  568.  * The caller should not modify the contents of the returned object.
  569.  *
  570.  * Results:
  571.  * As above.
  572.  *
  573.  * Side effects:
  574.  * None.
  575.  *
  576.  *-------------------------------------------------------------------------
  577.  */
  578. Tcl_Obj *
  579. TclGetLibraryPath()
  580. {
  581.     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  582.     if (tsdPtr->tclLibraryPath == NULL) {
  583. /*
  584.  * Grab the shared string and place it into a new thread specific
  585.  * Tcl_Obj.
  586.  */
  587. tsdPtr->tclLibraryPath = Tcl_NewStringObj(tclLibraryPathStr, -1);
  588. /* take ownership */
  589. Tcl_IncrRefCount(tsdPtr->tclLibraryPath);
  590.     }
  591.     return tsdPtr->tclLibraryPath;
  592. }
  593. /*
  594.  *-------------------------------------------------------------------------
  595.  *
  596.  * TclInitSubsystems --
  597.  *
  598.  * Initialize various subsytems in Tcl.  This should be called the
  599.  * first time an interp is created, or before any of the subsystems
  600.  * are used.  This function ensures an order for the initialization 
  601.  * of subsystems:
  602.  *
  603.  * 1. that cannot be initialized in lazy order because they are 
  604.  * mutually dependent.
  605.  *
  606.  * 2. so that they can be finalized in a known order w/o causing
  607.  * the subsequent re-initialization of a subsystem in the act of
  608.  * shutting down another.
  609.  *
  610.  * Results:
  611.  * None.
  612.  *
  613.  * Side effects:
  614.  * Varied, see the respective initialization routines.
  615.  *
  616.  *-------------------------------------------------------------------------
  617.  */
  618. void
  619. TclInitSubsystems(argv0)
  620.     CONST char *argv0; /* Name of executable from argv[0] to main()
  621.  * in native multi-byte encoding. */
  622. {
  623.     ThreadSpecificData *tsdPtr;
  624.     if (inFinalize != 0) {
  625. panic("TclInitSubsystems called while finalizing");
  626.     }
  627.     /*
  628.      * Grab the thread local storage pointer before doing anything because
  629.      * the initialization routines will be registering exit handlers.
  630.      * We use this pointer to detect if this is the first time this
  631.      * thread has created an interpreter.
  632.      */
  633.     tsdPtr = (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey);
  634.     if (subsystemsInitialized == 0) {
  635. /* 
  636.  * Double check inside the mutex.  There are definitly calls
  637.  * back into this routine from some of the procedures below.
  638.  */
  639. TclpInitLock();
  640. if (subsystemsInitialized == 0) {
  641.     /*
  642.      * Have to set this bit here to avoid deadlock with the
  643.      * routines below us that call into TclInitSubsystems.
  644.      */
  645.     subsystemsInitialized = 1;
  646.     tclExecutableName = NULL;
  647.     /*
  648.      * Initialize locks used by the memory allocators before anything
  649.      * interesting happens so we can use the allocators in the
  650.      * implementation of self-initializing locks.
  651.      */
  652. #if USE_TCLALLOC
  653.     TclInitAlloc(); /* process wide mutex init */
  654. #endif
  655. #ifdef TCL_MEM_DEBUG
  656.     TclInitDbCkalloc(); /* process wide mutex init */
  657. #endif
  658.     TclpInitPlatform(); /* creates signal handler(s) */
  659.     TclInitObjSubsystem(); /* register obj types, create mutexes */
  660.     TclInitIOSubsystem(); /* inits a tsd key (noop) */
  661.     TclInitEncodingSubsystem(); /* process wide encoding init */
  662.     TclInitNamespaceSubsystem(); /* register ns obj type (mutexed) */
  663. }
  664. TclpInitUnlock();
  665.     }
  666.     if (tsdPtr == NULL) {
  667. /*
  668.  * First time this thread has created an interpreter.
  669.  * We fetch the key again just in case no exit handlers were
  670.  * registered by this point.
  671.  */
  672. (void) TCL_TSD_INIT(&dataKey);
  673. TclInitNotifier();
  674.      }
  675. }
  676. /*
  677.  *----------------------------------------------------------------------
  678.  *
  679.  * Tcl_Finalize --
  680.  *
  681.  * Shut down Tcl.  First calls registered exit handlers, then
  682.  * carefully shuts down various subsystems.
  683.  * Called by Tcl_Exit or when the Tcl shared library is being 
  684.  * unloaded.
  685.  *
  686.  * Results:
  687.  * None.
  688.  *
  689.  * Side effects:
  690.  * Varied, see the respective finalization routines.
  691.  *
  692.  *----------------------------------------------------------------------
  693.  */
  694. void
  695. Tcl_Finalize()
  696. {
  697.     ExitHandler *exitPtr;
  698.     
  699.     /*
  700.      * Invoke exit handlers first.
  701.      */
  702.     Tcl_MutexLock(&exitMutex);
  703.     inFinalize = 1;
  704.     for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) {
  705. /*
  706.  * Be careful to remove the handler from the list before
  707.  * invoking its callback.  This protects us against
  708.  * double-freeing if the callback should call
  709.  * Tcl_DeleteExitHandler on itself.
  710.  */
  711. firstExitPtr = exitPtr->nextPtr;
  712. Tcl_MutexUnlock(&exitMutex);
  713. (*exitPtr->proc)(exitPtr->clientData);
  714. ckfree((char *) exitPtr);
  715. Tcl_MutexLock(&exitMutex);
  716.     }    
  717.     firstExitPtr = NULL;
  718.     Tcl_MutexUnlock(&exitMutex);
  719.     TclpInitLock();
  720.     if (subsystemsInitialized != 0) {
  721. subsystemsInitialized = 0;
  722. /*
  723.  * Ensure the thread-specific data is initialised as it is
  724.  * used in Tcl_FinalizeThread()
  725.  */
  726. (void) TCL_TSD_INIT(&dataKey);
  727. /*
  728.  * Clean up after the current thread now, after exit handlers.
  729.  * In particular, the testexithandler command sets up something
  730.  * that writes to standard output, which gets closed.
  731.  * Note that there is no thread-local storage after this call.
  732.  */
  733. Tcl_FinalizeThread();
  734. /*
  735.  * Now finalize the Tcl execution environment.  Note that this
  736.  * must be done after the exit handlers, because there are
  737.  * order dependencies.
  738.  */
  739. TclFinalizeCompilation();
  740. TclFinalizeExecution();
  741. TclFinalizeEnvironment();
  742. /* 
  743.  * Finalizing the filesystem must come after anything which
  744.  * might conceivably interact with the 'Tcl_FS' API. 
  745.  */
  746. TclFinalizeFilesystem();
  747. /*
  748.  * Undo all the Tcl_ObjType registrations, and reset the master list
  749.  * of free Tcl_Obj's.  After this returns, no more Tcl_Obj's should
  750.  * be allocated or freed.
  751.  *
  752.  * Note in particular that TclFinalizeObjects() must follow
  753.  * TclFinalizeFilesystem() because TclFinalizeFilesystem free's
  754.  * the Tcl_Obj that holds the path of the current working directory.
  755.  */
  756. TclFinalizeObjects();
  757. /* 
  758.  * We must be sure the encoding finalization doesn't need
  759.  * to examine the filesystem in any way.  Since it only
  760.  * needs to clean up internal data structures, this is
  761.  * fine.
  762.  */
  763. TclFinalizeEncodingSubsystem();
  764. if (tclExecutableName != NULL) {
  765.     ckfree(tclExecutableName);
  766.     tclExecutableName = NULL;
  767. }
  768. if (tclNativeExecutableName != NULL) {
  769.     ckfree(tclNativeExecutableName);
  770.     tclNativeExecutableName = NULL;
  771. }
  772. if (tclDefaultEncodingDir != NULL) {
  773.     ckfree(tclDefaultEncodingDir);
  774.     tclDefaultEncodingDir = NULL;
  775. }
  776. if (tclLibraryPathStr != NULL) {
  777.     ckfree(tclLibraryPathStr);
  778.     tclLibraryPathStr = NULL;
  779. }
  780. Tcl_SetPanicProc(NULL);
  781. /*
  782.  * There have been several bugs in the past that cause
  783.  * exit handlers to be established during Tcl_Finalize
  784.  * processing.  Such exit handlers leave malloc'ed memory,
  785.  * and Tcl_FinalizeThreadAlloc or Tcl_FinalizeMemorySubsystem
  786.  * will result in a corrupted heap.  The result can be a
  787.  * mysterious crash on process exit.  Check here that
  788.  * nobody's done this.
  789.  */
  790. #ifdef TCL_MEM_DEBUG
  791. if ( firstExitPtr != NULL ) {
  792.     Tcl_Panic( "exit handlers were created during Tcl_Finalize" );
  793. }
  794. #endif
  795. TclFinalizePreserve();
  796. /*
  797.  * Free synchronization objects.  There really should only be one
  798.  * thread alive at this moment.
  799.  */
  800. TclFinalizeSynchronization();
  801. #if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG) && !defined(PURIFY)
  802. TclFinalizeThreadAlloc();
  803. #endif
  804. /*
  805.  * We defer unloading of packages until very late 
  806.  * to avoid memory access issues.  Both exit callbacks and
  807.  * synchronization variables may be stored in packages.
  808.  * 
  809.  * Note that TclFinalizeLoad unloads packages in the reverse
  810.  * of the order they were loaded in (i.e. last to be loaded
  811.  * is the first to be unloaded).  This can be important for
  812.  * correct unloading when dependencies exist.
  813.  * 
  814.  * Once load has been finalized, we will have deleted any
  815.  * temporary copies of shared libraries and can therefore
  816.  * reset the filesystem to its original state.
  817.  */
  818. TclFinalizeLoad();
  819. TclResetFilesystem();
  820. /*
  821.  * At this point, there should no longer be any ckalloc'ed memory.
  822.  */
  823. TclFinalizeMemorySubsystem();
  824. inFinalize = 0;
  825.     }
  826.     TclFinalizeLock();
  827. }
  828. /*
  829.  *----------------------------------------------------------------------
  830.  *
  831.  * Tcl_FinalizeThread --
  832.  *
  833.  * Runs the exit handlers to allow Tcl to clean up its state
  834.  * about a particular thread.
  835.  *
  836.  * Results:
  837.  * None.
  838.  *
  839.  * Side effects:
  840.  * Varied, see the respective finalization routines.
  841.  *
  842.  *----------------------------------------------------------------------
  843.  */
  844. void
  845. Tcl_FinalizeThread()
  846. {
  847.     ExitHandler *exitPtr;
  848.     ThreadSpecificData *tsdPtr;
  849.     tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
  850.     if (tsdPtr != NULL) {
  851. tsdPtr->inExit = 1;
  852. /*
  853.  * Clean up the library path now, before we invalidate thread-local
  854.  * storage or calling thread exit handlers.
  855.  */
  856. if (tsdPtr->tclLibraryPath != NULL) {
  857.     Tcl_DecrRefCount(tsdPtr->tclLibraryPath);
  858.     tsdPtr->tclLibraryPath = NULL;
  859. }
  860. for (exitPtr = tsdPtr->firstExitPtr; exitPtr != NULL;
  861. exitPtr = tsdPtr->firstExitPtr) {
  862.     /*
  863.      * Be careful to remove the handler from the list before invoking
  864.      * its callback.  This protects us against double-freeing if the
  865.      * callback should call Tcl_DeleteThreadExitHandler on itself.
  866.      */
  867.     tsdPtr->firstExitPtr = exitPtr->nextPtr;
  868.     (*exitPtr->proc)(exitPtr->clientData);
  869.     ckfree((char *) exitPtr);
  870. }
  871. TclFinalizeIOSubsystem();
  872. TclFinalizeNotifier();
  873. TclFinalizeAsync();
  874.     }
  875.     /*
  876.      * Blow away all thread local storage blocks.
  877.      *
  878.      * Note that Tcl API allows creation of threads which do not use any
  879.      * Tcl interp or other Tcl subsytems. Those threads might, however,
  880.      * use thread local storage, so we must unconditionally finalize it.
  881.      *
  882.      * Fix [Bug #571002]
  883.      */
  884.     TclFinalizeThreadData();
  885. }
  886. /*
  887.  *----------------------------------------------------------------------
  888.  *
  889.  * TclInExit --
  890.  *
  891.  * Determines if we are in the middle of exit-time cleanup.
  892.  *
  893.  * Results:
  894.  * If we are in the middle of exiting, 1, otherwise 0.
  895.  *
  896.  * Side effects:
  897.  * None.
  898.  *
  899.  *----------------------------------------------------------------------
  900.  */
  901. int
  902. TclInExit()
  903. {
  904.     return inFinalize;
  905. }
  906. /*
  907.  *----------------------------------------------------------------------
  908.  *
  909.  * TclInThreadExit --
  910.  *
  911.  * Determines if we are in the middle of thread exit-time cleanup.
  912.  *
  913.  * Results:
  914.  * If we are in the middle of exiting this thread, 1, otherwise 0.
  915.  *
  916.  * Side effects:
  917.  * None.
  918.  *
  919.  *----------------------------------------------------------------------
  920.  */
  921. int
  922. TclInThreadExit()
  923. {
  924.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  925.     TclThreadDataKeyGet(&dataKey);
  926.     if (tsdPtr == NULL) {
  927. return 0;
  928.     } else {
  929. return tsdPtr->inExit;
  930.     }
  931. }
  932. /*
  933.  *----------------------------------------------------------------------
  934.  *
  935.  * Tcl_VwaitObjCmd --
  936.  *
  937.  * This procedure is invoked to process the "vwait" Tcl command.
  938.  * See the user documentation for details on what it does.
  939.  *
  940.  * Results:
  941.  * A standard Tcl result.
  942.  *
  943.  * Side effects:
  944.  * See the user documentation.
  945.  *
  946.  *----------------------------------------------------------------------
  947.  */
  948. /* ARGSUSED */
  949. int
  950. Tcl_VwaitObjCmd(clientData, interp, objc, objv)
  951.     ClientData clientData; /* Not used. */
  952.     Tcl_Interp *interp; /* Current interpreter. */
  953.     int objc; /* Number of arguments. */
  954.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  955. {
  956.     int done, foundEvent;
  957.     char *nameString;
  958.     if (objc != 2) {
  959.         Tcl_WrongNumArgs(interp, 1, objv, "name");
  960. return TCL_ERROR;
  961.     }
  962.     nameString = Tcl_GetString(objv[1]);
  963.     if (Tcl_TraceVar(interp, nameString,
  964.     TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
  965.     VwaitVarProc, (ClientData) &done) != TCL_OK) {
  966. return TCL_ERROR;
  967.     };
  968.     done = 0;
  969.     foundEvent = 1;
  970.     while (!done && foundEvent) {
  971. foundEvent = Tcl_DoOneEvent(TCL_ALL_EVENTS);
  972.     }
  973.     Tcl_UntraceVar(interp, nameString,
  974.     TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
  975.     VwaitVarProc, (ClientData) &done);
  976.     /*
  977.      * Clear out the interpreter's result, since it may have been set
  978.      * by event handlers.
  979.      */
  980.     Tcl_ResetResult(interp);
  981.     if (!foundEvent) {
  982. Tcl_AppendResult(interp, "can't wait for variable "", nameString,
  983. "":  would wait forever", (char *) NULL);
  984. return TCL_ERROR;
  985.     }
  986.     return TCL_OK;
  987. }
  988. /* ARGSUSED */
  989. static char *
  990. VwaitVarProc(clientData, interp, name1, name2, flags)
  991.     ClientData clientData; /* Pointer to integer to set to 1. */
  992.     Tcl_Interp *interp; /* Interpreter containing variable. */
  993.     CONST char *name1; /* Name of variable. */
  994.     CONST char *name2; /* Second part of variable name. */
  995.     int flags; /* Information about what happened. */
  996. {
  997.     int *donePtr = (int *) clientData;
  998.     *donePtr = 1;
  999.     return (char *) NULL;
  1000. }
  1001. /*
  1002.  *----------------------------------------------------------------------
  1003.  *
  1004.  * Tcl_UpdateObjCmd --
  1005.  *
  1006.  * This procedure is invoked to process the "update" Tcl command.
  1007.  * See the user documentation for details on what it does.
  1008.  *
  1009.  * Results:
  1010.  * A standard Tcl result.
  1011.  *
  1012.  * Side effects:
  1013.  * See the user documentation.
  1014.  *
  1015.  *----------------------------------------------------------------------
  1016.  */
  1017. /* ARGSUSED */
  1018. int
  1019. Tcl_UpdateObjCmd(clientData, interp, objc, objv)
  1020.     ClientData clientData; /* Not used. */
  1021.     Tcl_Interp *interp; /* Current interpreter. */
  1022.     int objc; /* Number of arguments. */
  1023.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  1024. {
  1025.     int optionIndex;
  1026.     int flags = 0; /* Initialized to avoid compiler warning. */
  1027.     static CONST char *updateOptions[] = {"idletasks", (char *) NULL};
  1028.     enum updateOptions {REGEXP_IDLETASKS};
  1029.     if (objc == 1) {
  1030. flags = TCL_ALL_EVENTS|TCL_DONT_WAIT;
  1031.     } else if (objc == 2) {
  1032. if (Tcl_GetIndexFromObj(interp, objv[1], updateOptions,
  1033. "option", 0, &optionIndex) != TCL_OK) {
  1034.     return TCL_ERROR;
  1035. }
  1036. switch ((enum updateOptions) optionIndex) {
  1037.     case REGEXP_IDLETASKS: {
  1038. flags = TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS|TCL_DONT_WAIT;
  1039. break;
  1040.     }
  1041.     default: {
  1042. panic("Tcl_UpdateObjCmd: bad option index to UpdateOptions");
  1043.     }
  1044. }
  1045.     } else {
  1046.         Tcl_WrongNumArgs(interp, 1, objv, "?idletasks?");
  1047. return TCL_ERROR;
  1048.     }
  1049.     
  1050.     while (Tcl_DoOneEvent(flags) != 0) {
  1051. /* Empty loop body */
  1052.     }
  1053.     /*
  1054.      * Must clear the interpreter's result because event handlers could
  1055.      * have executed commands.
  1056.      */
  1057.     Tcl_ResetResult(interp);
  1058.     return TCL_OK;
  1059. }
  1060. #ifdef TCL_THREADS
  1061. /*
  1062.  *-----------------------------------------------------------------------------
  1063.  *
  1064.  *  NewThreadProc --
  1065.  *
  1066.  *  Bootstrap function of a new Tcl thread.
  1067.  *
  1068.  * Results:
  1069.  * None.
  1070.  *
  1071.  * Side Effects:
  1072.  * Initializes Tcl notifier for the current thread.
  1073.  *
  1074.  *-----------------------------------------------------------------------------
  1075.  */
  1076. static Tcl_ThreadCreateType
  1077. NewThreadProc(ClientData clientData)
  1078. {
  1079.     ThreadClientData *cdPtr;
  1080.     ClientData threadClientData;
  1081.     Tcl_ThreadCreateProc *threadProc;
  1082.     cdPtr = (ThreadClientData*)clientData;
  1083.     threadProc = cdPtr->proc;
  1084.     threadClientData = cdPtr->clientData;
  1085.     ckfree((char*)clientData); /* Allocated in Tcl_CreateThread() */
  1086.     (*threadProc)(threadClientData);
  1087.     TCL_THREAD_CREATE_RETURN;
  1088. }
  1089. #endif
  1090. /*
  1091.  *----------------------------------------------------------------------
  1092.  *
  1093.  * Tcl_CreateThread --
  1094.  *
  1095.  * This procedure creates a new thread. This actually belongs
  1096.  * to the tclThread.c file but since we use some private 
  1097.  * data structures local to this file, it is placed here.
  1098.  *
  1099.  * Results:
  1100.  * TCL_OK if the thread could be created.  The thread ID is
  1101.  * returned in a parameter.
  1102.  *
  1103.  * Side effects:
  1104.  * A new thread is created.
  1105.  *
  1106.  *----------------------------------------------------------------------
  1107.  */
  1108. int
  1109. Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags)
  1110.     Tcl_ThreadId *idPtr; /* Return, the ID of the thread */
  1111.     Tcl_ThreadCreateProc proc; /* Main() function of the thread */
  1112.     ClientData clientData; /* The one argument to Main() */
  1113.     int stackSize; /* Size of stack for the new thread */
  1114.     int flags; /* Flags controlling behaviour of
  1115.  * the new thread */
  1116. {
  1117. #ifdef TCL_THREADS
  1118.     ThreadClientData *cdPtr;
  1119.     cdPtr = (ThreadClientData*)ckalloc(sizeof(ThreadClientData));
  1120.     cdPtr->proc = proc;
  1121.     cdPtr->clientData = clientData;
  1122.     return TclpThreadCreate(idPtr, NewThreadProc, (ClientData)cdPtr,
  1123.                            stackSize, flags);
  1124. #else
  1125.     return TCL_ERROR;
  1126. #endif /* TCL_THREADS */
  1127. }