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