[Openmcl-devel] *initial-process* and *current-process*

Gary Byers gb at clozure.com
Thu Jun 23 18:26:38 PDT 2011



On Thu, 23 Jun 2011, Gabriel Dos Reis wrote:

>
> I am not doubting you.  All I can tell you is that the application works pretty
> well with CCL-1.4 and onwards except recent CCL-1.7-dev  Unfortunately,
> I did not record the SVN revision before making the update.  I tried bissection
> but the trunk seems to be unbuildable on x86-64 for a long time, so my
> efforts were non-conclusive.
>

An automated process tries to build and test the trunk CCL on a pretty 
regular basis; I spent most of yesterday alternately building it and
breaking it, and that automated process screamed hysterically every
time I broke it and I didn't sleep until it stopped screaming.

I can't guess why you'd say "the trunk seems to be unbuildable on x86-64
for a long time."  Do you think that this is:

- generally true, and you're the only person  to notice ?
- possibly due to some local issue that only affects you but which remains
   a mystery to everyone else ?


>> If the example above had been written as:
>>
>> (setq *x* 17) ; modify the static binding
>>
>> (save-application ...)
>>
>> then that modification would persist.
>
> Yes, these forms -- assignments at toplevel -- work pretty
> well.  What is happening in my application is the following:
>   1. I have a set of fasls containing toplevel assignments
>       like above
>
>   2.  I use a function to LOAD those fasls.  After loading, I verify
>        that the special variables have the "right" (modified)
>        value.  Then I call SAVE-APPLICATION.
>
>   3. The saved image from step 2. does not appear to have the
>       correct (modified) values for the special values.  These seem
>       to contain only their original toplevel values before the LOAD.
>
>   4.  The only LET-binding in effect while loading the fasls is
>        that of *PACKAGE*.  No other LET-binding (or the like) is in effect.
>        Am I understanding you correctly that by the time SAVE-APPLICATION
>        does it works, the *PACKAGE* has been "unwound" to its previous
>        value, so any changes to its symbols are lost?
>        I did not suspect this because other Lisps which have dynamic bindings
>        per thread did not bark at this (nor did CCL-1.4.)

CCL 1.4 worked exactly the same way as earlier and subsequent versions.

Threads start up with a set of "standard initial bindings": things
like *PACKAGE* and *READTABLE*, the standard stream variables, the
printer control variables, some internal things used for freelisting.

;;; (CCL::STANDARD-INITAL-BINDINGS) returns an alist whose CARs are
;;; special variable names and whose CDRs are thunks used to provide
;;; default initial values.

In the current trunk:

