More efficient integer division by multiplication
[sbcl.git] / src / runtime / runtime.c
index f2b52d6..d1a215b 100644 (file)
@@ -35,6 +35,7 @@
 #endif
 #include <errno.h>
 #include <locale.h>
 #endif
 #include <errno.h>
 #include <locale.h>
+#include <limits.h>
 
 #if defined(SVR4) || defined(__linux__)
 #include <time.h>
 
 #if defined(SVR4) || defined(__linux__)
 #include <time.h>
 #include "signal.h"
 
 #include "runtime.h"
 #include "signal.h"
 
 #include "runtime.h"
-#include "alloc.h"
 #include "vars.h"
 #include "globals.h"
 #include "os.h"
 #include "vars.h"
 #include "globals.h"
 #include "os.h"
+#include "interr.h"
+#include "alloc.h"
 #include "interrupt.h"
 #include "arch.h"
 #include "gc.h"
 #include "interrupt.h"
 #include "arch.h"
 #include "gc.h"
-#include "interr.h"
 #include "validate.h"
 #include "core.h"
 #include "save.h"
 #include "validate.h"
 #include "core.h"
 #include "save.h"
 #endif
 
 #ifndef SBCL_HOME
 #endif
 
 #ifndef SBCL_HOME
-#define SBCL_HOME "/usr/local/lib/sbcl/"
+#define SBCL_HOME SBCL_PREFIX"/lib/sbcl/"
+#endif
+
+#ifdef LISP_FEATURE_HPUX
+extern void *return_from_lisp_stub;
+#include "genesis/closure.h"
+#include "genesis/simple-fun.h"
 #endif
 
 \f
 /* SIGINT handler that invokes the monitor (for when Lisp isn't up to it) */
 static void
 #endif
 
 \f
 /* SIGINT handler that invokes the monitor (for when Lisp isn't up to it) */
 static void
