0.7.6.12:
[sbcl.git] / src / runtime / runtime.c
1 /*
2  * main() entry point for a stand-alone SBCL image
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
9  * This software is derived from the CMU CL system, which was
10  * written at Carnegie Mellon University and released into the
11  * public domain. The software is in the public domain and is
12  * provided with absolutely no warranty. See the COPYING and CREDITS
13  * files for more information.
14  */
15
16 #include <stdio.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <sys/file.h>
22 #include <sys/param.h>
23 #include <sys/stat.h>
24
25 #if defined(SVR4) || defined(__linux__)
26 #include <time.h>
27 #endif
28
29 #include "signal.h"
30
31 #include "runtime.h"
32 #include "sbcl.h"
33 #include "alloc.h"
34 #include "vars.h"
35 #include "globals.h"
36 #include "os.h"
37 #include "interrupt.h"
38 #include "arch.h"
39 #include "gc.h"
40 #include "interr.h"
41 #include "monitor.h"
42 #include "validate.h"
43 #include "core.h"
44 #include "save.h"
45 #include "lispregs.h"
46
47 #ifdef irix
48 #include <string.h>
49 #include "interr.h"
50 #endif
51 \f
52 /* SIGINT handler that invokes the monitor (for when Lisp isn't up to it) */
53 static void
54 sigint_handler(int signal, siginfo_t *info, void *void_context)
55 {
56     lose("\nSIGINT hit at 0x%08lX\n", 
57          (unsigned long) *os_context_pc_addr(void_context));
58 }
59
60 /* (This is not static, because we want to be able to call it from
61  * Lisp land.) */
62 void
63 sigint_init(void)
64 {
65     SHOW("entering sigint_init()");
66     install_handler(SIGINT, sigint_handler);
67     SHOW("leaving sigint_init()");
68 }
69 \f
70 /*
71  * helper functions for dealing with command line args
72  */
73
74 void *
75 successful_malloc(size_t size)
76 {
77     void* result = malloc(size);
78     if (0 == result) {
79         lose("malloc failure");
80     } else {
81         return result;
82     }
83     return (void *) NULL; /* dummy value: return something ... */
84 }
85
86 char *
87 copied_string(char *string)
88 {
89     return strcpy(successful_malloc(1+strlen(string)), string);
90 }
91
92 char *
93 copied_existing_filename_or_null(char *filename)
94 {
95     struct stat filename_stat;
96     if (stat(filename, &filename_stat)) { /* if failure */
97         return 0;
98     } else {
99         return copied_string(filename);
100     }
101 }
102
103 /* Convert a null-terminated array of null-terminated strings (e.g.
104  * argv or envp) into a Lisp list of Lisp strings. */
105 static lispobj
106 alloc_string_list(char *array_ptr[])
107 {
108     if (*array_ptr) {
109         return alloc_cons(alloc_string(*array_ptr),
110                           alloc_string_list(1 + array_ptr));
111     } else {
112         return NIL;
113     }
114 }
115 \f
116 int
117 main(int argc, char *argv[], char *envp[])
118 {
119     /* the name of the core file we're to execute. Note that this is
120      * a malloc'ed string which should be freed eventually. */
121     char *core = 0;
122
123     /* other command line options */
124     boolean noinform = 0;
125     boolean end_runtime_options = 0;
126
127     lispobj initial_function;
128
129     /* KLUDGE: os_vm_page_size is set by os_init(), and on some
130      * systems (e.g. Alpha) arch_init() needs need os_vm_page_size, so
131      * it must follow os_init(). -- WHN 2000-01-26 */
132     os_init();
133     arch_init();
134     gc_init();
135     validate();
136
137     /* Parse our part of the command line (aka "runtime options"),
138      * stripping out those options that we handle. */
139     {
140         int argi = 1;
141         while (argi < argc) {
142             char *arg = argv[argi];
143             if (0 == strcmp(arg, "--noinform")) {
144                 noinform = 1;
145                 ++argi;
146             } else if (0 == strcmp(arg, "--core")) {
147                 if (core) {
148                     lose("more than one core file specified");
149                 } else {
150                     ++argi;
151                     core = copied_string(argv[argi]);
152                     if (argi >= argc) {
153                         lose("missing filename for --core argument");
154                     }
155                     ++argi;
156                 }
157             } else if (0 == strcmp(arg, "--end-runtime-options")) {
158                 end_runtime_options = 1;
159                 ++argi;
160                 break;
161             } else {
162                 /* This option was unrecognized as a runtime option,
163                  * so it must be a toplevel option or a user option,
164                  * so we must be past the end of the runtime option
165                  * section. */
166                 break;
167             }
168         }
169         /* This is where we strip out those options that we handle. We
170          * also take this opportunity to make sure that we don't find
171          * an out-of-place "--end-runtime-options" option. */
172         {
173             char *argi0 = argv[argi];
174             int argj = 1;
175             while (argi < argc) {
176                 char *arg = argv[argi++];
177                 /* If we encounter --end-runtime-options for the first
178                  * time after the point where we had to give up on
179                  * runtime options, then the point where we had to
180                  * give up on runtime options must've been a user
181                  * error. */
182                 if (!end_runtime_options &&
183                     0 == strcmp(arg, "--end-runtime-options")) {
184                     lose("bad runtime option \"%s\"", argi0);
185                 }
186                 argv[argj++] = arg;
187             }
188             argv[argj] = 0;
189             argc = argj;
190         }
191     }
192
193     /* If no core file was specified, look for one. */
194     if (!core) {
195         char *sbcl_home = getenv("SBCL_HOME");
196         if (sbcl_home) {
197             char *lookhere;
198             char *stem = "/sbcl.core";
199             lookhere = (char *) calloc(strlen(sbcl_home) +
200                                        strlen(stem) +
201                                        1,
202                                        sizeof(char));
203             sprintf(lookhere, "%s%s", sbcl_home, stem);
204             core = copied_existing_filename_or_null(lookhere);
205             free(lookhere);
206         } else {
207             core = copied_existing_filename_or_null("/usr/lib/sbcl.core");
208             if (!core) {
209                 core =
210                     copied_existing_filename_or_null("/usr/local/lib/sbcl.core");
211             }
212         }
213         if (!core) {
214             lose("can't find core file");
215         }
216     }
217
218     if (!noinform) {
219         printf(
220 "This is SBCL %s, an implementation of ANSI Common Lisp.\n\
221 \n\
222 SBCL is derived from the CMU CL system created at Carnegie Mellon University.\n\
223 Besides software and documentation originally created at Carnegie Mellon\n\
224 University, SBCL contains some software originally from the Massachusetts\n\
225 Institute of Technology, Symbolics Incorporated, and Xerox Corporation, and\n\
226 material contributed by volunteers since the release of CMU CL into the\n\
227 public domain. See the CREDITS file in the distribution for more information.\n\
228 \n\
229 SBCL is a free software system, provided as is, with absolutely no warranty.\n\
230 It is mostly in the public domain, but also includes some software copyrighted\n\
231   Massachusetts Institute of Technology, 1986;\n\
232   Symbolics, Inc., 1989, 1990, 1991, 1992; and\n\
233   Xerox Corporation, 1985, 1986, 1987, 1988, 1989, 1990\n\
234 used under BSD-style licenses allowing copying only under certain conditions.\n\
235 See the COPYING file in the distribution for more information.\n\
236 \n\
237 More information about SBCL is available at <http://sbcl.sourceforge.net/>.\n\
238 ", SBCL_VERSION_STRING);
239         fflush(stdout);
240     }
241
242 #ifdef MACH
243     mach_init();
244 #endif
245 #if defined(SVR4) || defined(__linux__)
246     tzset();
247 #endif
248
249     define_var("nil", NIL, 1);
250     define_var("t", T, 1);
251
252     set_lossage_handler(monitor_or_something);
253
254     globals_init();
255
256     initial_function = load_core_file(core);
257     if (initial_function == NIL) {
258         lose("couldn't find initial function");
259     }
260     SHOW("freeing core");
261     free(core);
262
263     gc_initialize_pointers();
264
265 #ifdef BINDING_STACK_POINTER
266     SetSymbolValue(BINDING_STACK_POINTER, BINDING_STACK_START);
267 #endif
268
269     interrupt_init();
270
271     arch_install_interrupt_handlers();
272     os_install_interrupt_handlers();
273
274 #ifdef PSEUDO_ATOMIC_ATOMIC
275     /* Turn on pseudo atomic for when we call into Lisp. */
276     SHOW("turning on pseudo atomic");
277     SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, make_fixnum(1));
278     SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(0));
279 #endif
280
281     /* Convert remaining argv values to something that Lisp can grok. */
282     SHOW("setting POSIX-ARGV symbol value");
283     SetSymbolValue(POSIX_ARGV, alloc_string_list(argv));
284
285     /* Install a handler to pick off SIGINT until the Lisp system gets
286      * far enough along to install its own handler. */
287     sigint_init();
288
289     FSHOW((stderr, "/funcalling initial_function=0x%lx\n", initial_function));
290     funcall0(initial_function);
291
292     /* initial_function() is not supposed to return. */
293     lose("Lisp initial_function gave up control.");
294     return 0; /* dummy value: return something */
295 }
296