Special variables have a global value which is shared across all threads, and a dynamic value which is local to each thread. The function symbol-value returns the variable dynamic binding if bound else the global value.
Two new declaration specifiers have been added, ext:global and ext:dynamic, which allow a symbol to be declared as a global special, or a dynamic special, respectively. These specifiers allow the usage of a variable to be restricted - the compiler can check for erroneous attempts bind to a global variable. These specifiers can also be used by the compiler to optimise symbol-value access - an access to a defined global variable need not first check the dynamic value, and access to a dynamic variable need not consider the global value.
Defining global and dynamic special variables
A global or dynamic special variable can be globally defined by using proclaim along with the new declaration specifiers ext:global and ext:dynamic, just as for proclaiming a special variable. Two variants of the standard defvar macros are also provided.
|ext:defgvar variable &optional val doc||[Macro]|
For globally defining global variables at top level. Proclaims the variable ext:global and, optionally, initializes it. If the variable already has a value, the old value is not clobbered. The third argument is an optional documentation string for the variable.
|ext:defdvar variable &optional val doc||[Macro]|
For globally defining dynamic variables at top level. Proclaims the variable ext:dynamic. The variable is optionally initialized in the current thread if currently unbound, otherwise the val form is not evaluated. When a initial val form is given it is evaluated by newly created threads to initialise the variable. The third argument is an optional documentation string for the variable.
Note that ext:defdvar does not initialize the variable across all threads, just the thread executing the macro, and in newly created threads. This could leave the variable unbound in other threads. This macro may in future be modified to initialise the variable across all threads in which the value is unbound, making the assumption that in such cases the variable is not currently used and thus there are no synchronisation issues.
Symbol dynamic value cell allocation
The current symbol dynamic value is stored in thread local storage. This storage is allocated only when code dynamically binds a symbol value, but when such a binding does occur the storage is currently reserved across all threads and can not be freed. Since most code creates dynamic bindings to only small number of special variables, the lack of garbage collection of the dynamic value cells is generally not a problem.
A memory region is currently reserved for the thread dynamic value cells upon thread creation and the later expansion of this region is not currently supported. The size of this region can be set upon startup using the -symbol-dynamic-values-size command line argument, or setup in a saved lisp core through the variable lisp::*symbol-dynamic-values-size*. If an overflow of this region is reported, then increase the size by one cell for each dynamic variable used by an application.
Of the special symbols exported from the :common-lisp package, the following are defined as regular special variables. If a thread does not bind a dynamic value to these then it will be using the shared global value.
*break-on-signals*, *compile-print*, *compile-verbose*, *debug-io*, *debugger-hook*, *default-pathname-defaults*, *error-output*, *features*, *load-print*, *load-verbose*, *macroexpand-hook*, *modules*, *print-pprint-dispatch*, *query-io*, *random-state*, *read-default-float-format*, *readtable*, *standard-input*, *standard-output*, *terminal-io*, *trace-output*.
The typical values of many of these special variables, such as streams and the random state, are not thread safe so a thread should bind suitable values to these if there is a potential conflict. Since this could cause unexpected problems for programmers, perhaps more of the currently special variables will be defined as thread local dynamic special variables.
The follow symbols, exported from the :common-lisp package, are defined as dynamic special variables and are initialised with a fresh default value at the startup of each thread.
variable *, **, ***, *compile-file-pathname*, *compile-file-truename*, *gensym-counter*, *load-pathname*, *load-truename*, *package*, *print-array*, *print-base*, *print-case*, *print-circle*, *print-escape*, *print-gensym*, *print-length*, *print-level*, *print-lines*, *print-miser-width*, *print-pretty*, *print-radix*, *print-readably*, *print-right-margin*, *read-base*, *read-eval*, *read-suppress*, variable +, ++, +++, variable -, variable /, //, ///.