0.9.2.18: various error &co reporting improvements and build tweaks
[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 boolean
91 save(char *filename, lispobj init_function)
92 {
93     FILE *file;
94     struct thread *th;
95
96     /* Open the output file. We don't actually need the file yet, but
97      * the fopen() might fail for some reason, and we want to detect
98      * that and back out before we do anything irreversible. */
99     unlink(filename);
100     file = fopen(filename, "w");
101     if (!file) {
102         perror(filename);
103         return 1;
104     }
105
106     /* Smash the enclosing state. (Once we do this, there's no good
107      * way to go back, which is a sufficient reason that this ends up
108      * being SAVE-LISP-AND-DIE instead of SAVE-LISP-AND-GO-ON). */
109     printf("[undoing binding stack and other enclosing state... ");
110     fflush(stdout);
111     for_each_thread(th) {       /* XXX really? */
112         unbind_to_here((lispobj *)th->binding_stack_start,th);
113         SetSymbolValue(CURRENT_CATCH_BLOCK, 0,th);
114         SetSymbolValue(CURRENT_UNWIND_PROTECT_BLOCK, 0,th);
115     }
116     printf("done]\n");
117     fflush(stdout);
118     
119     /* (Now we can actually start copying ourselves into the output file.) */
120
121     printf("[saving current Lisp image into %s:\n", filename);
122     fflush(stdout);
123
124     write_lispobj(CORE_MAGIC, file);
125
126     write_lispobj(VERSION_CORE_ENTRY_TYPE_CODE, file);
127     write_lispobj(3, file);
128     write_lispobj(SBCL_CORE_VERSION_INTEGER, file);
129
130     write_lispobj(BUILD_ID_CORE_ENTRY_TYPE_CODE, file);
131     write_lispobj(/* (We're writing the word count of the entry here, and the 2
132           * term is one word for the leading BUILD_ID_CORE_ENTRY_TYPE_CODE
133           * word and one word where we store the count itself.) */
134          2 + strlen(build_id),
135          file);
136     {
137         char *p;
138         for (p = build_id; *p; ++p)
139             write_lispobj(*p, file);
140     }
141
142     write_lispobj(NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE, file);
143     write_lispobj(/* (word count = 3 spaces described by 5 words each, plus the
144           * entry type code, plus this count itself) */
145          (5*3)+2, file);
146     output_space(file,
147                  READ_ONLY_CORE_SPACE_ID,
148                  (lispobj *)READ_ONLY_SPACE_START,
149                  (lispobj *)SymbolValue(READ_ONLY_SPACE_FREE_POINTER,0));
150     output_space(file,
151                  STATIC_CORE_SPACE_ID,
152                  (lispobj *)STATIC_SPACE_START,
153                  (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER,0));
154 #ifdef reg_ALLOC
155     output_space(file,
156                  DYNAMIC_CORE_SPACE_ID,
157                  (lispobj *)current_dynamic_space,
158                  dynamic_space_free_pointer);
159 #else
160 #ifdef LISP_FEATURE_GENCGC
161     /* Flush the current_region, updating the tables. */
162     gc_alloc_update_all_page_tables();
163     update_x86_dynamic_space_free_pointer();
164 #endif
165     output_space(file,
166                  DYNAMIC_CORE_SPACE_ID,
167                  (lispobj *)DYNAMIC_SPACE_START,
168                  (lispobj *)SymbolValue(ALLOCATION_POINTER,0));
169 #endif
170
171     write_lispobj(INITIAL_FUN_CORE_ENTRY_TYPE_CODE, file);
172     write_lispobj(3, file);
173     write_lispobj(init_function, file);
174
175     write_lispobj(END_CORE_ENTRY_TYPE_CODE, file);
176
177     fclose(file);
178     printf("done]\n");
179
180     exit(0);
181 }