-sigint_handler(int signal, siginfo_t *info, void *void_context)
+sigint_handler(int signal, siginfo_t *info, os_context_t *context)
 {
     lose("\nSIGINT hit at 0x%08lX\n",
 {
     lose("\nSIGINT hit at 0x%08lX\n",
-         (unsigned long) *os_context_pc_addr(void_context));
+         (unsigned long) *os_context_pc_addr(context));
 }
 
 /* (This is not static, because we want to be able to call it from
 }
 
 /* (This is not static, because we want to be able to call it from
@@ -122,18 +129,36 @@ copied_existing_filename_or_null(char *filename)
     }
 }
 
     }
 }
 
-/* Convert a null-terminated array of null-terminated strings (e.g.
- * argv or envp) into a Lisp list of Lisp base-strings. */
-static lispobj
-alloc_base_string_list(char *array_ptr[])
+#ifndef LISP_FEATURE_WIN32
+char *
+copied_realpath(const char *pathname)
 {
 {
-    if (*array_ptr) {
-        return alloc_cons(alloc_base_string(*array_ptr),
-                          alloc_base_string_list(1 + array_ptr));
-    } else {
-        return NIL;
+    char *messy, *tidy;
+    size_t len;
+
+    /* realpath() supposedly can't be counted on to always return
+     * an absolute path, so we prepend the cwd to relative paths */
+    messy = NULL;
+    if (pathname[0] != '/') {
+        messy = successful_malloc(PATH_MAX + 1);
+        if (getcwd(messy, PATH_MAX + 1) == NULL) {
+            free(messy);
+            return NULL;
+        }
+        len = strlen(messy);
+        snprintf(messy + len, PATH_MAX + 1 - len, "/%s", pathname);
+    }
+
+    tidy = successful_malloc(PATH_MAX + 1);
+    if (realpath((messy ? messy : pathname), tidy) == NULL) {
+        free(messy);
+        free(tidy);
+        return NULL;
     }
     }
+
+    return tidy;
 }
 }
+#endif /* LISP_FEATURE_WIN32 */
 \f
 /* miscellaneous chattiness */
 
 \f
 /* miscellaneous chattiness */
 
@@ -147,12 +172,21 @@ Common runtime options:\n\
   --version                  Print version information and exit.\n\
   --core <filename>          Use the specified core file instead of the default.\n\
   --dynamic-space-size <MiB> Size of reserved dynamic space in megabytes.\n\
   --version                  Print version information and exit.\n\
   --core <filename>          Use the specified core file instead of the default.\n\
   --dynamic-space-size <MiB> Size of reserved dynamic space in megabytes.\n\
+  --control-stack-size <MiB> Size of reserved control stack in megabytes.\n\
 \n\
 Common toplevel options:\n\
   --sysinit <filename>       System-wide init-file to use instead of default.\n\
   --userinit <filename>      Per-user init-file to use instead of default.\n\
   --no-sysinit               Inhibit processing of any system-wide init-file.\n\
   --no-userinit              Inhibit processing of any per-user init-file.\n\
 \n\
 Common toplevel options:\n\
   --sysinit <filename>       System-wide init-file to use instead of default.\n\
   --userinit <filename>      Per-user init-file to use instead of default.\n\
   --no-sysinit               Inhibit processing of any system-wide init-file.\n\
   --no-userinit              Inhibit processing of any per-user init-file.\n\
+  --disable-debugger         Invoke sb-ext:disable-debugger.\n\
+  --noprint                  Run a Read-Eval Loop without printing results.\n\
+  --script [<filename>]      Skip #! line, disable debugger, avoid verbosity.\n\
+  --quit                     Exit with code 0 after option processing.\n\
+  --non-interactive          Sets both --quit and --disable-debugger.\n\
+Common toplevel options that are processed in order:\n\
+  --eval <form>              Form to eval when processing this option.\n\
+  --load <filename>          File to load when processing this option.\n\
 \n\
 User options are not processed by SBCL. All runtime options must\n\
 appear before toplevel options, and all toplevel options must\n\
 \n\
 User options are not processed by SBCL. All runtime options must\n\
 appear before toplevel options, and all toplevel options must\n\
@@ -194,7 +228,7 @@ search_for_core ()
     char *stem = "/sbcl.core";
     char *core;
 
     char *stem = "/sbcl.core";
     char *core;
 
-    if(!sbcl_home) sbcl_home = SBCL_HOME;
+    if (!(sbcl_home && *sbcl_home)) sbcl_home = SBCL_HOME;
     lookhere = (char *) calloc(strlen(sbcl_home) +
                                strlen(stem) +
                                1,
     lookhere = (char *) calloc(strlen(sbcl_home) +
                                strlen(stem) +
                                1,
@@ -211,9 +245,58 @@ search_for_core ()
     return core;
 }
 
     return core;
 }
 
+/* Try to find the path to an executable from argv[0], this is only
+ * used when os_get_runtime_executable_path() returns NULL */
+#ifdef LISP_FEATURE_WIN32
+char *
+search_for_executable(const char *argv0)
+{
+    return NULL;
+}
+#else /* LISP_FEATURE_WIN32 */
+char *
+search_for_executable(const char *argv0)
+{
+    char *search, *start, *end, *buf;
+
+    /* If argv[0] contains a slash then it's probably an absolute path
+     * or relative to the current directory, so check if it exists. */
+    if (strchr(argv0, '/') != NULL && access(argv0, F_OK) == 0)
+        return copied_realpath(argv0);
+
+    /* Bail on an absolute path which doesn't exist */
+    if (argv0[0] == '/')
+        return NULL;
+
+    /* Otherwise check if argv[0] exists relative to any directory in PATH */
+    search = getenv("PATH");
+    if (search == NULL)
+        return NULL;
+    search = copied_string(search);
+    buf = successful_malloc(PATH_MAX + 1);
+    for (start = search; (end = strchr(start, ':')) != NULL; start = end + 1) {
+        *end = '\0';
+        snprintf(buf, PATH_MAX + 1, "%s/%s", start, argv0);
+        if (access(buf, F_OK) == 0) {
+            free(search);
+            search = copied_realpath(buf);
+            free(buf);
+            return search;
+        }
+    }
+
+    free(search);
+    free(buf);
+    return NULL;
+}
+#endif /* LISP_FEATURE_WIN32 */
+
 char **posix_argv;
 char *core_string;
 
 char **posix_argv;
 char *core_string;
 
+struct runtime_options *runtime_options;
+
+char *saved_runtime_path = NULL;
 \f
 int
 main(int argc, char *argv[], char *envp[])
 \f
 int
 main(int argc, char *argv[], char *envp[])
@@ -228,25 +311,70 @@ main(int argc, char *argv[], char *envp[])
     char *core = 0;
     char **sbcl_argv = 0;
     os_vm_offset_t embedded_core_offset = 0;
     char *core = 0;
     char **sbcl_argv = 0;
     os_vm_offset_t embedded_core_offset = 0;
+    char *runtime_path = 0;
 
     /* other command line options */
     boolean noinform = 0;
     boolean end_runtime_options = 0;
 
     /* other command line options */
     boolean noinform = 0;
     boolean end_runtime_options = 0;
+    boolean disable_lossage_handler_p = 0;
 
     lispobj initial_function;
 
     lispobj initial_function;
+    const char *sbcl_home = getenv("SBCL_HOME");
 
     interrupt_init();
 
     interrupt_init();
-    block_blockable_signals();
+    block_blockable_signals(0, 0);
 
     setlocale(LC_ALL, "");
 
 
     setlocale(LC_ALL, "");
 
+    runtime_options = NULL;
+
+    /* Save the argv[0] derived runtime path in case
+     * os_get_runtime_executable_path(1) isn't able to get an
+     * externally-usable path later on. */
+    saved_runtime_path = search_for_executable(argv[0]);
+
+    /* Check early to see if this executable has an embedded core,
+     * which also populates runtime_options if the core has runtime
+     * options */
+    runtime_path = os_get_runtime_executable_path(0);
+    if (runtime_path || saved_runtime_path) {
+        os_vm_offset_t offset = search_for_embedded_core(
+            runtime_path ? runtime_path : saved_runtime_path);
+        if (offset != -1) {
+            embedded_core_offset = offset;
+            core = (runtime_path ? runtime_path :
+                    copied_string(saved_runtime_path));
+        } else {
+            if (runtime_path)
+                free(runtime_path);
+        }
+    }
+
+
     /* Parse our part of the command line (aka "runtime options"),
      * stripping out those options that we handle. */
     /* Parse our part of the command line (aka "runtime options"),
      * stripping out those options that we handle. */
-    {
+    if (runtime_options != NULL) {
+        dynamic_space_size = runtime_options->dynamic_space_size;
+        thread_control_stack_size = runtime_options->thread_control_stack_size;
+        sbcl_argv = argv;
+    } else {
         int argi = 1;
         int argi = 1;
+
+        runtime_options = successful_malloc(sizeof(struct runtime_options));
+
         while (argi < argc) {
             char *arg = argv[argi];
         while (argi < argc) {
             char *arg = argv[argi];
-            if (0 == strcmp(arg, "--noinform")) {
+            if (0 == strcmp(arg, "--script")) {
+                /* This is both a runtime and a toplevel option. As a
+                 * runtime option, it is equivalent to --noinform.
+                 * This exits, and does not increment argi, so that
+                 * TOPLEVEL-INIT sees the option. */
+                noinform = 1;
+                end_runtime_options = 1;
+                disable_lossage_handler_p = 1;
+                lose_on_corruption_p = 1;
+                break;
+            } else if (0 == strcmp(arg, "--noinform")) {
                 noinform = 1;
                 ++argi;
             } else if (0 == strcmp(arg, "--core")) {
                 noinform = 1;
                 ++argi;
             } else if (0 == strcmp(arg, "--core")) {
@@ -274,10 +402,32 @@ main(int argc, char *argv[], char *envp[])
                 ++argi;
                 if (argi >= argc)
                     lose("missing argument for --dynamic-space-size");
                 ++argi;
                 if (argi >= argc)
                     lose("missing argument for --dynamic-space-size");
+                {
+                  char *tail;
+                  long tmp = strtol(argv[argi++], &tail, 0);
+                  if (tail[0])
+                    lose("--dynamic-space-size argument is not a number");
+                  if ((tmp <= 0) ||
+                      (tmp >= (LONG_MAX >> 20))) {
+                    lose("--dynamic-space-size argument is out of range");
+                  }
+                  dynamic_space_size = tmp << 20;
+                }
+#               ifdef MAX_DYNAMIC_SPACE_END
+                if (!((DYNAMIC_SPACE_START <
+                       DYNAMIC_SPACE_START+dynamic_space_size) &&
+                      (DYNAMIC_SPACE_START+dynamic_space_size <=
+                       MAX_DYNAMIC_SPACE_END)))
+                    lose("--dynamic-space-size argument is too large");
+#               endif
+            } else if (0 == strcmp(arg, "--control-stack-size")) {
+                ++argi;
+                if (argi >= argc)
+                    lose("missing argument for --control-stack-size");
                 errno = 0;
                 errno = 0;
-                dynamic_space_size = strtol(argv[argi++], 0, 0) << 20;
+                thread_control_stack_size = strtol(argv[argi++], 0, 0) << 20;
                 if (errno)
                 if (errno)
-                    lose("argument to --dynamic-space-size is not a number");
+                    lose("argument to --control-stack-size is not a number");
             } else if (0 == strcmp(arg, "--debug-environment")) {
                 int n = 0;
                 printf("; Commandline arguments:\n");
             } else if (0 == strcmp(arg, "--debug-environment")) {
                 int n = 0;
                 printf("; Commandline arguments:\n");
@@ -292,6 +442,12 @@ main(int argc, char *argv[], char *envp[])
                     ++n;
                 }
                 ++argi;
                     ++n;
                 }
                 ++argi;
+            } else if (0 == strcmp(arg, "--disable-ldb")) {
+                disable_lossage_handler_p = 1;
+                ++argi;
+            } else if (0 == strcmp(arg, "--lose-on-corruption")) {
+                lose_on_corruption_p = 1;
+                ++argi;
             } else if (0 == strcmp(arg, "--end-runtime-options")) {
                 end_runtime_options = 1;
                 ++argi;
             } else if (0 == strcmp(arg, "--end-runtime-options")) {
                 end_runtime_options = 1;
                 ++argi;
@@ -331,8 +487,17 @@ main(int argc, char *argv[], char *envp[])
         }
     }
 
         }
     }
 
-    /* Align down to multiple of page_table page size */
-    dynamic_space_size = (dynamic_space_size/PAGE_BYTES) * PAGE_BYTES;
+    /* Align down to multiple of page_table page size, and to the appropriate
+     * stack alignment. */
+    dynamic_space_size &= ~(PAGE_BYTES-1);
+#ifdef LISP_FEATURE_GENCGC
+    dynamic_space_size &= ~(GENCGC_CARD_BYTES-1);
+#endif
+    thread_control_stack_size &= ~(CONTROL_STACK_ALIGNMENT_BYTES-1);
+
+    /* Preserve the runtime options for possible future core saving */
+    runtime_options->dynamic_space_size = dynamic_space_size;
+    runtime_options->thread_control_stack_size = thread_control_stack_size;
 
     /* KLUDGE: os_vm_page_size is set by os_init(), and on some
      * systems (e.g. Alpha) arch_init() needs need os_vm_page_size, so
 
     /* KLUDGE: os_vm_page_size is set by os_init(), and on some
      * systems (e.g. Alpha) arch_init() needs need os_vm_page_size, so
@@ -344,25 +509,12 @@ main(int argc, char *argv[], char *envp[])
 
     /* If no core file was specified, look for one. */
     if (!core) {
 
     /* If no core file was specified, look for one. */
     if (!core) {
-       char *runtime_path = os_get_runtime_executable_path();
-
-       if (runtime_path) {
-          os_vm_offset_t offset = search_for_embedded_core(runtime_path);
-
-          if (offset != -1) {
-             embedded_core_offset = offset;
-             core = runtime_path;
-          } else {
-             free(runtime_path);
-             core = search_for_core();
-          }
-       } else {
-          core = search_for_core();
-       }
+        core = search_for_core();
     }
 
     }
 
-    /* Make sure that SBCL_HOME is set, unless loading an embedded core. */
-    if (!getenv("SBCL_HOME") && embedded_core_offset == 0) {
+    /* Make sure that SBCL_HOME is set and not the empty string,
+       unless loading an embedded core. */
+    if (!(sbcl_home && *sbcl_home) && embedded_core_offset == 0) {
         char *envstring, *copied_core, *dir;
         char *stem = "SBCL_HOME=";
         copied_core = copied_string(core);
         char *envstring, *copied_core, *dir;
         char *stem = "SBCL_HOME=";
         copied_core = copied_string(core);
@@ -376,19 +528,20 @@ main(int argc, char *argv[], char *envp[])
         free(copied_core);
     }
 
         free(copied_core);
     }
 
-    if (!noinform) {
+    if (!noinform && embedded_core_offset == 0) {
         print_banner();
         fflush(stdout);
     }
 
         print_banner();
         fflush(stdout);
     }
 
-#if defined(SVR4) || defined(__linux__)
+#if defined(SVR4) || defined(__linux__) || defined(__NetBSD__)
     tzset();
 #endif
 
     define_var("nil", NIL, 1);
     define_var("t", T, 1);
 
     tzset();
 #endif
 
     define_var("nil", NIL, 1);
     define_var("t", T, 1);
 
-    enable_lossage_handler();
+    if (!disable_lossage_handler_p)
+        enable_lossage_handler();
 
     globals_init();
 
 
     globals_init();
 
@@ -396,6 +549,12 @@ main(int argc, char *argv[], char *envp[])
     if (initial_function == NIL) {
         lose("couldn't find initial function\n");
     }
     if (initial_function == NIL) {
         lose("couldn't find initial function\n");
     }
+#ifdef LISP_FEATURE_HPUX
+    /* -1 = CLOSURE_FUN_OFFSET, 23 = SIMPLE_FUN_CODE_OFFSET, we are
+     * not in LANGUAGE_ASSEMBLY so we cant reach them. */
+    return_from_lisp_stub = (void *) ((char *)*((unsigned long *)
+                 ((char *)initial_function + -1)) + 23);
+#endif
 
     gc_initialize_pointers();
 
 
     gc_initialize_pointers();