2 * main() entry point for a stand-alone SBCL image
6 * This software is part of the SBCL system. See the README file for
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.
21 #include <sys/types.h>
26 #include <sys/param.h>
29 #ifdef LISP_FEATURE_SB_THREAD
30 #include <sys/ptrace.h>
35 #if defined(SVR4) || defined(__linux__)
46 #include "interrupt.h"
57 #include "genesis/static-symbols.h"
58 #include "genesis/symbol.h"
67 #define SBCL_HOME "/usr/local/lib/sbcl/"
71 /* SIGINT handler that invokes the monitor (for when Lisp isn't up to it) */
73 sigint_handler(int signal, siginfo_t *info, void *void_context)
75 lose("\nSIGINT hit at 0x%08lX\n",
76 (unsigned long) *os_context_pc_addr(void_context));
79 /* (This is not static, because we want to be able to call it from
84 SHOW("entering sigint_init()");
85 install_handler(SIGINT, sigint_handler);
86 SHOW("leaving sigint_init()");
90 * helper functions for dealing with command line args
94 successful_malloc(size_t size)
96 void* result = malloc(size);
98 lose("malloc failure");
102 return (void *) NULL; /* dummy value: return something ... */
106 copied_string(char *string)
108 return strcpy(successful_malloc(1+strlen(string)), string);
112 copied_existing_filename_or_null(char *filename)
114 struct stat filename_stat;
115 if (stat(filename, &filename_stat)) { /* if failure */
118 return copied_string(filename);
122 /* Convert a null-terminated array of null-terminated strings (e.g.
123 * argv or envp) into a Lisp list of Lisp base-strings. */
125 alloc_base_string_list(char *array_ptr[])
128 return alloc_cons(alloc_base_string(*array_ptr),
129 alloc_base_string_list(1 + array_ptr));
135 /* miscellaneous chattiness */
141 "SBCL is a Common Lisp programming environment. Ordinarily you shouldn't\n\
142 need command line options when you invoke it interactively: you can just\n\
143 start it and work with the customary Lisp READ-EVAL-PRINT loop.\n\
145 One option idiom which is sometimes useful interactively (e.g. when\n\
146 exercising a test case for a bug report) is\n\
147 sbcl --sysinit /dev/null --userinit /dev/null\n\
148 to keep SBCL from reading any initialization files at startup. And some\n\
149 people like to suppress the default startup message:\n\
152 Other options can be useful when you're running SBCL noninteractively,\n\
153 e.g. from a script, or if you have a strange system configuration, so\n\
154 that SBCL can't by default find one of the files it needs. For\n\
155 information on such options, see the sbcl(1) man page.\n\
157 More information on SBCL can be found on its man page, or at\n\
158 <http://sbcl.sf.net/>.\n");
164 printf("SBCL %s\n", SBCL_VERSION_STRING);
171 "This is SBCL %s, an implementation of ANSI Common Lisp.\n\
173 SBCL is derived from the CMU CL system created at Carnegie Mellon University.\n\
174 Besides software and documentation originally created at Carnegie Mellon\n\
175 University, SBCL contains some software originally from the Massachusetts\n\
176 Institute of Technology, Symbolics Incorporated, and Xerox Corporation, and\n\
177 material contributed by volunteers since the release of CMU CL into the\n\
178 public domain. See the CREDITS file in the distribution for more information.\n\
180 SBCL is a free software system, provided as is, with absolutely no warranty.\n\
181 It is mostly in the public domain, but also includes some software copyrighted\n\
182 Massachusetts Institute of Technology, 1986;\n\
183 Symbolics, Inc., 1989, 1990, 1991, 1992; and\n\
184 Xerox Corporation, 1985, 1986, 1987, 1988, 1989, 1990\n\
185 used under BSD-style licenses allowing copying only under certain conditions.\n\
186 See the COPYING file in the distribution for more information.\n\
188 More information about SBCL is available at <http://sbcl.sourceforge.net/>.\n\
189 ", SBCL_VERSION_STRING);
197 main(int argc, char *argv[], char *envp[])
199 /* the name of the core file we're to execute. Note that this is
200 * a malloc'ed string which should be freed eventually. */
203 /* other command line options */
204 boolean noinform = 0;
205 boolean end_runtime_options = 0;
207 lispobj initial_function;
209 /* KLUDGE: os_vm_page_size is set by os_init(), and on some
210 * systems (e.g. Alpha) arch_init() needs need os_vm_page_size, so
211 * it must follow os_init(). -- WHN 2000-01-26 */
217 /* Parse our part of the command line (aka "runtime options"),
218 * stripping out those options that we handle. */
221 while (argi < argc) {
222 char *arg = argv[argi];
223 if (0 == strcmp(arg, "--noinform")) {
226 } else if (0 == strcmp(arg, "--core")) {
228 lose("more than one core file specified");
232 lose("missing filename for --core argument");
234 core = copied_string(argv[argi]);
237 } else if (0 == strcmp(arg, "--help")) {
238 /* I think this is the (or a) usual convention: upon
239 * seeing "--help" we immediately print our help
240 * string and exit, ignoring everything else. */
243 } else if (0 == strcmp(arg, "--version")) {
244 /* As in "--help" case, I think this is expected. */
247 } else if (0 == strcmp(arg, "--end-runtime-options")) {
248 end_runtime_options = 1;
252 /* This option was unrecognized as a runtime option,
253 * so it must be a toplevel option or a user option,
254 * so we must be past the end of the runtime option
259 /* This is where we strip out those options that we handle. We
260 * also take this opportunity to make sure that we don't find
261 * an out-of-place "--end-runtime-options" option. */
263 char *argi0 = argv[argi];
265 while (argi < argc) {
266 char *arg = argv[argi++];
267 /* If we encounter --end-runtime-options for the first
268 * time after the point where we had to give up on
269 * runtime options, then the point where we had to
270 * give up on runtime options must've been a user
272 if (!end_runtime_options &&
273 0 == strcmp(arg, "--end-runtime-options")) {
274 lose("bad runtime option \"%s\"", argi0);
283 /* If no core file was specified, look for one. */
285 char *sbcl_home = getenv("SBCL_HOME");
287 char *stem = "/sbcl.core";
288 if(!sbcl_home) sbcl_home = SBCL_HOME;
289 lookhere = (char *) calloc(strlen(sbcl_home) +
293 sprintf(lookhere, "%s%s", sbcl_home, stem);
294 core = copied_existing_filename_or_null(lookhere);
297 lose("can't find core file");
300 /* Make sure that SBCL_HOME is set, no matter where the core was
302 if (!getenv("SBCL_HOME")) {
303 char *envstring, *copied_core, *dir;
304 char *stem = "SBCL_HOME=";
305 copied_core = copied_string(core);
306 dir = dirname(copied_core);
307 envstring = (char *) calloc(strlen(stem) +
311 sprintf(envstring, "%s%s", stem, dir);
324 #if defined(SVR4) || defined(__linux__)
328 define_var("nil", NIL, 1);
329 define_var("t", T, 1);
331 set_lossage_handler(monitor_or_something);
335 initial_function = load_core_file(core);
336 if (initial_function == NIL) {
337 lose("couldn't find initial function");
339 SHOW("freeing core");
342 gc_initialize_pointers();
345 arch_install_interrupt_handlers();
346 os_install_interrupt_handlers();
348 /* Convert remaining argv values to something that Lisp can grok. */
349 SHOW("setting POSIX-ARGV symbol value");
350 SetSymbolValue(POSIX_ARGV, alloc_base_string_list(argv),0);
352 /* Install a handler to pick off SIGINT until the Lisp system gets
353 * far enough along to install its own handler. */
356 FSHOW((stderr, "/funcalling initial_function=0x%lx\n", initial_function));
357 create_thread(initial_function);
358 /* in a unithread build, create_thread never returns */
359 #ifdef LISP_FEATURE_SB_THREAD
360 gc_thread_pid=getpid();
365 static void parent_sighandler(int signum,siginfo_t *info, void *void_context)
368 os_context_t *context = (os_context_t*)void_context;
370 "parent thread got signal %d from %d, maybe_gc_pending=%d\n",
371 signum, info->si_pid,
376 #ifdef LISP_FEATURE_SB_THREAD
377 int show_thread_exit=0;
379 static void /* noreturn */ parent_loop(void)
386 sigemptyset(&sigset);
388 sigaddset(&sigset, SIGALRM);
389 sigaddset(&sigset, SIGCHLD);
390 sigprocmask(SIG_UNBLOCK,&sigset,0);
391 sa.sa_handler=parent_sighandler;
393 sa.sa_flags=SA_SIGINFO;
394 sigaction(SIGALRM, &sa, 0);
395 sigaction(SIGCHLD, &sa, 0);
397 sigemptyset(&sigset);
398 sa.sa_handler=SIG_IGN;
401 sigaction(SIGINT, &sa, 0);
403 while(!all_threads) {
406 while(all_threads && (pid=waitpid(-1,&status,__WALL))) {
408 int real_errno=errno;
410 if(real_errno == EINTR) {
413 if(real_errno == ECHILD) break;
414 fprintf(stderr,"waitpid: %s\n",strerror(real_errno));
417 if(WIFEXITED(status) || WIFSIGNALED(status)) {
418 th=find_thread_by_pid(pid);
421 fprintf(stderr,"waitpid : child %d %x exited \n", pid,th);
423 if(!all_threads) break;
426 exit(WEXITSTATUS(status));