[Openmcl-devel] save-application and :toplevel-function

Gary Byers gb at clozure.com
Wed Sep 7 15:28:34 PDT 2005

There's a loop in the kernel that calls the toplevel function repeatedly
until it's null.  (So yes, this behavior is intentional, but some of the
reasons for it are historical and ... not well remembered, at least by

The loop does something like:

   (catch :toplevel
     (let* ((f (<current-thread-toplevel-function>)))
      (if (null f)
       (funcal f)))))

There's also a function:

which updates the current thread's <current-thread-toplevel-function>
and returns its old value ; calling it with no arguments simply returns
the current value.

and calling


does (THROW :TOPLEVEL NIL).  (It'd be better if the catch tag in the kernel
loop was something a little more private/anonymous.)

If you look at the function SAVE-IMAGE (in "ccl:lib;dumplisp.lisp"),
you'll see that both the process of exiting (and ensuring that an
image is written) and the process of restarting the saved image
involve calls to these functions.  When an image starts up, the
initial thread's toplevel function is a closure which establishes the
user-specified toplevel function and calls CCL::RESTORE-LISP-POINTERS
(which is also defined in that file.)  CCL::RESTORE-LISP-POINTERS does
a lot of initialization (re-creates standard streams, reinitializes
foreign function entrypoints, runs a set of "system" and "user" startup
functions) and, when it returns, the user-specified toplevel function
is (finally) run.

On Wed, 7 Sep 2005, Dave Baum wrote:

> I am a little confused about how save-application works with a 
> toplevel-function.  I assumed that the toplevel-function would be called, and 
> that when it returned the process would end.  However, it appears that the 
> toplevel-function gets called repeatedly in an infinite loop.  Is this by 
> design, or is there something wrong with how I am generating the image? 
> Here's some code...
> (defun my-topfunc ()
>  (format t "Hello, world~%"))
> (save-application "my-app" :toplevel-function #'my-topfunc :prepend-kernel t 
> :compress t)
> Assuming that calling toplevel-function repeatedly is by design, then what is 
> the best way to have something run once and exit?  Just calling "quit" 
> doesn't seem to be enough since standard output remains unflushed.  The 
> following works, but I'm concerned that perhaps I'm missing other cleanup.
> (defun my-topfunc ()
>  (format t "Hello, world~%")
>  (finish-output *standard-output*)
>  (quit))
> Is there a function other than quit that should be used for orderly 
> termination of the lisp environment?
> Thanks,
> Dave
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel

More information about the Openmcl-devel mailing list