0.6.10.4:
[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 must 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     os_init();
126     gc_init();
127     validate();
128
129     /* Parse our part of the command line (aka "runtime options"),
130      * stripping out those options that we handle. */
131     {
132         int argi = 1;
133         while (argi < argc) {
134             char *arg = argv[argi];
135             if (0 == strcmp(arg, "--noinform")) {
136                 noinform = 1;
137                 ++argi;
138             } else if (0 == strcmp(arg, "--core")) {
139                 if (core) {
140                     lose("more than one core file specified");
141                 } else {
142                     ++argi;
143                     core = copied_string(argv[argi]);
144                     if (argi >= argc) {
145                         lose("missing filename for --core argument");
146                     }
147                     ++argi;
148                 }
149             } else if (0 == strcmp(arg, "--end-runtime-options")) {
150                 end_runtime_options = 1;
151                 ++argi;
152                 break;
153             } else {
154                 /* This option was unrecognized as a runtime option,
155                  * so it must be a toplevel option or a user option,
156                  * so we must be past the end of the runtime option
157                  * section. */
158                 break;
159             }
160         }
161         /* This is where we strip out those options that we handle. We
162          * also take this opportunity to make sure that we don't find
163          * an out-of-place "--end-runtime-options" option. */
164         {
165             char *argi0 = argv[argi];
166             int argj = 1;
167             while (argi < argc) {
168                 char *arg = argv[argi++];
169                 /* If we encounter --end-runtime-options for the first
170                  * time after the point where we had to give up on
171                  * runtime options, then the point where we had to
172                  * give up on runtime options must've been a user
173                  * error. */
174                 if (!end_runtime_options &&
175                     0 == strcmp(arg, "--end-runtime-options")) {
176                     lose("bad runtime option \"%s\"", argi0);
177                 }
178                 argv[argj++] = arg;
179             }
180             argv[argj] = 0;
181             argc = argj;
182         }
183     }
184
185     /* If no core file was specified, look for one. */
186     if (!core) {
187         char *sbcl_home = getenv("SBCL_HOME");
188         if (sbcl_home) {
189             char *lookhere;
190             lookhere = (char *) calloc(strlen("/sbcl.core") + strlen(sbcl_home) + 1,
191                                         sizeof(char));
192             sprintf(lookhere, "%s/sbcl.core", sbcl_home);
193             core = copied_existing_filename_or_null(lookhere);
194             free(lookhere);
195         } else {
196             core = copied_existing_filename_or_null("/usr/lib/sbcl.core");
197             if (!core) {
198                 core = copied_existing_filename_or_null("/usr/local/lib/sbcl.core");
199             }
200         }
201         if (!core) {
202             lose("can't find core file");
203         }
204     }
205
206     if (!noinform) {
207         printf(
208 "This is SBCL " SBCL_VERSION_STRING ", an implementation of ANSI Common Lisp.
209
210 SBCL is derived from the CMU CL system created at Carnegie Mellon University.
211 Besides material created at Carnegie Mellon University, and material
212 contributed by volunteers since its release into the public domain, CMU CL
213 contained, and SBCL contains, material copyrighted by
214   Massachusetts Institute of Technology, 1986;
215   Symbolics, Inc., 1989, 1990, 1991, 1992; and
216   Xerox Corporation, 1985, 1986, 1987, 1988, 1989, 1990.
217 More information about the origin of SBCL is available in the CREDITS file
218 in the distribution.
219
220 SBCL is a free software system, provided as is, with absolutely no warranty.
221 It is mostly public domain software, but also includes some software from
222 MIT, Symbolics, and Xerox, used under BSD-style licenses which allow copying
223 only under certain conditions. More information about copying SBCL is
224 available in the COPYING file in the distribution.
225
226 More information on SBCL is available at <http://sbcl.sourceforge.net/>.
227 ");
228         fflush(stdout);
229     }
230
231 #ifdef MACH
232     mach_init();
233 #endif
234 #if defined(SVR4) || defined(__linux__)
235     tzset();
236 #endif
237
238     define_var("nil", NIL, 1);
239     define_var("t", T, 1);
240
241     set_lossage_handler(ldb_monitor);
242
243 #if 0
244     os_init();
245     gc_init();
246     validate();
247 #endif
248     globals_init();
249
250     initial_function = load_core_file(core);
251     if (initial_function == NIL) {
252         lose("couldn't find initial function");
253     }
254     free(core);
255
256 #if defined GENCGC
257     gencgc_pickup_dynamic();
258 #else
259 #if defined WANT_CGC && defined X86_CGC_ACTIVE_P
260     {
261         extern int use_cgc_p;
262         lispobj x = SymbolValue(X86_CGC_ACTIVE_P);
263         if (x != type_UnboundMarker && x != NIL) {
264             /* Enable allocator. */
265             use_cgc_p = 1;              
266         }
267     }
268 #endif
269 #endif
270
271 #ifdef BINDING_STACK_POINTER
272     SetSymbolValue(BINDING_STACK_POINTER, BINDING_STACK_START);
273 #endif
274 #if defined INTERNAL_GC_TRIGGER && !defined __i386__
275     SetSymbolValue(INTERNAL_GC_TRIGGER, make_fixnum(-1));
276 #endif
277
278     interrupt_init();
279
280     arch_install_interrupt_handlers();
281     os_install_interrupt_handlers();
282
283 #ifdef PSEUDO_ATOMIC_ATOMIC
284     /* Turn on pseudo atomic for when we call into Lisp. */
285     SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, make_fixnum(1));
286     SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(0));
287 #endif
288
289     /* Convert remaining argv values to something that Lisp can grok. */
290     SetSymbolValue(POSIX_ARGV, alloc_string_list(argv));
291
292     /* Install a handler to pick off SIGINT until the Lisp system gets
293      * far enough along to install its own handler. */
294     sigint_init();
295
296     funcall0(initial_function);
297
298     /* initial_function() is not supposed to return. */
299     lose("Lisp initial_function gave up control.");
300     return 0; /* dummy value: return something */
301 }
302