Rename "marknsweepgc.c" to "immobile-space.c" plus 2 bugfixes
[sbcl.git] / src / runtime / save.c
blob1f2bb570ed00f3400878c63e1d454e30e63da115
1 /*
2 * This software is part of the SBCL system. See the README file for
3 * more information.
5 * This software is derived from the CMU CL system, which was
6 * written at Carnegie Mellon University and released into the
7 * public domain. The software is in the public domain and is
8 * provided with absolutely no warranty. See the COPYING and CREDITS
9 * files for more information.
12 #ifndef LISP_FEATURE_WIN32
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #endif
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/file.h>
21 #include "sbcl.h"
22 #if defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD)
23 #include "pthreads_win32.h"
24 #else
25 #include <signal.h>
26 #endif
27 #include "runtime.h"
28 #include "os.h"
29 #include "core.h"
30 #include "globals.h"
31 #include "save.h"
32 #include "dynbind.h"
33 #include "lispregs.h"
34 #include "validate.h"
35 #include "gc-internal.h"
36 #include "thread.h"
37 #include "arch.h"
38 #include "pseudo-atomic.h"
40 #include "genesis/static-symbols.h"
41 #include "genesis/symbol.h"
43 #ifdef LISP_FEATURE_GENCGC
44 # include "gencgc.h"
45 #endif
47 #ifdef LISP_FEATURE_IMMOBILE_SPACE
48 # include "immobile-space.h"
49 #endif
51 #ifdef LISP_FEATURE_SB_CORE_COMPRESSION
52 # include <zlib.h>
53 #endif
55 #define GENERAL_WRITE_FAILURE_MSG "error writing to core file"
57 /* write_runtime_options uses a simple serialization scheme that
58 * consists of one word of magic, one word indicating whether options
59 * are actually saved, and one word per struct field. */
60 static void
61 write_runtime_options(FILE *file, struct runtime_options *options)
63 size_t optarray[RUNTIME_OPTIONS_WORDS];
65 memset(&optarray, 0, sizeof(optarray));
66 optarray[0] = RUNTIME_OPTIONS_MAGIC;
68 if (options != NULL) {
69 /* optarray[1] is a flag indicating that options are present */
70 optarray[1] = 1;
71 optarray[2] = options->dynamic_space_size;
72 optarray[3] = options->thread_control_stack_size;
75 if (RUNTIME_OPTIONS_WORDS !=
76 fwrite(optarray, sizeof(size_t), RUNTIME_OPTIONS_WORDS, file)) {
77 perror("Error writing runtime options to file");
81 static void
82 write_lispobj(lispobj obj, FILE *file)
84 if (1 != fwrite(&obj, sizeof(lispobj), 1, file)) {
85 perror(GENERAL_WRITE_FAILURE_MSG);
89 static void
90 write_bytes_to_file(FILE * file, char *addr, long bytes, int compression)
92 if (compression == COMPRESSION_LEVEL_NONE) {
93 while (bytes > 0) {
94 sword_t count = fwrite(addr, 1, bytes, file);
95 if (count > 0) {
96 bytes -= count;
97 addr += count;
99 else {
100 perror(GENERAL_WRITE_FAILURE_MSG);
101 lose("core file is incomplete or corrupt\n");
104 #ifdef LISP_FEATURE_SB_CORE_COMPRESSION
105 } else if ((compression >= -1) && (compression <= 9)) {
106 # define ZLIB_BUFFER_SIZE (1u<<16)
107 z_stream stream;
108 unsigned char* buf = successful_malloc(ZLIB_BUFFER_SIZE);
109 unsigned char * written, * end;
110 long total_written = 0;
111 int ret;
112 stream.zalloc = NULL;
113 stream.zfree = NULL;
114 stream.opaque = NULL;
115 stream.avail_in = bytes;
116 stream.next_in = (void*)addr;
117 ret = deflateInit(&stream, compression);
118 if (ret != Z_OK)
119 lose("deflateInit: %i\n", ret);
120 do {
121 stream.avail_out = ZLIB_BUFFER_SIZE;
122 stream.next_out = buf;
123 ret = deflate(&stream, Z_FINISH);
124 if (ret < 0) lose("zlib deflate error: %i... exiting\n", ret);
125 written = buf;
126 end = buf+ZLIB_BUFFER_SIZE-stream.avail_out;
127 total_written += end - written;
128 while (written < end) {
129 long count = fwrite(written, 1, end-written, file);
130 if (count > 0) {
131 written += count;
132 } else {
133 perror(GENERAL_WRITE_FAILURE_MSG);
134 lose("core file is incomplete or corrupt\n");
137 } while (stream.avail_out == 0);
138 deflateEnd(&stream);
139 free(buf);
140 printf("compressed %lu bytes into %lu at level %i\n",
141 bytes, total_written, compression);
142 # undef ZLIB_BUFFER_SIZE
143 #endif
144 } else {
145 #ifdef LISP_FEATURE_SB_CORE_COMPRESSION
146 lose("Unknown core compression level %i, exiting\n", compression);
147 #else
148 lose("zlib-compressed core support not built in this runtime\n");
149 #endif
152 if (fflush(file) != 0) {
153 perror(GENERAL_WRITE_FAILURE_MSG);
154 lose("core file is incomplete or corrupt\n");
159 static long
160 write_and_compress_bytes(FILE *file, char *addr, long bytes, os_vm_offset_t file_offset,
161 int compression)
163 long here, data;
165 bytes = (bytes+os_vm_page_size-1)&~(os_vm_page_size-1);
167 #ifdef LISP_FEATURE_WIN32
168 long count;
169 /* touch every single page in the space to force it to be mapped. */
170 for (count = 0; count < bytes; count += 0x1000) {
171 volatile int temp = addr[count];
173 #endif
175 fflush(file);
176 here = ftell(file);
177 fseek(file, 0, SEEK_END);
178 data = (ftell(file)+os_vm_page_size-1)&~(os_vm_page_size-1);
179 fseek(file, data, SEEK_SET);
180 write_bytes_to_file(file, addr, bytes, compression);
181 fseek(file, here, SEEK_SET);
182 return ((data - file_offset) / os_vm_page_size) - 1;
185 static long __attribute__((__unused__))
186 write_bytes(FILE *file, char *addr, long bytes, os_vm_offset_t file_offset)
188 return write_and_compress_bytes(file, addr, bytes, file_offset,
189 COMPRESSION_LEVEL_NONE);
192 extern struct lisp_startup_options lisp_startup_options;
194 static void
195 output_space(FILE *file, int id, lispobj *addr, lispobj *end,
196 os_vm_offset_t file_offset,
197 int core_compression_level)
199 size_t words, bytes, data, compressed_flag;
200 static char *names[] = {NULL, "dynamic", "static", "read-only",
201 "immobile", "immobile"};
203 compressed_flag
204 = ((core_compression_level != COMPRESSION_LEVEL_NONE)
205 ? DEFLATED_CORE_SPACE_ID_FLAG : 0);
207 write_lispobj(id | compressed_flag, file);
208 words = end - addr;
209 write_lispobj(words, file);
211 bytes = words * sizeof(lispobj);
213 if (!lisp_startup_options.noinform)
214 printf("writing %lu bytes from the %s space at %p\n",
215 (long unsigned)bytes, names[id], addr);
217 data = write_and_compress_bytes(file, (char *)addr, bytes, file_offset,
218 core_compression_level);
220 write_lispobj(data, file);
221 write_lispobj((uword_t)addr / 1024, file); // units as per core.h
222 write_lispobj((bytes + os_vm_page_size - 1) / os_vm_page_size, file);
225 FILE *
226 open_core_for_saving(char *filename)
228 /* Open the output file. We don't actually need the file yet, but
229 * the fopen() might fail for some reason, and we want to detect
230 * that and back out before we do anything irreversible. */
231 unlink(filename);
232 return fopen(filename, "wb");
235 void
236 smash_enclosing_state(boolean verbose) {
237 struct thread *th = all_threads;
239 // Since SB-IMPL::DEINIT already checked for exactly 1 thread,
240 // losing here probably can't happen.
241 if (th->next)
242 lose("Can't save image with more than one executing thread");
244 #ifdef LISP_FEATURE_X86_64
245 untune_asm_routines_for_microarch();
246 #endif
248 /* Smash the enclosing state. (Once we do this, there's no good
249 * way to go back, which is a sufficient reason that this ends up
250 * being SAVE-LISP-AND-DIE instead of SAVE-LISP-AND-GO-ON). */
251 if (verbose) {
252 printf("[undoing binding stack and other enclosing state... ");
253 fflush(stdout);
255 unbind_to_here((lispobj *)th->binding_stack_start,th);
256 write_TLS(CURRENT_CATCH_BLOCK, 0, th); // If set to 0 on start, why here too?
257 write_TLS(CURRENT_UNWIND_PROTECT_BLOCK, 0, th);
258 if (verbose) printf("done]\n");
261 void
262 do_destructive_cleanup_before_save(lispobj init_function)
264 boolean verbose = !lisp_startup_options.noinform;
265 // Preparing to save.
266 smash_enclosing_state(verbose);
267 #ifdef LISP_FEATURE_IMMOBILE_SPACE
268 prepare_immobile_space_for_save(init_function, verbose);
269 #endif
272 boolean
273 save_to_filehandle(FILE *file, char *filename, lispobj init_function,
274 boolean make_executable,
275 boolean save_runtime_options,
276 int core_compression_level)
278 boolean verbose = !lisp_startup_options.noinform;
280 /* (Now we can actually start copying ourselves into the output file.) */
282 if (verbose) {
283 printf("[saving current Lisp image into %s:\n", filename);
284 fflush(stdout);
287 os_vm_offset_t core_start_pos = ftell(file);
288 write_lispobj(CORE_MAGIC, file);
290 int stringlen = strlen((const char *)build_id);
291 int string_words = ALIGN_UP(stringlen, sizeof (core_entry_elt_t))
292 / sizeof (core_entry_elt_t);
293 int pad = string_words * sizeof (core_entry_elt_t) - stringlen;
294 /* Write 3 word entry header: a word for entry-type-code, a word for
295 * the total length in words, and a word for the string length */
296 write_lispobj(BUILD_ID_CORE_ENTRY_TYPE_CODE, file);
297 write_lispobj(3 + string_words, file);
298 write_lispobj(stringlen, file);
299 int nwrote = fwrite(build_id, 1, stringlen, file);
300 /* Write padding bytes to align to core_entry_elt_t */
301 while (pad--) nwrote += (fputc(0xff, file) != EOF);
302 if (nwrote != (int)(sizeof (core_entry_elt_t) * string_words))
303 perror(GENERAL_WRITE_FAILURE_MSG);
305 write_lispobj(NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE, file);
306 write_lispobj(/* (word count = N spaces described by 5 words each, plus the
307 * entry type code, plus this count itself) */
308 (5 * MAX_CORE_SPACE_ID) + 2, file);
309 output_space(file,
310 READ_ONLY_CORE_SPACE_ID,
311 (lispobj *)READ_ONLY_SPACE_START,
312 read_only_space_free_pointer,
313 core_start_pos,
314 core_compression_level);
315 output_space(file,
316 STATIC_CORE_SPACE_ID,
317 (lispobj *)STATIC_SPACE_START,
318 static_space_free_pointer,
319 core_start_pos,
320 core_compression_level);
321 #ifdef LISP_FEATURE_GENCGC
322 /* Flush the current_region, updating the tables. */
323 gc_alloc_update_all_page_tables(1);
324 gc_assert(get_alloc_pointer() == (lispobj*)(page_address(find_last_free_page())));
325 #endif
326 #ifdef LISP_FEATURE_IMMOBILE_SPACE
327 output_space(file,
328 IMMOBILE_FIXEDOBJ_CORE_SPACE_ID,
329 (lispobj *)IMMOBILE_SPACE_START,
330 immobile_fixedobj_free_pointer,
331 core_start_pos,
332 core_compression_level);
333 output_space(file,
334 IMMOBILE_VARYOBJ_CORE_SPACE_ID,
335 (lispobj *)IMMOBILE_VARYOBJ_SUBSPACE_START,
336 immobile_space_free_pointer,
337 core_start_pos,
338 core_compression_level);
339 #endif
340 output_space(file,
341 DYNAMIC_CORE_SPACE_ID,
342 current_dynamic_space,
343 (lispobj *)get_alloc_pointer(),
344 core_start_pos,
345 core_compression_level);
347 write_lispobj(INITIAL_FUN_CORE_ENTRY_TYPE_CODE, file);
348 write_lispobj(3, file);
349 write_lispobj(init_function, file);
351 #ifdef LISP_FEATURE_GENCGC
353 extern void gc_store_corefile_ptes(struct corefile_pte*);
354 size_t true_size = sizeof last_free_page
355 + (last_free_page * sizeof(struct corefile_pte));
356 size_t rounded_size = ALIGN_UP(true_size, os_vm_page_size);
357 char* data = successful_malloc(rounded_size);
358 *(page_index_t*)data = last_free_page;
359 struct corefile_pte *ptes = (struct corefile_pte*)(data + sizeof(page_index_t));
360 gc_store_corefile_ptes(ptes);
361 write_lispobj(PAGE_TABLE_CORE_ENTRY_TYPE_CODE, file);
362 write_lispobj(4, file);
363 write_lispobj(rounded_size, file);
364 /* Clear unwritten bytes in the malloc'd range. They're probably zero
365 * because malloc of large blocks is usually just an mmap(),
366 * but we can't be certain the memory was freshly allocated */
367 char* clear_from = (char*)&ptes[last_free_page];
368 char* clear_to = data + rounded_size;
369 memset(clear_from, 0, clear_to-clear_from);
370 sword_t offset = write_bytes(file, data, rounded_size, core_start_pos);
371 write_lispobj(offset, file);
373 #endif
375 write_lispobj(END_CORE_ENTRY_TYPE_CODE, file);
377 /* Write a trailing header, ignored when parsing the core normally.
378 * This is used to locate the start of the core when the runtime is
379 * prepended to it. */
380 fseek(file, 0, SEEK_END);
382 /* If NULL runtime options are passed to write_runtime_options,
383 * command-line processing is performed as normal in the SBCL
384 * executable. Otherwise, the saved runtime options are used and
385 * all command-line arguments are available to Lisp in
386 * SB-EXT:*POSIX-ARGV*. */
387 write_runtime_options(file,
388 (save_runtime_options ? runtime_options : NULL));
390 if (1 != fwrite(&core_start_pos, sizeof(os_vm_offset_t), 1, file)) {
391 perror("Error writing core starting position to file");
392 fclose(file);
393 } else {
394 write_lispobj(CORE_MAGIC, file);
395 fclose(file);
398 #ifndef LISP_FEATURE_WIN32
399 if (make_executable)
400 chmod (filename, 0755);
401 #endif
403 if (verbose) printf("done]\n");
404 exit(0);
407 /* Check if the build_id for the current runtime is present in a
408 * buffer. */
410 check_runtime_build_id(void *buf, size_t size)
412 size_t idlen;
413 char *pos;
415 idlen = strlen((const char*)build_id) - 1;
416 while ((pos = memchr(buf, build_id[0], size)) != NULL) {
417 size -= (pos + 1) - (char *)buf;
418 buf = (pos + 1);
419 if (idlen <= size && memcmp(buf, build_id + 1, idlen) == 0)
420 return 1;
423 return 0;
426 /* Slurp the executable portion of the runtime into a malloced buffer
427 * and return it. Places the size in bytes of the runtime into
428 * 'size_out'. Returns NULL if the runtime cannot be loaded from
429 * 'runtime_path'. */
430 void *
431 load_runtime(char *runtime_path, size_t *size_out)
433 void *buf = NULL;
434 FILE *input = NULL;
435 size_t size, count;
436 os_vm_offset_t core_offset;
438 core_offset = search_for_embedded_core (runtime_path);
439 if ((input = fopen(runtime_path, "rb")) == NULL) {
440 fprintf(stderr, "Unable to open runtime: %s\n", runtime_path);
441 goto lose;
444 fseek(input, 0, SEEK_END);
445 size = (size_t) ftell(input);
446 fseek(input, 0, SEEK_SET);
448 if (core_offset != -1 && size > (size_t) core_offset)
449 size = core_offset;
451 buf = successful_malloc(size);
452 if ((count = fread(buf, 1, size, input)) != size) {
453 fprintf(stderr, "Premature EOF while reading runtime.\n");
454 goto lose;
457 if (!check_runtime_build_id(buf, size)) {
458 fprintf(stderr, "Failed to locate current build_id in runtime: %s\n",
459 runtime_path);
460 goto lose;
463 fclose(input);
464 *size_out = size;
465 return buf;
467 lose:
468 if (input != NULL)
469 fclose(input);
470 if (buf != NULL)
471 free(buf);
472 return NULL;
475 boolean
476 save_runtime_to_filehandle(FILE *output, void *runtime, size_t runtime_size,
477 int application_type)
479 size_t padding;
480 void *padbytes;
482 #ifdef LISP_FEATURE_WIN32
484 PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)runtime;
485 PIMAGE_NT_HEADERS nt_header = (PIMAGE_NT_HEADERS)((char *)dos_header +
486 dos_header->e_lfanew);
488 int sub_system;
489 switch (application_type) {
490 case 0:
491 sub_system = IMAGE_SUBSYSTEM_WINDOWS_CUI;
492 break;
493 case 1:
494 sub_system = IMAGE_SUBSYSTEM_WINDOWS_GUI;
495 break;
496 default:
497 fprintf(stderr, "Invalid application type %d\n", application_type);
498 return 0;
501 nt_header->OptionalHeader.Subsystem = sub_system;
503 #endif
505 if (runtime_size != fwrite(runtime, 1, runtime_size, output)) {
506 perror("Error saving runtime");
507 return 0;
510 padding = (os_vm_page_size - (runtime_size % os_vm_page_size)) & ~os_vm_page_size;
511 if (padding > 0) {
512 padbytes = successful_malloc(padding);
513 memset(padbytes, 0, padding);
514 if (padding != fwrite(padbytes, 1, padding, output)) {
515 perror("Error saving runtime");
516 free(padbytes);
517 return 0;
519 free(padbytes);
522 return 1;
525 FILE *
526 prepare_to_save(char *filename, boolean prepend_runtime, void **runtime_bytes,
527 size_t *runtime_size)
529 FILE *file;
530 char *runtime_path;
532 if (prepend_runtime) {
533 runtime_path = os_get_runtime_executable_path(0);
535 if (runtime_path == NULL && saved_runtime_path == NULL) {
536 fprintf(stderr, "Unable to get default runtime path.\n");
537 return NULL;
540 if (runtime_path == NULL)
541 *runtime_bytes = load_runtime(saved_runtime_path, runtime_size);
542 else {
543 *runtime_bytes = load_runtime(runtime_path, runtime_size);
544 free(runtime_path);
547 if (*runtime_bytes == NULL)
548 return 0;
551 file = open_core_for_saving(filename);
552 if (file == NULL) {
553 free(*runtime_bytes);
554 perror(filename);
555 return NULL;
558 return file;
561 #ifdef LISP_FEATURE_CHENEYGC
562 boolean
563 save(char *filename, lispobj init_function, boolean prepend_runtime,
564 boolean save_runtime_options, boolean compressed, int compression_level,
565 int application_type)
567 FILE *file;
568 void *runtime_bytes = NULL;
569 size_t runtime_size;
571 file = prepare_to_save(filename, prepend_runtime, &runtime_bytes, &runtime_size);
572 if (file == NULL)
573 return 1;
575 if (prepend_runtime)
576 save_runtime_to_filehandle(file, runtime_bytes, runtime_size, application_type);
578 do_destructive_cleanup_before_save(init_function);
579 return save_to_filehandle(file, filename, init_function, prepend_runtime,
580 save_runtime_options,
581 compressed ? compressed : COMPRESSION_LEVEL_NONE);
583 #endif