1 ;;;; Dump the current Lisp image into a core file. Also contains
2 ;;;; various high-level initialization stuff: loading init files and
3 ;;;; parsing environment variables.
5 ;;;; (All the real work is done by C.)
7 ;;;; This software is part of the SBCL system. See the README file for
10 ;;;; This software is derived from the CMU CL system, which was
11 ;;;; written at Carnegie Mellon University and released into the
12 ;;;; public domain. The software is in the public domain and is
13 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
14 ;;;; files for more information.
16 (in-package "SB!IMPL")
18 ;;;; SAVE-LISP-AND-DIE itself
20 (define-alien-routine "save" (boolean)
22 (initial-fun (unsigned #.sb
!vm
:n-word-bits
))
24 (save-runtime-options int
)
26 (compression-level int
)
27 (application-type int
))
30 (define-alien-routine "gc_and_save" void
33 (save-runtime-options int
)
35 (compression-level int
)
36 (application-type int
))
39 (defvar sb
!vm
::*restart-lisp-function
*)
41 (define-condition save-condition
(reference-condition)
44 :references
(list '(:sbcl
:node
"Saving a Core Image"))))
46 (define-condition save-error
(error save-condition
)
48 (:report
"Could not save core."))
50 (define-condition save-with-multiple-threads-error
(save-error)
51 ((interactive-thread :initarg
:interactive-threads
52 :reader save-with-multiple-threads-error-interactive-threads
)
53 (other-threads :initarg
:other-threads
54 :reader save-with-multiple-threads-error-other-threads
))
55 (:report
(lambda (condition stream
)
56 (let ((interactive (save-with-multiple-threads-error-interactive-threads condition
))
57 (other (save-with-multiple-threads-error-other-threads condition
)))
58 (format stream
"~@<Cannot save core with multiple threads running.~
59 ~@:_~@:_Interactive thread~P (of current session):~
60 ~@:_~2@T~<~{~A~^, ~}~:>~
61 ~@:_~@:_Other thread~P:~
62 ~@:_~2@T~<~{~A~^, ~}~:>~@:>"
63 (length interactive
) (list interactive
)
64 (length other
) (list other
))))))
66 (defun save-lisp-and-die (core-file-name &key
67 (toplevel #'toplevel-init
)
69 (save-runtime-options nil
)
72 (environment-name "auxiliary")
75 (application-type :console
))
77 "Save a \"core image\", i.e. enough information to restart a Lisp
78 process later in the same state, in the file of the specified name.
79 Only global state is preserved: the stack is unwound in the process.
81 The following &KEY arguments are defined:
84 The function to run when the created core file is resumed. The
85 default function handles command line toplevel option processing
86 and runs the top level read-eval-print loop. This function returning
87 is equivalent to (SB-EXT:EXIT :CODE 0) being called.
89 TOPLEVEL functions should always provide an ABORT restart: otherwise
90 code they call will run without one.
93 If true, arrange to combine the SBCL runtime and the core image
94 to create a standalone executable. If false (the default), the
95 core image will not be executable on its own. Executable images
96 always behave as if they were passed the --noinform runtime option.
99 If true, values of runtime options --dynamic-space-size and
100 --control-stack-size that were used to start SBCL are stored in
101 the standalone executable, and restored when the executable is
102 run. This also inhibits normal runtime option processing, causing
103 all command line arguments to be passed to the toplevel.
104 Meaningless if :EXECUTABLE is NIL.
107 If true (the default on cheneygc), do a purifying GC which moves all
108 dynamically allocated objects into static space. This takes
109 somewhat longer than the normal GC which is otherwise done, but
110 it's only done once, and subsequent GC's will be done less often
111 and will take less time in the resulting core file. See the PURIFY
112 function. This parameter has no effect on platforms using the
113 generational garbage collector.
116 This should be a list of the main entry points in any newly loaded
117 systems. This need not be supplied, but locality and/or GC performance
118 may be better if they are. Meaningless if :PURIFY is NIL. See the
122 This is also passed to the PURIFY function when :PURIFY is T.
126 This is only meaningful if the runtime was built with the :SB-CORE-COMPRESSION
127 feature enabled. If NIL (the default), saves to uncompressed core files. If
128 :SB-CORE-COMPRESSION was enabled at build-time, the argument may also be
129 an integer from -1 to 9, corresponding to zlib compression levels, or T
130 (which is equivalent to the default compression level, -1).
133 Present only on Windows and is meaningful only with :EXECUTABLE T.
134 Specifies the subsystem of the executable, :CONSOLE or :GUI.
135 The notable difference is that :GUI doesn't automatically create a console
136 window. The default is :CONSOLE.
138 The save/load process changes the values of some global variables:
140 *STANDARD-OUTPUT*, *DEBUG-IO*, etc.
141 Everything related to open streams is necessarily changed, since
142 the OS won't let us preserve a stream across save and load.
144 *DEFAULT-PATHNAME-DEFAULTS*
145 This is reinitialized to reflect the working directory where the
146 saved core is loaded.
148 SAVE-LISP-AND-DIE interacts with SB-ALIEN:LOAD-SHARED-OBJECT: see its
149 documentation for details.
151 On threaded platforms only a single thread may remain running after
152 SB-EXT:*SAVE-HOOKS* have run. Applications using multiple threads can
153 be SAVE-LISP-AND-DIE friendly by registering a save-hook that quits
154 any additional threads, and an init-hook that restarts them.
156 This implementation is not as polished and painless as you might like:
157 * It corrupts the current Lisp image enough that the current process
158 needs to be killed afterwards. This can be worked around by forking
159 another process that saves the core.
160 * There is absolutely no binary compatibility of core images between
161 different runtime support programs. Even runtimes built from the same
162 sources at different times are treated as incompatible for this
164 This isn't because we like it this way, but just because there don't
165 seem to be good quick fixes for either limitation and no one has been
166 sufficiently motivated to do lengthy fixes."
168 (declare (ignore purify root-structures environment-name
))
169 #!+sb-core-compression
170 (check-type compression
(or boolean
(integer -
1 9)))
171 #!-sb-core-compression
173 (error "Unable to save compressed core: this runtime was not built with zlib support"))
174 (when *dribble-stream
*
175 (restart-case (error "Dribbling to ~s is enabled." (pathname *dribble-stream
*))
177 :report
"Stop dribbling and save the core."
180 :report
"Abort saving the core."
181 (return-from save-lisp-and-die
))))
182 (when (eql t compression
)
183 (setf compression -
1))
184 (tune-hashtable-sizes-of-all-packages)
186 ;; FIXME: Would it be possible to unmix the PURIFY logic from this
187 ;; function, and just do a GC :FULL T here? (Then if the user wanted
188 ;; a PURIFYed image, he'd just run PURIFY immediately before calling
189 ;; SAVE-LISP-AND-DIE.)
190 (labels ((restart-lisp ()
191 (handling-end-of-the-world
193 #!+hpux
(%primitive sb
!vm
::setup-return-from-lisp-stub
)
195 (foreign-bool (value)
198 (let ((name (native-namestring
199 (physicalize-pathname core-file-name
)
203 ;; Do a destructive non-conservative GC, and then save a core.
204 ;; A normal GC will leave huge amounts of storage unreclaimed
205 ;; (over 50% on x86). This needs to be done by a single function
206 ;; since the GC will invalidate the stack.
207 #!+gencgc
(gc-and-save name
208 (foreign-bool executable
)
209 (foreign-bool save-runtime-options
)
210 (foreign-bool compression
)
213 (ecase application-type
219 (get-lisp-obj-address #'restart-lisp
)
220 (foreign-bool executable
)
221 (foreign-bool save-runtime-options
)
222 (foreign-bool compression
)
225 (ecase application-type
229 ;; Save the restart function into a static symbol, to allow GC-AND-SAVE
230 ;; access to it even after the GC has moved it.
232 (setf sb
!vm
::*restart-lisp-function
* #'restart-lisp
)
235 (purify :root-structures root-structures
236 :environment-name environment-name
)
240 ;; Something went very wrong -- reinitialize to have a prayer
241 ;; of being able to report the error.
243 (error 'save-error
)))
246 (call-hooks "save" *save-hooks
*)
248 (itimer-emulation-deinit)
249 (let ((threads (sb!thread
:list-all-threads
)))
250 (unless (= 1 (length threads
))
251 (let* ((interactive (sb!thread
::interactive-threads
))
252 (other (set-difference threads interactive
)))
253 (error 'save-with-multiple-threads-error
254 :interactive-threads interactive
255 :other-threads other
))))
261 (drop-all-hash-caches)