Reduce pinned object table size, part 1 of 2.
[sbcl.git] / src / runtime / save.c
blob07e25600c971e6c7e2bc134a6fbe82143a56da5d
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"
39 #include "genesis/static-symbols.h"
40 #include "genesis/symbol.h"
42 #ifdef LISP_FEATURE_SB_CORE_COMPRESSION
43 # include <zlib.h>
44 #endif
46 /* write_runtime_options uses a simple serialization scheme that
47 * consists of one word of magic, one word indicating whether options
48 * are actually saved, and one word per struct field. */
49 static void
50 write_runtime_options(FILE *file, struct runtime_options *options)
52 size_t optarray[RUNTIME_OPTIONS_WORDS];
54 memset(&optarray, 0, sizeof(optarray));
55 optarray[0] = RUNTIME_OPTIONS_MAGIC;
57 if (options != NULL) {
58 /* optarray[1] is a flag indicating that options are present */
59 optarray[1] = 1;
60 optarray[2] = options->dynamic_space_size;
61 optarray[3] = options->thread_control_stack_size;
64 if (RUNTIME_OPTIONS_WORDS !=
65 fwrite(optarray, sizeof(size_t), RUNTIME_OPTIONS_WORDS, file)) {
66 perror("Error writing runtime options to file");
70 static void
71 write_lispobj(lispobj obj, FILE *file)
73 if (1 != fwrite(&obj, sizeof(lispobj), 1, file)) {
74 perror("Error writing to file");
78 static void
79 write_bytes_to_file(FILE * file, char *addr, long bytes, int compression)
81 if (compression == COMPRESSION_LEVEL_NONE) {
82 while (bytes > 0) {
83 sword_t count = fwrite(addr, 1, bytes, file);
84 if (count > 0) {
85 bytes -= count;
86 addr += count;
88 else {
89 perror("error writing to core file");
90 lose("core file is incomplete or corrupt\n");
93 #ifdef LISP_FEATURE_SB_CORE_COMPRESSION
94 } else if ((compression >= -1) && (compression <= 9)) {
95 # define ZLIB_BUFFER_SIZE (1u<<16)
96 z_stream stream;
97 unsigned char buf[ZLIB_BUFFER_SIZE];
98 unsigned char * written, * end;
99 long total_written = 0;
100 int ret;
101 stream.zalloc = NULL;
102 stream.zfree = NULL;
103 stream.opaque = NULL;
104 stream.avail_in = bytes;
105 stream.next_in = (void*)addr;
106 ret = deflateInit(&stream, compression);
107 if (ret != Z_OK)
108 lose("deflateInit: %i\n", ret);
109 do {
110 stream.avail_out = sizeof(buf);
111 stream.next_out = buf;
112 ret = deflate(&stream, Z_FINISH);
113 if (ret < 0) lose("zlib deflate error: %i... exiting\n", ret);
114 written = buf;
115 end = buf+sizeof(buf)-stream.avail_out;
116 total_written += end - written;
117 while (written < end) {
118 long count = fwrite(written, 1, end-written, file);
119 if (count > 0) {
120 written += count;
121 } else {
122 perror("error writing to core file");
123 lose("core file is incomplete or corrupt\n");
126 } while (stream.avail_out == 0);
127 deflateEnd(&stream);
128 printf("compressed %lu bytes into %lu at level %i\n",
129 bytes, total_written, compression);
130 # undef ZLIB_BUFFER_SIZE
131 #endif
132 } else {
133 #ifdef LISP_FEATURE_SB_CORE_COMPRESSION
134 lose("Unknown core compression level %i, exiting\n", compression);
135 #else
136 lose("zlib-compressed core support not built in this runtime\n");
137 #endif
140 if (fflush(file) != 0) {
141 perror("error writing to core file");
142 lose("core file is incomplete or corrupt\n");
147 static long
148 write_and_compress_bytes(FILE *file, char *addr, long bytes, os_vm_offset_t file_offset,
149 int compression)
151 long here, data;
153 bytes = (bytes+os_vm_page_size-1)&~(os_vm_page_size-1);
155 #ifdef LISP_FEATURE_WIN32
156 long count;
157 /* touch every single page in the space to force it to be mapped. */
158 for (count = 0; count < bytes; count += 0x1000) {
159 volatile int temp = addr[count];
161 #endif
163 fflush(file);
164 here = ftell(file);
165 fseek(file, 0, SEEK_END);
166 data = (ftell(file)+os_vm_page_size-1)&~(os_vm_page_size-1);
167 fseek(file, data, SEEK_SET);
168 write_bytes_to_file(file, addr, bytes, compression);
169 fseek(file, here, SEEK_SET);
170 return ((data - file_offset) / os_vm_page_size) - 1;
173 static long __attribute__((__unused__))
174 write_bytes(FILE *file, char *addr, long bytes, os_vm_offset_t file_offset)
176 return write_and_compress_bytes(file, addr, bytes, file_offset,
177 COMPRESSION_LEVEL_NONE);
180 extern struct lisp_startup_options lisp_startup_options;
182 static void
183 output_space(FILE *file, int id, lispobj *addr, lispobj *end,
184 os_vm_offset_t file_offset,
185 int core_compression_level)
187 size_t words, bytes, data, compressed_flag;
188 static char *names[] = {NULL, "dynamic", "static", "read-only",
189 "immobile", "immobile"};
191 compressed_flag
192 = ((core_compression_level != COMPRESSION_LEVEL_NONE)
193 ? DEFLATED_CORE_SPACE_ID_FLAG : 0);
195 write_lispobj(id | compressed_flag, file);
196 words = end - addr;
197 write_lispobj(words, file);
199 bytes = words * sizeof(lispobj);
201 if (!lisp_startup_options.noinform)
202 printf("writing %lu bytes from the %s space at %p\n",
203 (long unsigned)bytes, names[id], addr);
205 data = write_and_compress_bytes(file, (char *)addr, bytes, file_offset,
206 core_compression_level);
208 write_lispobj(data, file);
209 write_lispobj((uword_t)addr / os_vm_page_size, file);
210 write_lispobj((bytes + os_vm_page_size - 1) / os_vm_page_size, file);
213 FILE *
214 open_core_for_saving(char *filename)
216 /* Open the output file. We don't actually need the file yet, but
217 * the fopen() might fail for some reason, and we want to detect
218 * that and back out before we do anything irreversible. */
219 unlink(filename);
220 return fopen(filename, "wb");
223 #ifdef LISP_FEATURE_IMMOBILE_SPACE
224 extern void prepare_immobile_space_for_save();
225 # define N_SPACES_TO_SAVE 5
226 # ifdef LISP_FEATURE_IMMOBILE_CODE
227 lispobj code_component_order;
228 extern void defrag_immobile_space(lispobj);
229 # endif
230 #else
231 # define N_SPACES_TO_SAVE 3
232 #endif
233 boolean
234 save_to_filehandle(FILE *file, char *filename, lispobj init_function,
235 boolean make_executable,
236 boolean save_runtime_options,
237 int core_compression_level)
239 struct thread *th;
240 os_vm_offset_t core_start_pos;
241 boolean verbose = !lisp_startup_options.noinform;
243 #ifdef LISP_FEATURE_X86_64
244 untune_asm_routines_for_microarch();
245 #endif
247 /* Smash the enclosing state. (Once we do this, there's no good
248 * way to go back, which is a sufficient reason that this ends up
249 * being SAVE-LISP-AND-DIE instead of SAVE-LISP-AND-GO-ON). */
250 if (verbose) {
251 printf("[undoing binding stack and other enclosing state... ");
252 fflush(stdout);
254 for_each_thread(th) { /* XXX really? */
255 unbind_to_here((lispobj *)th->binding_stack_start,th);
256 SetSymbolValue(CURRENT_CATCH_BLOCK, 0,th);
257 SetSymbolValue(CURRENT_UNWIND_PROTECT_BLOCK, 0,th);
259 if (verbose) printf("done]\n");
260 #ifdef LISP_FEATURE_IMMOBILE_CODE
261 // It's better to wait to defrag until after the binding stack is undone,
262 // because we explicitly don't fixup code refs from stacks.
263 // i.e. if there *were* something on the binding stack that cared that code
264 // moved, it would be wrong. This way we can be sure we don't care.
265 if (code_component_order) {
266 // Assert that defrag will not move the init_function
267 gc_assert(!immobile_space_p(init_function));
268 if (verbose) {
269 printf("[defragmenting immobile space... ");
270 fflush(stdout);
272 defrag_immobile_space(code_component_order);
273 if (verbose) printf("done]\n");
275 #endif
277 /* (Now we can actually start copying ourselves into the output file.) */
279 if (verbose) {
280 printf("[saving current Lisp image into %s:\n", filename);
281 fflush(stdout);
284 core_start_pos = ftell(file);
285 write_lispobj(CORE_MAGIC, file);
287 write_lispobj(BUILD_ID_CORE_ENTRY_TYPE_CODE, file);
288 write_lispobj(/* (We're writing the word count of the entry here, and the 2
289 * term is one word for the leading BUILD_ID_CORE_ENTRY_TYPE_CODE
290 * word and one word where we store the count itself.) */
291 2 + strlen((const char *)build_id),
292 file);
294 unsigned char *p;
295 for (p = (unsigned char *)build_id; *p; ++p)
296 write_lispobj(*p, file);
299 write_lispobj(NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE, file);
300 write_lispobj(/* (word count = N spaces described by 5 words each, plus the
301 * entry type code, plus this count itself) */
302 (5*N_SPACES_TO_SAVE)+2, file);
303 output_space(file,
304 READ_ONLY_CORE_SPACE_ID,
305 (lispobj *)READ_ONLY_SPACE_START,
306 (lispobj *)SymbolValue(READ_ONLY_SPACE_FREE_POINTER,0),
307 core_start_pos,
308 core_compression_level);
309 output_space(file,
310 STATIC_CORE_SPACE_ID,
311 (lispobj *)STATIC_SPACE_START,
312 (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER,0),
313 core_start_pos,
314 core_compression_level);
315 #ifdef LISP_FEATURE_GENCGC
316 /* Flush the current_region, updating the tables. */
317 gc_alloc_update_all_page_tables(1);
318 update_dynamic_space_free_pointer();
319 #endif
320 #ifdef LISP_FEATURE_IMMOBILE_SPACE
321 prepare_immobile_space_for_save();
322 output_space(file,
323 IMMOBILE_FIXEDOBJ_CORE_SPACE_ID,
324 (lispobj *)IMMOBILE_SPACE_START,
325 (lispobj *)SymbolValue(IMMOBILE_FIXEDOBJ_FREE_POINTER,0),
326 core_start_pos,
327 core_compression_level);
328 output_space(file,
329 IMMOBILE_VARYOBJ_CORE_SPACE_ID,
330 (lispobj *)IMMOBILE_VARYOBJ_SUBSPACE_START,
331 (lispobj *)SymbolValue(IMMOBILE_SPACE_FREE_POINTER,0),
332 core_start_pos,
333 core_compression_level);
334 #endif
335 #ifdef reg_ALLOC
336 #ifdef LISP_FEATURE_GENCGC
337 output_space(file,
338 DYNAMIC_CORE_SPACE_ID,
339 (lispobj *)DYNAMIC_SPACE_START,
340 dynamic_space_free_pointer,
341 core_start_pos,
342 core_compression_level);
343 #else
344 output_space(file,
345 DYNAMIC_CORE_SPACE_ID,
346 (lispobj *)current_dynamic_space,
347 dynamic_space_free_pointer,
348 core_start_pos,
349 core_compression_level);
350 #endif
351 #else
352 output_space(file,
353 DYNAMIC_CORE_SPACE_ID,
354 (lispobj *)DYNAMIC_SPACE_START,
355 (lispobj *)SymbolValue(ALLOCATION_POINTER,0),
356 core_start_pos,
357 core_compression_level);
358 #endif
360 write_lispobj(INITIAL_FUN_CORE_ENTRY_TYPE_CODE, file);
361 write_lispobj(3, file);
362 write_lispobj(init_function, file);
364 #ifdef LISP_FEATURE_GENCGC
366 size_t size = (last_free_page*sizeof(sword_t)+os_vm_page_size-1)
367 &~(os_vm_page_size-1);
368 uword_t *data = calloc(size, 1);
369 if (data) {
370 uword_t word;
371 sword_t offset;
372 page_index_t i;
373 for (i = 0; i < last_free_page; i++) {
374 /* Thanks to alignment requirements, the two low bits
375 * are always zero, so we can use them to store the
376 * allocation type -- region is always closed, so only
377 * the two low bits of allocation flags matter. */
378 word = page_scan_start_offset(i);
379 gc_assert((word & 0x03) == 0);
380 data[i] = word | (0x03 & page_table[i].allocated);
382 write_lispobj(PAGE_TABLE_CORE_ENTRY_TYPE_CODE, file);
383 write_lispobj(4, file);
384 write_lispobj(size, file);
385 offset = write_bytes(file, (char *)data, size, core_start_pos);
386 write_lispobj(offset, file);
389 #endif
391 write_lispobj(END_CORE_ENTRY_TYPE_CODE, file);
393 /* Write a trailing header, ignored when parsing the core normally.
394 * This is used to locate the start of the core when the runtime is
395 * prepended to it. */
396 fseek(file, 0, SEEK_END);
398 /* If NULL runtime options are passed to write_runtime_options,
399 * command-line processing is performed as normal in the SBCL
400 * executable. Otherwise, the saved runtime options are used and
401 * all command-line arguments are available to Lisp in
402 * SB-EXT:*POSIX-ARGV*. */
403 write_runtime_options(file,
404 (save_runtime_options ? runtime_options : NULL));
406 if (1 != fwrite(&core_start_pos, sizeof(os_vm_offset_t), 1, file)) {
407 perror("Error writing core starting position to file");
408 fclose(file);
409 } else {
410 write_lispobj(CORE_MAGIC, file);
411 fclose(file);
414 #ifndef LISP_FEATURE_WIN32
415 if (make_executable)
416 chmod (filename, 0755);
417 #endif
419 if (verbose) printf("done]\n");
420 exit(0);
422 #undef N_SPACES_TO_SAVE
424 /* Check if the build_id for the current runtime is present in a
425 * buffer. */
427 check_runtime_build_id(void *buf, size_t size)
429 size_t idlen;
430 char *pos;
432 idlen = strlen((const char*)build_id) - 1;
433 while ((pos = memchr(buf, build_id[0], size)) != NULL) {
434 size -= (pos + 1) - (char *)buf;
435 buf = (pos + 1);
436 if (idlen <= size && memcmp(buf, build_id + 1, idlen) == 0)
437 return 1;
440 return 0;
443 /* Slurp the executable portion of the runtime into a malloced buffer
444 * and return it. Places the size in bytes of the runtime into
445 * 'size_out'. Returns NULL if the runtime cannot be loaded from
446 * 'runtime_path'. */
447 void *
448 load_runtime(char *runtime_path, size_t *size_out)
450 void *buf = NULL;
451 FILE *input = NULL;
452 size_t size, count;
453 os_vm_offset_t core_offset;
455 core_offset = search_for_embedded_core (runtime_path);
456 if ((input = fopen(runtime_path, "rb")) == NULL) {
457 fprintf(stderr, "Unable to open runtime: %s\n", runtime_path);
458 goto lose;
461 fseek(input, 0, SEEK_END);
462 size = (size_t) ftell(input);
463 fseek(input, 0, SEEK_SET);
465 if (core_offset != -1 && size > (size_t) core_offset)
466 size = core_offset;
468 buf = successful_malloc(size);
469 if ((count = fread(buf, 1, size, input)) != size) {
470 fprintf(stderr, "Premature EOF while reading runtime.\n");
471 goto lose;
474 if (!check_runtime_build_id(buf, size)) {
475 fprintf(stderr, "Failed to locate current build_id in runtime: %s\n",
476 runtime_path);
477 goto lose;
480 fclose(input);
481 *size_out = size;
482 return buf;
484 lose:
485 if (input != NULL)
486 fclose(input);
487 if (buf != NULL)
488 free(buf);
489 return NULL;
492 boolean
493 save_runtime_to_filehandle(FILE *output, void *runtime, size_t runtime_size,
494 int application_type)
496 size_t padding;
497 void *padbytes;
499 #ifdef LISP_FEATURE_WIN32
501 PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)runtime;
502 PIMAGE_NT_HEADERS nt_header = (PIMAGE_NT_HEADERS)((char *)dos_header +
503 dos_header->e_lfanew);
505 int sub_system;
506 switch (application_type) {
507 case 0:
508 sub_system = IMAGE_SUBSYSTEM_WINDOWS_CUI;
509 break;
510 case 1:
511 sub_system = IMAGE_SUBSYSTEM_WINDOWS_GUI;
512 break;
513 default:
514 fprintf(stderr, "Invalid application type %d\n", application_type);
515 return 0;
518 nt_header->OptionalHeader.Subsystem = sub_system;
520 #endif
522 if (runtime_size != fwrite(runtime, 1, runtime_size, output)) {
523 perror("Error saving runtime");
524 return 0;
527 padding = (os_vm_page_size - (runtime_size % os_vm_page_size)) & ~os_vm_page_size;
528 if (padding > 0) {
529 padbytes = successful_malloc(padding);
530 memset(padbytes, 0, padding);
531 if (padding != fwrite(padbytes, 1, padding, output)) {
532 perror("Error saving runtime");
533 free(padbytes);
534 return 0;
536 free(padbytes);
539 return 1;
542 FILE *
543 prepare_to_save(char *filename, boolean prepend_runtime, void **runtime_bytes,
544 size_t *runtime_size)
546 FILE *file;
547 char *runtime_path;
549 if (prepend_runtime) {
550 runtime_path = os_get_runtime_executable_path(0);
552 if (runtime_path == NULL && saved_runtime_path == NULL) {
553 fprintf(stderr, "Unable to get default runtime path.\n");
554 return NULL;
557 if (runtime_path == NULL)
558 *runtime_bytes = load_runtime(saved_runtime_path, runtime_size);
559 else {
560 *runtime_bytes = load_runtime(runtime_path, runtime_size);
561 free(runtime_path);
564 if (*runtime_bytes == NULL)
565 return 0;
568 file = open_core_for_saving(filename);
569 if (file == NULL) {
570 free(*runtime_bytes);
571 perror(filename);
572 return NULL;
575 return file;
578 boolean
579 save(char *filename, lispobj init_function, boolean prepend_runtime,
580 boolean save_runtime_options, boolean compressed, int compression_level,
581 int application_type)
583 FILE *file;
584 void *runtime_bytes = NULL;
585 size_t runtime_size;
587 file = prepare_to_save(filename, prepend_runtime, &runtime_bytes, &runtime_size);
588 if (file == NULL)
589 return 1;
591 if (prepend_runtime)
592 save_runtime_to_filehandle(file, runtime_bytes, runtime_size, application_type);
594 return save_to_filehandle(file, filename, init_function, prepend_runtime,
595 save_runtime_options,
596 compressed ? compressed : COMPRESSION_LEVEL_NONE);