TIP 121: Controlled Application Shutdown via Tcl_Exit

Login
Bounty program for improvements to Tcl and certain Tcl packages.
Author:         Joe Mistachkin <joe@mistachkin.com>
State:          Final
Type:           Project
Vote:           Done
Created:        05-Dec-2002
Post-History:   
Tcl-Version:    8.5

Abstract

This TIP will allow all applications to perform a controlled shutdown (or do nothing) in the event that Tcl_Exit() is called.

Rationale

For most applications written in C that use Tcl, calling the runtime exit() function is normally a reasonable way to shutdown the application. Unfortunately, this is not always the case. Applications written in other languages (and very complex C applications) may have very specific application shutdown requirements. This is especially true in multi-threaded environments. The problem is further compounded by extensions that use Tcl_Exit.

Versus Exit Handlers

There are distinct advantages to using this method instead of using normal exit handlers in some cases. The normal exit handler cannot defer (or in an emergency, prevent) the application shutdown because Tcl_Finalize() has already been called. From the perspective of the exit handler, we have no way of knowing what other exit handlers have been called and/or their subsystems destroyed. In addition, even if it could somehow cause Tcl_Finalize() to defer the application shutdown, some or all of the other exit handlers may have already been executed, which would leave the application in an inconsistent state. This relatively simple change allows the programmer to get control very early during the application shutdown process.

Proposed Changes

First, this TIP proposes a new Tcl API function called Tcl_SetExitProc() or something similar. This function accepts a Tcl_ExitProc pointer and returns a Tcl_ExitProc pointer. The return value is the old exit proc pointer.

Second, the Tcl_Exit() Tcl API function would be modified to allow for the handler to be called.

Third, the documentation for Tcl_Exit() would be updated to include Tcl_SetExitProc() and a warning that any custom exit proc should NOT return.

Tcl_SetExitProc

Tcl_ExitProc *
Tcl_SetExitProc(proc)
    Tcl_ExitProc *proc; /* new exit handler for app or NULL */
{
    Tcl_ExitProc *prevExitProc; /* return prev exit handler to caller */

    Tcl_MutexLock(&exitMutex);
    prevExitProc = appExitPtr; /* get old app exit ptr */
    appExitPtr = proc; /* set new app exit ptr */
    Tcl_MutexUnlock(&exitMutex);

    return prevExitProc;
}

Tcl_Exit

void
Tcl_Exit(status)
    int status;			/* Exit status for application;  typically
				 * 0 for normal return, 1 for error return. */
{
    Tcl_ExitProc *currentAppExitPtr;

    Tcl_MutexLock(&exitMutex);
    currentAppExitPtr = appExitPtr;
    Tcl_MutexUnlock(&exitMutex);

    if (currentAppExitPtr) {
      /***********************************************************/
      /* WARNING: This code SHOULD NOT return, as there is code  */
      /*          that depends on Tcl_Exit never returning.      */
      /***********************************************************/
      currentAppExitPtr((ClientData) status);
    } else {
      Tcl_Finalize();
      TclpExit(status);
    }

    Tcl_Panic ("exitProc returned!");
}

Example

void MyAppExitProc(ClientData clientData)
{
  /* #1. Perform application specific shutdown code...    */
  /* #2. Wait for other threads to gracefully shutdown... */

  exit(0);

  return; /* We should never get here. */
}


 ... sometime during application initialization ...

 /* from this point on MyAppExitProc will handle Tcl_Exit requests */
 Tcl_SetExitProc(MyAppExitProc);

 ... optionally, sometime later ...

 /* from this point on the old (default) handling will be used */
 Tcl_SetExitProc(NULL);

Reference Implementation

A patch that implements everything suggested in this TIP is available at the URL:

http://sourceforge.net/tracker/index.php?func=detail&aid=649313&group\_id=10894&atid=310894

Consequences

There is no change for current users of the Tcl_Exit() function, including the [exit] command, if Tcl_SetExitProc() is never called explicitly by the application.

Copyright

This document is hereby placed in the public domain.

History