0.9.6.23:
[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 void
34 write_lispobj(lispobj obj, FILE *file)
35 {
36     fwrite(&obj, sizeof(lispobj), 1, file);
37 }
38
39 static long
40 write_bytes(FILE *file, char *addr, long bytes)
41 {
42     long count, here, data;
43
44     bytes = (bytes+os_vm_page_size-1)&~(os_vm_page_size-1);
45
46     fflush(file);
47     here = ftell(file);
48     fseek(file, 0, 2);
49     data = (ftell(file)+os_vm_page_size-1)&~(os_vm_page_size-1);
50     fseek(file, data, 0);
51
52     while (bytes > 0) {
53         count = fwrite(addr, 1, bytes, file);
54         if (count > 0) {
55             bytes -= count;
56             addr += count;
57         }
58         else {
59             perror("error writing to save file");
60             bytes = 0;
61         }
62     }
63     fflush(file);
64     fseek(file, here, 0);
65     return data/os_vm_page_size - 1;
66 }
67
68 static void
69 output_space(FILE *file, int id, lispobj *addr, lispobj *end)
70 {
71     int words, bytes, data;
72     static char *names[] = {NULL, "dynamic", "static", "read-only"};
73
74     write_lispobj(id, file);
75     words = end - addr;
76     write_lispobj(words, file);
77
78     bytes = words * sizeof(lispobj);
79
80     printf("writing %d bytes from the %s space at 0x%08lx\n",
81            bytes, names[id], (unsigned long)addr);
82
83     data = write_bytes(file, (char *)addr, bytes);
84
85     write_lispobj(data, file);
86     write_lispobj((long)addr / os_vm_page_size, file);
87     write_lispobj((bytes + os_vm_page_size - 1) / os_vm_page_size, file);
88 }
89
90 FILE *
91 open_core_for_saving(char *filename)
92 {
93     /* Open the output file. We don't actually need the file yet, but
94      * the fopen() might fail for some reason, and we want to detect
95      * that and back out before we do anything irreversible. */
96     unlink(filename);
97     return fopen(filename, "w");
98 }
99
100 boolean
101 save_to_filehandle(FILE *file, char *filename, lispobj init_function)
102 {
103     struct thread *th;
104
105     /* Smash the enclosing state. (Once we do this, there's no good
106      * way to go back, which is a sufficient reason that this ends up
107      * being SAVE-LISP-AND-DIE instead of SAVE-LISP-AND-GO-ON). */
108     printf("[undoing binding stack and other enclosing state... ");
109     fflush(stdout);
110     for_each_thread(th) {       /* XXX really? */
111         unbind_to_here((lispobj *)th->binding_stack_start,th);
112         SetSymbolValue(CURRENT_CATCH_BLOCK, 0,th);
113         SetSymbolValue(CURRENT_UNWIND_PROTECT_BLOCK, 0,th);
114     }
115     printf("done]\n");
116     fflush(stdout);
117
118     /* (Now we can actually start copying ourselves into the output file.) */
119
120     printf("[saving current Lisp image into %s:\n", filename);
121     fflush(stdout);
122
123     write_lispobj(CORE_MAGIC, file);
124
125     write_lispobj(VERSION_CORE_ENTRY_TYPE_CODE, file);
126     write_lispobj(3, file);
127     write_lispobj(SBCL_CORE_VERSION_INTEGER, file);
128
129     write_lispobj(BUILD_ID_CORE_ENTRY_TYPE_CODE, file);
130     write_lispobj(/* (We're writing the word count of the entry here, and the 2
131           * term is one word for the leading BUILD_ID_CORE_ENTRY_TYPE_CODE
132           * word and one word where we store the count itself.) */
133          2 + strlen((const char *)build_id),
134          file);
135     {
136         unsigned char *p;
137         for (p = build_id; *p; ++p)
138             write_lispobj(*p, file);
139     }
140
141     write_lispobj(NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE, file);
142     write_lispobj(/* (word count = 3 spaces described by 5 words each, plus the
143           * entry type code, plus this count itself) */
144          (5*3)+2, file);
145     output_space(file,
146                  READ_ONLY_CORE_SPACE_ID,
147                  (lispobj *)READ_ONLY_SPACE_START,
148                  (lispobj *)SymbolValue(READ_ONLY_SPACE_FREE_POINTER,0));
149     output_space(file,
150                  STATIC_CORE_SPACE_ID,
151                  (lispobj *)STATIC_SPACE_START,
152                  (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER,0));
153 #ifdef reg_ALLOC
154     output_space(file,
155                  DYNAMIC_CORE_SPACE_ID,
156                  (lispobj *)current_dynamic_space,
157                  dynamic_space_free_pointer);
158 #else
159 #ifdef LISP_FEATURE_GENCGC
160     /* Flush the current_region, updating the tables. */
161     gc_alloc_update_all_page_tables();
162     update_dynamic_space_free_pointer();
163 #endif
164     output_space(file,
165                  DYNAMIC_CORE_SPACE_ID,
166                  (lispobj *)DYNAMIC_SPACE_START,
167                  (lispobj *)SymbolValue(ALLOCATION_POINTER,0));
168 #endif
169
170     write_lispobj(INITIAL_FUN_CORE_ENTRY_TYPE_CODE, file);
171     write_lispobj(3, file);
172     write_lispobj(init_function, file);
173
174 #ifdef LISP_FEATURE_GENCGC
175     {
176         size_t size = (last_free_page*sizeof(long)+os_vm_page_size-1)
177             &~(os_vm_page_size-1);
178         long *data = calloc(size, 1);
179         if (data) {
180             long offset;
181             int i;
182             for (i = 0; i < last_free_page; i++) {
183                 data[i] = page_table[i].first_object_offset;
184             }
185             write_lispobj(PAGE_TABLE_CORE_ENTRY_TYPE_CODE, file);
186             write_lispobj(4, file);
187             write_lispobj(size, file);
188             offset = write_bytes(file, (char *) data, size);
189             write_lispobj(offset, file);
190         }
191     }
192 #endif
193
194     write_lispobj(END_CORE_ENTRY_TYPE_CODE, file);
195
196     fclose(file);
197     printf("done]\n");
198
199     exit(0);
200 }
201
202 boolean
203 save(char *filename, lispobj init_function)
204 {
205     FILE *file = open_core_for_saving(filename);
206
207     if (!file) {
208         perror(filename);
209         return 1;
210     }
211
212     return save_to_filehandle(file, filename, init_function);
213 }