contrib packages.
Zach Beane:
- He provided a number of additions to SB-POSIX and implemented the
- original timer facility on which SBCL's timers are based.
+ He provided a number of additions to SB-POSIX, implemented the
+ original timer facility on which SBCL's timers are based. and also
+ contributed the :SAVE-RUNTIME-OPTIONS support for SAVE-LISP-AND-DIE.
James Bielman:
He assisted in work on the port to the Windows operating system, and
* new feature: new commandline argument: --script, which supports
shebang lines. See documentation for details. (based on work by
Kevin Reid)
+ * new feature: SAVE-LISP-AND-DIE can save current values of
+ --dynamic-space-size and --control-stack-size in the executable core,
+ causing it to skip normal runtime option processing. See documentation
+ for details. (thanks to Zach Beane)
* enhancement: inoccous calls to EVAL or generic functions dispatching
on subclasses of eg. STREAM no longer cause compiler notes to appear.
* enhancement: the system no longer resignals errors from --load and
(define-alien-routine "save" (boolean)
(file c-string)
(initial-fun (unsigned #.sb!vm:n-word-bits))
- (prepend-runtime int))
+ (prepend-runtime int)
+ (save-runtime-options int))
#!+gencgc
(define-alien-routine "gc_and_save" void
(file c-string)
- (prepend-runtime int))
+ (prepend-runtime int)
+ (save-runtime-options int))
#!+gencgc
(defvar sb!vm::*restart-lisp-function*)
(defun save-lisp-and-die (core-file-name &key
(toplevel #'toplevel-init)
+ (executable nil)
+ (save-runtime-options nil)
(purify t)
(root-structures ())
- (environment-name "auxiliary")
- (executable nil))
+ (environment-name "auxiliary"))
#!+sb-doc
"Save a \"core image\", i.e. enough information to restart a Lisp
process later in the same state, in the file of the specified name.
:EXECUTABLE
If true, arrange to combine the SBCL runtime and the core image
to create a standalone executable. If false (the default), the
- core image will not be executable on its own.
+ core image will not be executable on its own. Executable images
+ always behave as if they were passed the --noinform runtime option.
+
+ :SAVE-RUNTIME-OPTIONS
+ If true, values of runtime options --dynamic-space-size and
+ --control-stack-size that were used to start SBCL are stored in
+ the standalone executable, and restored when the executable is
+ run. This also inhibits normal runtime option processing, causing
+ all command line arguments to be passed to the toplevel.
+ Meaningless if :EXECUTABLE is NIL.
:PURIFY
If true (the default on cheneygc), do a purifying GC which moves all
(handling-end-of-the-world
(reinit)
(funcall toplevel)))
+ (foreign-bool (value)
+ (if value 1 0))
(save-core (gc)
(when gc
#!-gencgc (gc)
;; (over 50% on x86). This needs to be done by a single function
;; since the GC will invalidate the stack.
#!+gencgc (gc-and-save (unix-namestring core-file-name nil)
- (if executable 1 0)))
+ (foreign-bool executable)
+ (foreign-bool save-runtime-options))
(without-gcing
(save (unix-namestring core-file-name nil)
(get-lisp-obj-address #'restart-lisp)
- (if executable 1 0)))))
+ (foreign-bool executable)
+ (foreign-bool save-runtime-options))))))
;; Save the restart function into a static symbol, to allow GC-AND-SAVE
;; access to it even after the GC has moved it.
#!+gencgc
return open(filename, mode);
}
+
+static struct runtime_options *
+read_runtime_options(int fd)
+{
+ size_t optarray[RUNTIME_OPTIONS_WORDS];
+ struct runtime_options *options = NULL;
+
+ if (read(fd, optarray, RUNTIME_OPTIONS_WORDS * sizeof(size_t)) !=
+ RUNTIME_OPTIONS_WORDS * sizeof(size_t)) {
+ return NULL;
+ }
+
+ if ((RUNTIME_OPTIONS_MAGIC != optarray[0]) || (0 == optarray[1])) {
+ return NULL;
+ }
+
+ options = successful_malloc(sizeof(struct runtime_options));
+
+ options->dynamic_space_size = optarray[2];
+ options->thread_control_stack_size = optarray[3];
+
+ return options;
+}
+
+void
+maybe_initialize_runtime_options(int fd)
+{
+ off_t end_offset = sizeof(lispobj) +
+ sizeof(os_vm_offset_t) +
+ (RUNTIME_OPTIONS_WORDS * sizeof(size_t));
+
+ lseek(fd, -end_offset, SEEK_END);
+ runtime_options = read_runtime_options(fd);
+}
+
/* Search 'filename' for an embedded core. An SBCL core has, at the
- * end of the file, a trailer containing the size of the core (an
- * os_vm_offset_t) and a final signature word (the lispobj
- * CORE_MAGIC). If this trailer is found at the end of the file, the
- * start of the core can be determined from the core size.
+ * end of the file, a trailer containing optional saved runtime
+ * options, the start of the core (an os_vm_offset_t), and a final
+ * signature word (the lispobj CORE_MAGIC). If this trailer is found
+ * at the end of the file, the start of the core can be determined
+ * from the core size.
*
* If an embedded core is present, this returns the offset into the
* file to load the core from, or -1 if no core is present. */
lispobj header;
os_vm_offset_t lispobj_size = sizeof(lispobj);
os_vm_offset_t trailer_size = lispobj_size + sizeof(os_vm_offset_t);
- os_vm_offset_t core_size, pos;
+ os_vm_offset_t core_start, pos;
int fd = -1;
if ((fd = open_binary(filename, O_RDONLY)) < 0)
if (header == CORE_MAGIC) {
if (lseek(fd, -trailer_size, SEEK_END) < 0)
goto lose;
- if (read(fd, &core_size, sizeof(os_vm_offset_t)) < 0)
+ if (read(fd, &core_start, sizeof(os_vm_offset_t)) < 0)
goto lose;
- if (lseek(fd, -(core_size + trailer_size), SEEK_END) < 0)
+ if (lseek(fd, core_start, SEEK_SET) < 0)
goto lose;
pos = lseek(fd, 0, SEEK_CUR);
if (header != CORE_MAGIC)
goto lose;
+ maybe_initialize_runtime_options(fd);
+
close(fd);
return pos;
}
* function being set to the value of the static symbol
* SB!VM:RESTART-LISP-FUNCTION */
void
-gc_and_save(char *filename, int prepend_runtime)
+gc_and_save(char *filename, boolean prepend_runtime,
+ boolean save_runtime_options)
{
FILE *file;
void *runtime_bytes = NULL;
/* The dumper doesn't know that pages need to be zeroed before use. */
zero_all_free_pages();
save_to_filehandle(file, filename, SymbolValue(RESTART_LISP_FUNCTION,0),
- prepend_runtime);
+ prepend_runtime, save_runtime_options);
/* Oops. Save still managed to fail. Since we've mangled the stack
* beyond hope, there's not much we can do.
* (beyond FUNCALLing RESTART_LISP_FUNCTION, but I suspect that's
extern size_t dynamic_space_size;
extern size_t thread_control_stack_size;
+extern struct runtime_options *runtime_options;
+
#ifdef LISP_FEATURE_WIN32
#define ENVIRON _environ
#else
char **posix_argv;
char *core_string;
+struct runtime_options *runtime_options;
+
\f
int
main(int argc, char *argv[], char *envp[])
char *core = 0;
char **sbcl_argv = 0;
os_vm_offset_t embedded_core_offset = 0;
+ char *runtime_path = 0;
/* other command line options */
boolean noinform = 0;
setlocale(LC_ALL, "");
+ runtime_options = NULL;
+
+ /* Check early to see if this executable has an embedded core,
+ * which also populates runtime_options if the core has runtime
+ * options */
+ runtime_path = os_get_runtime_executable_path();
+ if (runtime_path) {
+ os_vm_offset_t offset = search_for_embedded_core(runtime_path);
+ if (offset != -1) {
+ embedded_core_offset = offset;
+ core = runtime_path;
+ } else {
+ free(runtime_path);
+ }
+ }
+
+
/* Parse our part of the command line (aka "runtime options"),
* stripping out those options that we handle. */
- {
+ if (runtime_options != NULL) {
+ dynamic_space_size = runtime_options->dynamic_space_size;
+ thread_control_stack_size = runtime_options->thread_control_stack_size;
+ sbcl_argv = argv;
+ } else {
int argi = 1;
+
+ runtime_options = successful_malloc(sizeof(struct runtime_options));
+
while (argi < argc) {
char *arg = argv[argi];
if (0 == strcmp(arg, "--script")) {
dynamic_space_size &= ~(PAGE_BYTES-1);
thread_control_stack_size &= ~(CONTROL_STACK_ALIGNMENT_BYTES-1);
+ /* Preserve the runtime options for possible future core saving */
+ runtime_options->dynamic_space_size = dynamic_space_size;
+ runtime_options->thread_control_stack_size = thread_control_stack_size;
+
/* KLUDGE: os_vm_page_size is set by os_init(), and on some
* systems (e.g. Alpha) arch_init() needs need os_vm_page_size, so
* it must follow os_init(). -- WHN 2000-01-26 */
/* If no core file was specified, look for one. */
if (!core) {
- char *runtime_path = os_get_runtime_executable_path();
-
- if (runtime_path) {
- os_vm_offset_t offset = search_for_embedded_core(runtime_path);
-
- if (offset != -1) {
- embedded_core_offset = offset;
- core = runtime_path;
- } else {
- free(runtime_path);
- core = search_for_core();
- }
- } else {
- core = search_for_core();
- }
+ core = search_for_core();
}
/* Make sure that SBCL_HOME is set and not the empty string,
extern void *successful_malloc (size_t size);
extern char *copied_string (char *string);
+#define RUNTIME_OPTIONS_MAGIC 0x31EBF355
+/* 1 for magic, 1 for boolean, 2 for struct runtime_options fields */
+#define RUNTIME_OPTIONS_WORDS (1 + 1 + 2)
+
+struct runtime_options {
+ size_t dynamic_space_size;
+ size_t thread_control_stack_size;
+};
+
#endif /* _SBCL_RUNTIME_H_ */
#include "genesis/lutex.h"
#endif
+/* write_runtime_options uses a simple serialization scheme that
+ * consists of one word of magic, one word indicating whether options
+ * are actually saved, and one word per struct field. */
+static void
+write_runtime_options(FILE *file, struct runtime_options *options)
+{
+ size_t optarray[RUNTIME_OPTIONS_WORDS];
+
+ memset(&optarray, 0, sizeof(optarray));
+ optarray[0] = RUNTIME_OPTIONS_MAGIC;
+
+ if (options != NULL) {
+ /* optarray[1] is a flag indicating that options are present */
+ optarray[1] = 1;
+ optarray[2] = options->dynamic_space_size;
+ optarray[3] = options->thread_control_stack_size;
+ }
+
+ fwrite(optarray, sizeof(size_t), RUNTIME_OPTIONS_WORDS, file);
+}
+
static void
write_lispobj(lispobj obj, FILE *file)
{
boolean
save_to_filehandle(FILE *file, char *filename, lispobj init_function,
- boolean make_executable)
+ boolean make_executable,
+ boolean save_runtime_options)
{
struct thread *th;
- os_vm_offset_t core_start_pos, core_end_pos, core_size;
+ os_vm_offset_t core_start_pos;
/* Smash the enclosing state. (Once we do this, there's no good
* way to go back, which is a sufficient reason that this ends up
* This is used to locate the start of the core when the runtime is
* prepended to it. */
fseek(file, 0, SEEK_END);
- core_end_pos = ftell(file);
- core_size = core_end_pos - core_start_pos;
- fwrite(&core_size, sizeof(os_vm_offset_t), 1, file);
+ /* If NULL runtime options are passed to write_runtime_options,
+ * command-line processing is performed as normal in the SBCL
+ * executable. Otherwise, the saved runtime options are used and
+ * all command-line arguments are available to Lisp in
+ * SB-EXT:*POSIX-ARGV*. */
+ write_runtime_options(file,
+ (save_runtime_options ? runtime_options : NULL));
+
+ fwrite(&core_start_pos, sizeof(os_vm_offset_t), 1, file);
write_lispobj(CORE_MAGIC, file);
fclose(file);
}
boolean
-save(char *filename, lispobj init_function, boolean prepend_runtime)
+save(char *filename, lispobj init_function, boolean prepend_runtime,
+ boolean save_runtime_options)
{
FILE *file;
void *runtime_bytes = NULL;
if (prepend_runtime)
save_runtime_to_filehandle(file, runtime_bytes, runtime_size);
- return save_to_filehandle(file, filename, init_function, prepend_runtime);
+ return save_to_filehandle(file, filename, init_function, prepend_runtime,
+ save_runtime_options);
}
extern void *load_runtime(char *runtime_path, size_t *size_out);
extern FILE *prepare_to_save(char *filename, boolean prepend_runtime, void **runtime_bytes, size_t *runtime_size);
extern boolean save_runtime_to_filehandle(FILE *output, void *runtime_bytes, size_t runtime_size);
-extern boolean save_to_filehandle(FILE *file, char *filename, lispobj initfun, int make_executable);
-extern boolean save(char *filename, lispobj initfun, boolean prepend_runtime);
+extern boolean save_to_filehandle(FILE *file, char *filename, lispobj initfun, boolean make_executable, boolean keep_runtime_options);
+extern boolean save(char *filename, lispobj initfun, boolean prepend_runtime, boolean keep_runtime_options);
#endif
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.21.23"
+"1.0.21.24"