#include "genesis/static-symbols.h"
#include "genesis/symbol.h"
+#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
+#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)
{
return ((data - file_offset) / os_vm_page_size) - 1;
}
+#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
+/* saving lutexes in the core */
+static void **lutex_addresses;
+static long n_lutexes = 0;
+static long max_lutexes = 0;
+
+static long
+default_scan_action(lispobj *obj)
+{
+ return (sizetab[widetag_of(*obj)])(obj);
+}
+
+static long
+lutex_scan_action(lispobj *obj)
+{
+ /* note the address of the lutex */
+ if(n_lutexes >= max_lutexes) {
+ max_lutexes *= 2;
+ lutex_addresses = realloc(lutex_addresses, max_lutexes * sizeof(void *));
+ gc_assert(lutex_addresses);
+ }
+
+ lutex_addresses[n_lutexes++] = obj;
+
+ return (*sizetab[widetag_of(*obj)])(obj);
+}
+
+typedef long (*scan_table[256])(lispobj *obj);
+
+static void
+scan_objects(lispobj *start, long n_words, scan_table table)
+{
+ lispobj *end = start + n_words;
+ lispobj *object_ptr;
+ long n_words_scanned;
+ for (object_ptr = start;
+ object_ptr < end;
+ object_ptr += n_words_scanned) {
+ lispobj obj = *object_ptr;
+
+ n_words_scanned = (table[widetag_of(obj)])(object_ptr);
+ }
+}
+
+static void
+scan_for_lutexes(lispobj *addr, long n_words)
+{
+ static int initialized = 0;
+ static scan_table lutex_scan_table;
+
+ if (!initialized) {
+ int i;
+
+ /* allocate a little space to get started */
+ lutex_addresses = malloc(16*sizeof(void *));
+ gc_assert(lutex_addresses);
+ max_lutexes = 16;
+
+ /* initialize the mapping table */
+ for(i = 0; i < ((sizeof lutex_scan_table)/(sizeof lutex_scan_table[0])); ++i) {
+ lutex_scan_table[i] = default_scan_action;
+ }
+
+ lutex_scan_table[LUTEX_WIDETAG] = lutex_scan_action;
+
+ initialized = 1;
+ }
+
+ /* do the scan */
+ scan_objects(addr, n_words, lutex_scan_table);
+}
+#endif
+
static void
output_space(FILE *file, int id, lispobj *addr, lispobj *end, os_vm_offset_t file_offset)
{
bytes = words * sizeof(lispobj);
- printf("writing %ld bytes from the %s space at 0x%08lx\n",
- bytes, names[id], (unsigned long)addr);
+#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
+ printf("scanning space for lutexes...\n");
+ scan_for_lutexes((char *)addr, words);
+#endif
+
+ printf("writing %lu bytes from the %s space at 0x%08lx\n",
+ (unsigned long)bytes, names[id], (unsigned long)addr);
data = write_bytes(file, (char *)addr, bytes, file_offset);
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
file);
{
unsigned char *p;
- for (p = build_id; *p; ++p)
+ for (p = (unsigned char *)build_id; *p; ++p)
write_lispobj(*p, file);
}
{
size_t size = (last_free_page*sizeof(long)+os_vm_page_size-1)
&~(os_vm_page_size-1);
- long *data = calloc(size, 1);
+ unsigned long *data = calloc(size, 1);
if (data) {
long offset;
int i;
for (i = 0; i < last_free_page; i++) {
- data[i] = page_table[i].first_object_offset;
+ data[i] = page_table[i].region_start_offset;
}
write_lispobj(PAGE_TABLE_CORE_ENTRY_TYPE_CODE, file);
write_lispobj(4, file);
}
#endif
+#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
+ if(n_lutexes > 0) {
+ long offset;
+ printf("writing %ld lutexes to the core...\n", n_lutexes);
+ write_lispobj(LUTEX_TABLE_CORE_ENTRY_TYPE_CODE, file);
+ /* word count of the entry */
+ write_lispobj(4, file);
+ /* indicate how many lutexes we saved */
+ write_lispobj(n_lutexes, file);
+ /* save the lutexes */
+ offset = write_bytes(file, (char *) lutex_addresses,
+ n_lutexes * sizeof(*lutex_addresses),
+ core_start_pos);
+
+ write_lispobj(offset, file);
+ }
+#endif
+
write_lispobj(END_CORE_ENTRY_TYPE_CODE, file);
/* Write a trailing header, ignored when parsing the core normally.
* 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);
}