? (mapcar #'car (ccl::standard-initial-bindings))
(CCL::*FREE-XPS* CCL::*FREE-CIRCULARITY-HASH-TABLES* CCL::*LOGICAL-BLOCK-XP* CCL::*FORMAT-TOP-LEVEL* CCL::*FORMAT-STREAM-STACK* CCL::*VINSN-VARPARTS* CCL::*VINSN-LABEL-FREELIST* CCL::*VINSN-FREELIST* CCL::*LCELL-FREELIST* CCL::*LREG-FREELIST* CCL::*FRAG-FREELIST* CCL::*X86-LAP-FRAG-VECTOR-FREELIST* CCL::*X86-LAP-LABEL-FREELIST* *QUERY-IO* *DEBUG-IO* *TRACE-OUTPUT* *ERROR-OUTPUT* *STANDARD-OUTPUT* *STANDARD-INPUT* CCL::%TOKEN-STRINGS% *READ-BASE* *READ-SUPPRESS* *READ-DEFAULT-FLOAT-FORMAT* *READ-EVAL* *READTABLE* *PRINT-PPRINT-DISPATCH* CCL::*DEFAULT-RIGHT-MARGIN* *PRINT-LINES* *PRINT-MISER-WIDTH* *PRINT-RIGHT-MARGIN* *PRINT-READABLY* *PRINT-GENSYM* *PRINT-ARRAY* *PRINT-CASE* *PRINT-CIRCLE* *PRINT-LENGTH* *PRINT-LEVEL* *PRINT-RADIX* *PRINT-BASE* *PRINT-PRETTY* *PRINT-ESCAPE* *PRINT-STRING-LENGTH* *PRINT-SIMPLE-BIT-VECTOR* *PRINT-SIMPLE-VECTOR* *PRINT-STRUCTURE* *PRINT-ABBREVIATE-QUOTE* CCL::*BACKTRACE-CONTEXTS* CCL::%STRING-OUTPUT-STREAM-IOBLOCKS% CCL::*CONS-POOL* CCL::*ERROR!
 -PRINT-LEVEL* CCL::*ERROR-PRINT-LENGTH* CCL::*WHOSTATE* *RANDOM-STATE* *PACKAGE*)

I don't have 1.4 installed on this machine, but in 1.3 the list is a lot shorter:

? (mapcar #'car (ccl::standard-initial-bindings))
(CCL::*FREE-XPS* CCL::*FREE-CIRCULARITY-HASH-TABLES* CCL::*LOGICAL-BLOCK-XP* CCL::*FORMAT-TOP-LEVEL* CCL::*FORMAT-STREAM-STACK* CCL::*VINSN-VARPARTS* CCL::*VINSN-LABEL-FREELIST* CCL::*VINSN-FREELIST* CCL::*LCELL-FREELIST* CCL::*LREG-FREELIST* CCL::*FRAG-FREELIST* CCL::*X86-LAP-FRAG-VECTOR-FREELIST* CCL::*X86-LAP-LABEL-FREELIST* *QUERY-IO* *DEBUG-IO* *TRACE-OUTPUT* *ERROR-OUTPUT* *STANDARD-OUTPUT* *STANDARD-INPUT* CCL::%TOKEN-STRINGS% *READTABLE* CCL::*BACKTRACE-CONTEXTS* CCL::%STRING-OUTPUT-STREAM-IOBLOCKS% CCL::*CONS-POOL* CCL::*ERROR-PRINT-LEVEL* CCL::*ERROR-PRINT-LENGTH* CCL::*WHOSTATE* *RANDOM-STATE* *GENSYM-COUNTER* *PACKAGE*)

The difference involves the printer control variables; according to

<http://trac.clozure.com/ccl/wiki/ReleaseNotes/1.5>, this change was made in 1.5:

(*PRINT-ABBREVIATE-QUOTE* *PRINT-STRUCTURE* *PRINT-SIMPLE-VECTOR* *PRINT-SIMPLE-BIT-VECTOR* *PRINT-STRING-LENGTH* *PRINT-ESCAPE* *PRINT-PRETTY* *PRINT-BASE* *PRINT-RADIX* *PRINT-LEVEL* *PRINT-LENGTH* *PRINT-CIRCLE* *PRINT-CASE* *PRINT-ARRAY* *PRINT-GENSYM* *PRINT-READABLY* *PRINT-RIGHT-MARGIN* *PRINT-MISER-WIDTH* *PRINT-LINES* CCL::*DEFAULT-RIGHT-MARGIN* *PRINT-PPRINT-DISPATCH* *READ-EVAL* *READ-DEFAULT-FLOAT-FORMAT* *READ-SUPPRESS* *READ-BASE*)

The good news is that in older versions an assignment to *PRINT-BASE* (when no
dynamic binding was in effect) modified the static binding and that change
persisted when an image was saved.

The bad news is that in older versions such an assignement to *PRINT-BASE*
could have unexpected and possibly undesirable effects on ongoing printing
in other threads.  One could guard against those effects by binding the
printer control variables (via WITH-STANDARD-IO-SYNTAX) around all code that
did printing, or the implementation could make the printer control variables
thread-local.

The good news is that in newer versions assignments to printer control variables
don't have unexpected effects on printing behavior in other threads.

The bad news is that in newer versions it's harder to change the default
value of those variables in newly-created threads, and harder still to
do so in threads that you don't create.  If you wanted to have a lisp
in which *PRINT-BASE* was 16 in all newly-created threads, you're supposed
to use DEF-STANDARD-INITIAL-BINDING.  (The manual mentions this in section
7.7, but DEF-STANDARD-INITIAL-BINDING isn't documented or exported; it should
be.)

? (ccl::def-standard-initial-binding *print-base* 16)
*PRINT-BASE*
? *print-base*
10
? (process-run-function "show-me" (lambda () (format t "~&*PRINT-BASE* = ~d." *print-base*)))
#<PROCESS show-me(2) [Reset] #x30200064E0BD>
? 
*PRINT-BASE* = 16.

If we saved an image, the listener thread and other threads in that image
would start up with *PRINT-BASE* bound to 16. instead of 10.  It's more
awkward to arrange that than it used to be (it used to usually work to
just use SETQ), but the fact that SETQ had such pervasive effects wasn't 
an entirely good thing.

I think that *GENSYM-COUNTER* used to be thread-local and isn't anymore;
there are arguments on both sides and ways to lose in both cases.

The set of per-thread bindings (STANDARD-INITIAL-BINDINGS) may change from
release to release; changes that involve public variables should be (and
generally have been) documented.

The general model of how dynamic bindings work hasn't changed in a
very long time (CCL has never really implemented another model), and
this model is likely to be either very similar to in most respects or
identical to that used in other implementations in its observable
behavior.  The set of things that're automatically thread-local is
probably larger in CCL than in other implementations and there may be
a stronger relationship between the bindings in effect in the creating
thread and those established in the created thread in other
implementations than there is in CCL.  (In CCL, there's essentially no
such relationship.)




>
> -- Gaby
>
>


More information about the Openmcl-devel mailing list