0.8.9.8:
[sbcl.git] / src / runtime / save.c
1 /*
2  * This software is part of the SBCL system. See the README file for
3  * more information.
4  *
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.
10  */
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <signal.h>
16 #include <sys/file.h>
17
18 #include "sbcl.h"
19 #include "runtime.h"
20 #include "os.h"
21 #include "core.h"
22 #include "globals.h"
23 #include "save.h"
24 #include "dynbind.h"
25 #include "lispregs.h"
26 #include "validate.h"
27 #include "gc-internal.h"
28 #include "thread.h"
29
30 #include "genesis/static-symbols.h"
31 #include "genesis/symbol.h"
32
33 static long
34 write_bytes(FILE *file, char *addr, long bytes)
35 {
36     long count, here, data;
37
38     bytes = (bytes+os_vm_page_size-1)&~(os_vm_page_size-1);
39
40     fflush(file);
41     here = ftell(file);
42     fseek(file, 0, 2);
43     data = (ftell(file)+os_vm_page_size-1)&~(os_vm_page_size-1);
44     fseek(file, data, 0);
45
46     while (bytes > 0) {
47         count = fwrite(addr, 1, bytes, file);
48         if (count > 0) {
49             bytes -= count;
50             addr += count;
51         }
52         else {
53             perror("error writing to save file");
54             bytes = 0;
55         }
56     }
57     fflush(file);
58     fseek(file, here, 0);
59     return data/os_vm_page_size - 1;
60 }
61
62 static void
63 output_space(FILE *file, int id, lispobj *addr, lispobj *end)
64 {
65     int words, bytes, data;
66     static char *names[] = {NULL, "dynamic", "static", "read-only"};
67
68     putw(id, file);
69     words = end - addr;
70     putw(words, file);
71
72     bytes = words * sizeof(lispobj);
73
74     printf("writing %d bytes from the %s space at 0x%08lx\n",
75            bytes, names[id], (unsigned long)addr);
76
77     data = write_bytes(file, (char *)addr, bytes);
78
79     putw(data, file);
80     putw((long)addr / os_vm_page_size, file);
81     putw((bytes + os_vm_page_size - 1) / os_vm_page_size, file);
82 }
83
84 boolean
85 save(char *filename, lispobj init_function)
86 {
87     FILE *file;
88     struct thread *th;
89
90     /* Open the output file. We don't actually need the file yet, but
91      * the fopen() might fail for some reason, and we want to detect
92      * that and back out before we do anything irreversible. */
93     unlink(filename);
94     file = fopen(filename, "w");
95     if (!file) {
96         perror(filename);
97         return 1;
98     }
99
100     /* Smash the enclosing state. (Once we do this, there's no good
101      * way to go back, which is a sufficient reason that this ends up
102      * being SAVE-LISP-AND-DIE instead of SAVE-LISP-AND-GO-ON). */
103     printf("[undoing binding stack and other enclosing state... ");
104     fflush(stdout);
105     for_each_thread(th) {       /* XXX really? */
106         unbind_to_here((lispobj *)th->binding_stack_start,th);
107         SetSymbolValue(CURRENT_CATCH_BLOCK, 0,th);
108         SetSymbolValue(CURRENT_UNWIND_PROTECT_BLOCK, 0,th);
109     }
110     printf("done]\n");
111     fflush(stdout);
112     
113     /* (Now we can actually start copying ourselves into the output file.) */
114
115     printf("[saving current Lisp image into %s:\n", filename);
116     fflush(stdout);
117
118     putw(CORE_MAGIC, file);
119
120     putw(VERSION_CORE_ENTRY_TYPE_CODE, file);
121     putw(3, file);
122     putw(SBCL_CORE_VERSION_INTEGER, file);
123
124     putw(BUILD_ID_CORE_ENTRY_TYPE_CODE, file);
125     putw(/* (We're writing the word count of the entry here, and the 2
126           * term is one word for the leading BUILD_ID_CORE_ENTRY_TYPE_CODE
127           * word and one word where we store the count itself.) */
128          2 + strlen(build_id),
129          file);
130     {
131         char *p;
132         for (p = build_id; *p; ++p)
133             putw(*p, file);
134     }
135
136     putw(NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE, file);
137     putw(/* (word count = 3 spaces described by 5 words each, plus the
138           * entry type code, plus this count itself) */
139          (5*3)+2, file);
140     output_space(file,
141                  READ_ONLY_CORE_SPACE_ID,
142                  (lispobj *)READ_ONLY_SPACE_START,
143                  (lispobj *)SymbolValue(READ_ONLY_SPACE_FREE_POINTER,0));
144     output_space(file,
145                  STATIC_CORE_SPACE_ID,
146                  (lispobj *)STATIC_SPACE_START,
147                  (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER,0));
148 #ifdef reg_ALLOC
149     output_space(file,
150                  DYNAMIC_CORE_SPACE_ID,
151                  (lispobj *)current_dynamic_space,
152                  dynamic_space_free_pointer);
153 #else
154 #ifdef LISP_FEATURE_GENCGC
155     /* Flush the current_region, updating the tables. */
156     gc_alloc_update_all_page_tables();
157     update_x86_dynamic_space_free_pointer();
158 #endif
159     output_space(file,
160                  DYNAMIC_CORE_SPACE_ID,
161                  (lispobj *)DYNAMIC_SPACE_START,
162                  (lispobj *)SymbolValue(ALLOCATION_POINTER,0));
163 #endif
164
165     putw(INITIAL_FUN_CORE_ENTRY_TYPE_CODE, file);
166     putw(3, file);
167     putw(init_function, file);
168
169     putw(END_CORE_ENTRY_TYPE_CODE, file);
170
171     fclose(file);
172     printf("done]\n");
173
174     exit(0);
175 }