NAME¶
ns_ictl - Facility to control AOLserver multi-threaded Tcl interpreters
SYNOPSIS¶
ns_ictl addmodule module
ns_ictl cancel thread
ns_ictl cleanup
ns_ictl epoch
ns_ictl get
ns_ictl getmodules
ns_ictl gettraces which
ns_ictl once key script
ns_ictl oncleanup script
ns_ictl oncreate script
ns_ictl ondelete script
ns_ictl oninit script
ns_ictl package ?-exact? package ?version?
ns_ictl runtraces which
ns_ictl save script
ns_ictl threads
ns_ictl trace when script
ns_ictl update
DESCRIPTION¶
This command provides access to the internal facilities to control and configure
multi-threaded Tcl interpreters in the context of AOLserver virtual servers.
It is normally used in startup initialization scripts to define how new
interpreters are initialized when created and to support cleanup and
re-initalization between transactions (e.g., HTTP connections).
- ns_ictl addmodule module
- Add a module to the list of modules to be initialized at
startup. This command is not normally required as each module specified in
the AOLserver modules config section for the corresponding server (e.g.,
ns/server/server1/modules) is automatically added to the list.
- ns_ictl cancel thread
- Send an asynchronous interrupt request to the specified
thread, cancelling any script currently executing on any AOLserver created
interpreter (note the interrupt is not virtual-server specific). This
command utilizes the facilities of Tcl_AsyncMark to mark as ready a
callback registered with Tcl_AsyncCreate. The callback places an
error message in the interpreter result and returns TCL_ERROR to
unwind the call stack. The underlying Tcl facility has limitations, e.g.,
the interrupt will only be noticed when Tcl checks via
Tcl_AsyncReady calls between commands and the interrupt can be
caught with a catch command. See the man page for
Tcl_AsyncCreate for details.
- ns_ictl cleanup
- This command invokes any callbacks registered during a
transaction via the C-level Ns_TclRegisterDefer routine. Unlike
callbacks registered with the ns_ictl trace deallocate command or
Ns_TclRegisterTrace routine, these callbacks are executed only once
and there is no Tcl-level access to the underlying
Ns_TclRegisterDefer routine.
- ns_ictl epoch
- This command returns the unique id for the current
duplication script for the virtual server. The id starts as 0 when the
virtual server is created and is incremented each time a new script is
saved via the ns_ictl save command.
- ns_ictl get
- Return the current duplication script for the virtual
server. This command is useful to view the duplication script created by
the initialization script at startup.
- ns_ictl getmodules
- Return the list of modules to be initialized at startup.
This list corresponds to the names of modules specified in the virtual
server modules config section, e.g., ns/server/server1/modules
unless additional modules are added via the ns_ictl addmodule
command.
- ns_ictl gettraces which
- Return the list of traces which will be invoked at the
specified time. The which argument can be one of create,
delete, allocate, deallocate, getconn, or freeconn. The
traces are returned in the order in which they will be executed. Script
level traces are returns as strings to evaluate and C-level traces are
returned with strings which specify the address of the underlying C
procedure and argument.
- ns_ictl once key script
- Evaluate given script once in the virtual server. The given
key is a string name which uniquely identifies the corresponding script.
This command is useful in a Tcl package which includes one-time
initialization routines, e.g., calls to ns_register_proc or
initialization of shared variables using nsv_set (see
EXAMPLES below).
- ns_ictl oncleanup script
- This command is equivalent to ns_ictl trace
deallocate script.
- ns_ictl oncreate script
- This command is equivalent to ns_ictl trace create
script.
- ns_ictl ondelete script
- This command is equivalent to ns_ictl trace delete
script.
- ns_ictl oninit script
- This command is equivalent to ns_ictl trace allocate
script.
- ns_ictl package ?-exact? package
?version?
- This command is used to require a package in the calling
interpreter and, if successfully loaded, in all other interpreters for the
virtual server. In addition to ensuring version consistency for the
package, it is equivalent to:
set version [package require package ?version?]
ns_ictl trace allocate [list package require package
$version]
- ns_ictl runtraces which
- This command runs the requested traces. The which
argument must be one of create, delete, allocate,
deallocate, getconn, or freeconn. Direct calls to
this command are not normally necessary as the underlying C code will
invoke the callbacks at the required times. Exceptions include calling
ns_ictl runtraces or testing purposes or to mimic the normal
cleanup and initialization work performed on between transactions in a
long running thread (see EXAMPLES below).
- ns_ictl save script
- Save the given script as the duplication script,
incrementing the virtual server epoch number. This command is normally
called by the bootstrap script after constructing the script to duplicate
the procedures defined by sourcing the various module initialization
script files.
- ns_ictl threads
- Return a list of all threads with interpreters for the
virtual server. The ids return are small strings which represent the
underlying thread ids and can be passed to the ns_ictl cancel
command to send an asynchronous cancel request.
- ns_ictl trace create script
- Register script to be called when an interpreter is
first created. This is useful to create procedures, require packages, or
initialize other state to be used during the lifetime of the interpreter.
- ns_ictl trace delete script
- Register script to be called before an interpreter
is destroyed. This is useful to free any resources which may have been
allocated for the interpreter during the lifetime of the interpreter.
- ns_ictl trace allocate script
- Register script to be called each time an
interpreter is allocated for use by the Ns_TclAllocateInterp
routine. This is useful for reinitializing resources which may be used
during a single transaction in the interpreter.
- ns_ictl trace deallocate script
- Register script to be called each time an
interpreter is returned after a transaction with the
Ns_TclDeAllocateInterp routine. This is useful for garbage
collection, i.e., freeing any resources which may be used during a single
transaction in the interpreter.
- ns_ictl trace getconn script
- Register script to be called each time an
interpreter is returned and associated with an HTTP connection with the
Ns_GetConnInterp routine. This could be useful to define variables
relative to the HTTP request.
- ns_ictl trace freeconn script
- Register script to be called each time an HTTP
connection is closed. This could be used to log information about the
request, e.g., timing statistics. Note that the interpreter may still be
actively evaluating a script after the connection is closed, i.e., this is
not equivalent to ns_ictl trace deallocate for connection-related
interpreters.
- ns_ictl update
- This command can be used to atomically compare the epoch of
the current duplication script with the epoch of the interpreter,
evaluating the script and updating the epoch in the interpreter if they do
not match. This command is generally registered as a callback with
ns_ictl trace allocate by the legacy initialization code.
INTERPRETER ALLOCATION¶
Tcl interpreter in AOLserver are available on demand with state specific to a
virtual server. These interpreters are also expected to be reused for multiple
transactions (e.g., HTTP connections, scheduled procedures, socket callbacks).
To support reuse, AOLserver provides the C-level
Ns_TclAllocateInterp
routine to allocate an interpreter from a per-thread cache (creating and
initializing a new interpreter if necessary) and the
Ns_TclDeAllocateInterp routine to return an interpreter to the cache
when no longer required. All interpreters in the per-thread cache are
destroyed when a thread exists.
In general, only C-level extension writers need to call the C-level API's
directly; the various Tcl-level interfaces in AOLserver (e.g.,
ADP
pages,
ns_regiseter_proc,
ns_schedule_proc,
ns_thread,
etc.) allocate and reuse interpreters using the C-level API's automatically
before invoking the cooresponding script or ADP page.
INTERPRETER TRACES¶
To ensure a consistent state of interpreters when allocated and enable cleanup
and reinitialization between transactions, each virtual server maintains a
list of callbacks to be invoked at various points in the lifetime of an
interpreter. These callbacks are generally installed when the server is
initialized at startup and then called automatically by the
Ns_TclAllocateInterp and
Ns_TclDeAllocateInterp API's at the
appropriate times and in consistent order. The
Ns_TclRegisterTrace
routine can be used to register C-level callbacks and the
ns_ictl trace
command can be used to register Tcl script callbacks. The
ns_ictl
gettraces command can be used to list all currently registered
callbacks, both at the Tcl script and C level.
Callbacks registered via the tracing facility are invoked in a specific order
depending on the type. Initialization style callbacks including
create,
allocate, and
getconn are invoked in FIFO order, with all script
callbacks invoked after all C-level callbacks. This enables extension writers
to utilize the facilities of previously initialized extensions.
Correspondingly, cleanup style callbacks including
freeconn,
deallocate, and
delete are invoked in LIFO order, with all
scripts callbacks invoked before C-level callbacks. This helps avoid the
possibility that a cleanup callback utilizes features of a previously cleaned
up extension.
In addition, the
ns_ictl package command can be used to consistently
manage the loading of a Tcl package in all interpreters for a virtual server.
This feature is mostly a convenience routine built above the generic trace
framework with additional checks to ensure version number consistency. Coupled
with
ns_ictl once, the
ns_ictl package command provides a clean
framework to utilize Tcl packages in multi-threaded AOLserver (see
EXAMPLES).
VIRTUAL SERVER TCL INITIALIZATION¶
AOLserver also supports a Tcl initialization framework for virtual servers based
on callbacks registered by loadable modules and the sourcing of scripts files
located in corresponding directories. Options to
ns_ictl to support
this framework include
save,
get,
epoch, and
update and are used in conjunction with the generic tracing facility by
the virtual server bootstrap script (normally
bin/init.tcl). The
ns_eval command also relies on this framework to support dynamic update
of the state of interpreters.
This initialization framework pre-dates the Tcl package facilities and utilizes
introspection of the state of a startup interpreter at the end of
initialization to construct a single script which attempts to duplicate the
state in subsequent interpreters. Steps taken during this initialization
include:
- 1. Load all modules in the server's module config section,
e.g.,
- ns/server/server1/modules. Modules with Tcl C-level
extensions typically call the legacy Ns_TclInitInterps routine or
the more general Ns_TclRegisterTrace routine with the
NS_TCL_TRACE_CREATE flag in their module init routine to register a
callback to invoke when new interpreters are created. The callback
normally creates one or more new commands in the interpreter with
Tcl_CreateObjCommand but may perform any per-interpreter
initialization required, e.g., creating and saving private state with the
Tcl_SetAssocData facility. In addition, as modules are loaded, the
string name of the module is added to the list of known modules.
- 2. After all C modules are loaded, AOLserver creates a new
Tcl
- interpreter for the virtual server, executing any trace
callbacks already registered via the loaded C modules (e.g., any
Ns_TclInitInterps callbacks) and then sources the virtual server
bootstrap script, normally bin/init.tcl. This script creates a few
utility procedures and then sources all private and public
script files in directories which correspond to loaded modules in the
order in which they were loaded. These directories are normally relative
to the virtual server and to the AOLserver installation directory, e.g.,
initialization script files for the module mymod in the
server1 virtual server would be searched for in the
servers/server1/modules/tcl/mymod/ and modules/tcl/mymod/.
Any init.tcl file found in each directory is sourced first with all
remaining files sourced in alphabetical order. In addition, any files in
the public directory with identical names to files in the private
directory are skipped as a means to enable overloading of specific
functionality on a per-server basis. In practice, most modules only
contain shared utility procedures defined in the public directories
and the private directories are empty or non-existant. The script
files normally contain a mix of commands to evaluate once for server
configuration (e.g., a call to ns_register_proc to bind a Tcl
procedure to an HTTP request URL) with proc and namespace
commands to provide additional functionality in the interpreter.
- 3. After all script files have been sourced, the bootstrap
script
- code then uses a collection of recursive procedures to
extract the definitions of all procedures defined in all namespaces. The
definitions are used to construct a script which attempts to duplicate the
state of the initialization interpreters. This scripts is then saved as
the per-virtual server duplication script with the ns_ictl
save command which also increments the epoch to 1. There are
limits to this approach to determine the full state, e.g., it does not
attempt to duplicate any global variables which may have been defined in
the startup scripts. Typically, startup scripts will use nsv_set or
other mechanisms to store such shared state.
- 4. The bootstrap code then uses the ns_ictl trace
allocate
- command to register a callback to the ns_ictl update
command each time an interpreter is allocated for use. In practice,
interpreters are created with the default epoch of 0 and the first
call to ns_ictl update determines an out-of-date condition,
evaluates the duplication script, and increments the interpreter's
epoch to 1 to match the state created by the startup interp.
- 5. Subsequent calls the ns_eval, if any, will
evaluate the
- given script and then re-generate and save the duplication
script as was done at startup, incrementing the epoch once again.
In this way, dynamic updates which are detected in other interpreters on
their next call to ns_ictl update can be supported in a limited
fashion.
In practice, while generally successful, this duplication technique has
inhibited the clean use of proper Tcl package extensions and encouraged the
use of the
ns_eval command which is generally not recommended for the
non-deterministic manner in which it attempts to dynamically reconfigure a
server. Also, commands required to configure the server once (e.g., calls to
ns_register_proc) are inter-mixed with
proc commands designed to
extend functionality in all interpreters, complicating configuration
management.
As an alternative, the example below illustrates a means to more explicitly
manage configuration through a combination of direct calls to
ns_ictl trace
create and
ns_ictl once. Unfortunately, the all encompassing nature
of the legacy initialization approach makes it difficult to incrementally move
to this cleaner approach because the duplication script construction code is
unable to distinguish between state created with the newer, cleaner
ns_ictl commands and state created as a side effect of one or more
script files being sourced. As such, it is expected the legacy initialization
framework will remain in place until AOLserver 5.x when it will be removed
entirely in a non-backwards compatible move towards the cleaner API's.
EXAMPLES¶
This example illustrates the use of
ns_ictl package and
ns_ictl
once to load an AOLserver-aware Tcl package into a virtual server. The
following code could be added to the virtual server bootstrap script,
bin/init.tcl, to load
MyPkg in the virtual server:
#
# Startup code in bin/init.tcl:
#
# Load MyPkg in all interps (including this one).
#
ns_ictl package require MyPkg
This call will result in the package being loaded into the startup interpreter
in the ordinary Tcl fashion (see the
package man page for details).
Ordinary Tcl extension packages would need no modifications but packages which
utilize AOLserver-specific features or require garbage collection between
transactions could also use
ns_ictl for finer grained control. For
example, the
init.tcl script specified by the
package ifneeded
command in the
MyPkg package's
pkgIndex.tcl file could contains:
#
# Package code in lib/myPkg1.0/init.tcl:
#
#
package provide MyPkg 1.0
#
# Server init which will be executed the first time called,
# normally in the context of the startup interpreter as above.
#
ns_ictl once MyPkg {
# Register the run Tcl proc HTTP handler.
ns_register_proc /mypkg mkpkg::run
# Register a garbage collection callback.
ns_ictl trace deallocate mypkg::cleanup
}
#
# Code which will be invoked to initialize the package in
# all interpreters when required.
#
proc mypkg::run {} {
... handle /mypkg requests ...
}
proc mkpkg::cleanup {} {
... cleanup transaction resources for mypkg, e.g., db handles ...
}
SEE ALSO¶
Ns_TclAllocateInterp(3),
Ns_TclDeAllocateInterp(3),
Ns_GetConnInterp(3),
Ns_FreeConnInterp(3),
Ns_TclInitInterps(3), Ns_TclRegisterTrace(3),
Ns_TclRegisterDeferred(3), ns_atclose(n), ns_eval(n).
KEYWORDS¶
threads, interpreters, traces, initialization