TIP #285 Version 1.4: Script Cancellation with [cancel] and Tcl_CancelEval

This is not necessarily the current version of this TIP.


TIP:285
Title:Script Cancellation with [cancel] and Tcl_CancelEval
Version:$Revision: 1.4 $
Authors: Joe Mistachkin <joe at mistachkin dot com>
Dawson Cowals <dawson at dawsoncowals dot com>
State:Draft
Type:Project
Tcl-Version:8.6
Vote:Pending
Created:Sunday, 04 June 2006
Keywords:eval, cancel, unwind, terminate, runaway, async, thread, safe

Abstract

This TIP introduces the ability to quickly and safely cancel a script within a specified interpreter from any thread in the process.

Rationale

Currently, once the evaluation of a script has been initiated it will do one of the following:

In each of the cases above, neither the host application nor an interactive user have any recourse to terminate the script prior to it running its course.

There are many situations for which it is absolutely necessary to be able to cancel a running script without its cooperation and without setting an arbitrary limit on the amount of time it can run (TIP #143). This is especially true in a multi-threaded application embedding environment, or where a user interface is present.

  1. In the case where the completion time for a script is unknown, non-existent, or non-deterministic a user may want or need to terminate the script prematurely.

  2. When evaluating an untrusted - or marginally trusted - script in either a safe or standard interpreter, there is a risk that the script might never terminate. In such a situation it is not reasonable to forcibly terminate the thread or the entire process.

    1. Forcibly terminating a thread prevents Tcl and Tk from cleaning up their thread-specific memory and resources.

    2. The host application may suffer similar memory and resource leaks as well as other serious side-effects that may corrupt data, prevent other threads from properly synchronizing, or leave the process in an unknown and unrecoverable state.

    3. For an interactive host application valuable work may be lost without providing an opportunity to save pending modifications. Even in the absence of modifications the host application might have been holding locks that left unreleased would prevent other processes and users from using important resources.

The basic building blocks needed for any scripting language to seamlessly integrate with an enterprise-ready host application are:

Tcl now provides full support for all of the above except script cancellation. TIP #143 allows for scripts to be prematurely terminated after reaching resource limits that were pre-arranged by the host application. However, this only handles terminating scripts based on a narrow set of deterministic criteria. Full support would require the ability to immediately and unconditionally terminate the evaluation of a script without adversely affecting the execution environment of the host application. In addition the following issues must be addressed:

Several other mainstream scripting engines (e.g., JavaScript, Microsoft Active Scripting, etc.) currently provide this capability to cancel the evaluation of a script. This TIP proposes an implementation that would bring this necessary aspect of application integration to Tcl. This must be implemented in the core, because access to and modification of internal Tcl functions and data structures is required.

Specification

A new interp cancel script command will be added, as follows:

interp cancel ?-unwind? ?--? ?path? ?result?

This command cancels the script being evaluated in the interpreter.

Arguments

-unwind

This argument is optional. Without -unwind, the evaluation stack for the interpreter is unwound until an enclosing catch command is found or there are no further invocations of the interpreter left on the call-stack. With -unwind, the evaluation stack for the interpreter is unwound without regard to any intervening catch command until there are no further invocations of the interpreter left on the call-stack.

--

This argument is optional, and marks the end of options. The argument following this one will be treated as being the path argument even if it starts with a "-".

path

This argument is optional. If not supplied, the current interpreter is assumed; otherwise, the interpreter specified by path is used.

result

This argument is optional. If not supplied, a default error message is left in the result of the interpreter; otherwise, the result specified by result is used.

Behavior

When a script is canceled, the following occur:

Notes

C API

Constants

TCL_CANCEL_UNWIND

New eval-flag bit that applies to Tcl_CancelEval and Tcl_Canceled.

When used in flags for Tcl_CancelEval, the evaluation stack for interp is unwound without regard to any intervening catch command until there are no further invocations of interp left on the call stack. When not set, the evaluation stack for the interpreter is unwound until an enclosing catch command is found or there are no further invocations of interp left on the call-stack.

When used in flags for Tcl_Canceled, checks if the script being evaluated has been canceled using the TCL_CANCEL_UNWIND flag (i.e., the evaluation stack for interp is being completely unwound).

TCL_LEAVE_ERR_MSG

Existing variable-related flag bit that applies to Tcl_Canceled only.

When used in flags for Tcl_Canceled, an error message will be left in the result of interp if the script being evaluated has been canceled.

Functions

int Tcl_CancelEval(Tcl_Interp *interp, Tcl_Obj *resultObjPtr, ClientData clientData, int flags)

The Tcl_CancelEval function initiates cancellation of the script being evaluated in interp. It returns a standard Tcl result. If resultObjPtr is NULL, a default error message will be left in the result of interp indicating that the script was canceled or unwound. If resultObjPtr is not NULL, it will be used verbatim to supply the result of interp. The clientData is reserved for future use and must be zero. This function may be called from any thread in the process, regardless of which thread created interp.

int Tcl_Canceled(Tcl_Interp *interp, int flags)

The Tcl_Canceled function checks whether the script being evaluated in interp has been canceled. Returns a standard Tcl result (i.e., TCL_ERROR if the script being eva