X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fsave.c;h=635bf49873497fcb971b7c43c62190a59e30cd4d;hb=a157ed0be79751f85b8243c06102eea95af06aa3;hp=9273ce19aeb7286e060480e0563ccec5a1244042;hpb=baa0eaf21221dc564088c37b228c620c298aeaa1;p=sbcl.git diff --git a/src/runtime/save.c b/src/runtime/save.c index 9273ce1..635bf498 100644 --- a/src/runtime/save.c +++ b/src/runtime/save.c @@ -34,10 +34,40 @@ #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; + } + + if (RUNTIME_OPTIONS_WORDS != + fwrite(optarray, sizeof(size_t), RUNTIME_OPTIONS_WORDS, file)) { + perror("Error writing runtime options to file"); + } +} + static void write_lispobj(lispobj obj, FILE *file) { - fwrite(&obj, sizeof(lispobj), 1, file); + if (1 != fwrite(&obj, sizeof(lispobj), 1, file)) { + perror("Error writing to file"); + } } static long @@ -76,10 +106,83 @@ write_bytes(FILE *file, char *addr, long bytes, os_vm_offset_t file_offset) 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) { - int words, bytes, data; + size_t words, bytes, data; static char *names[] = {NULL, "dynamic", "static", "read-only"}; write_lispobj(id, file); @@ -88,8 +191,13 @@ output_space(FILE *file, int id, lispobj *addr, lispobj *end, os_vm_offset_t fil bytes = words * sizeof(lispobj); - printf("writing %d 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); @@ -110,10 +218,11 @@ open_core_for_saving(char *filename) 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 @@ -148,7 +257,7 @@ save_to_filehandle(FILE *file, char *filename, lispobj init_function, file); { unsigned char *p; - for (p = build_id; *p; ++p) + for (p = (unsigned char *)build_id; *p; ++p) write_lispobj(*p, file); } @@ -166,18 +275,26 @@ save_to_filehandle(FILE *file, char *filename, lispobj init_function, (lispobj *)STATIC_SPACE_START, (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER,0), core_start_pos); +#ifdef LISP_FEATURE_GENCGC + /* Flush the current_region, updating the tables. */ + gc_alloc_update_all_page_tables(); + update_dynamic_space_free_pointer(); +#endif #ifdef reg_ALLOC +#ifdef LISP_FEATURE_GENCGC output_space(file, DYNAMIC_CORE_SPACE_ID, - (lispobj *)current_dynamic_space, + (lispobj *)DYNAMIC_SPACE_START, dynamic_space_free_pointer, core_start_pos); #else -#ifdef LISP_FEATURE_GENCGC - /* Flush the current_region, updating the tables. */ - gc_alloc_update_all_page_tables(); - update_dynamic_space_free_pointer(); + output_space(file, + DYNAMIC_CORE_SPACE_ID, + (lispobj *)current_dynamic_space, + dynamic_space_free_pointer, + core_start_pos); #endif +#else output_space(file, DYNAMIC_CORE_SPACE_ID, (lispobj *)DYNAMIC_SPACE_START, @@ -193,12 +310,12 @@ save_to_filehandle(FILE *file, char *filename, lispobj init_function, { 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); @@ -209,18 +326,46 @@ save_to_filehandle(FILE *file, char *filename, lispobj init_function, } #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); - write_lispobj(CORE_MAGIC, file); - fclose(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)); + + if (1 != fwrite(&core_start_pos, sizeof(os_vm_offset_t), 1, file)) { + perror("Error writing core starting position to file"); + fclose(file); + } else { + write_lispobj(CORE_MAGIC, file); + fclose(file); + } #ifndef LISP_FEATURE_WIN32 if (make_executable) @@ -280,13 +425,20 @@ save_runtime_to_filehandle(FILE *output, void *runtime, size_t runtime_size) size_t padding; void *padbytes; - fwrite(runtime, 1, runtime_size, output); + if (runtime_size != fwrite(runtime, 1, runtime_size, output)) { + perror("Error saving runtime"); + return 0; + } padding = (os_vm_page_size - (runtime_size % os_vm_page_size)) & ~os_vm_page_size; if (padding > 0) { padbytes = successful_malloc(padding); memset(padbytes, 0, padding); - fwrite(padbytes, 1, padding, output); + if (padding != fwrite(padbytes, 1, padding, output)) { + perror("Error saving runtime"); + free(padbytes); + return 0; + } free(padbytes); } @@ -326,7 +478,8 @@ prepare_to_save(char *filename, boolean prepend_runtime, void **runtime_bytes, } 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; @@ -339,5 +492,6 @@ save(char *filename, lispobj init_function, boolean prepend_runtime) 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); }