1.0.21.24: saving runtime options in executables
[sbcl.git] / src / runtime / linux-os.c
1 /*
2  * the Linux incarnation of OS-dependent routines.  See also
3  * $(sbcl_arch)-linux-os.c
4  *
5  * This file (along with os.h) exports an OS-independent interface to
6  * the operating system VM facilities. Surprise surprise, this
7  * interface looks a lot like the Mach interface (but simpler in some
8  * places). For some operating systems, a subset of these functions
9  * will have to be emulated.
10  */
11
12 /*
13  * This software is part of the SBCL system. See the README file for
14  * more information.
15  *
16  * This software is derived from the CMU CL system, which was
17  * written at Carnegie Mellon University and released into the
18  * public domain. The software is in the public domain and is
19  * provided with absolutely no warranty. See the COPYING and CREDITS
20  * files for more information.
21  */
22
23 #include <stdio.h>
24 #include <sys/param.h>
25 #include <sys/file.h>
26 #include "sbcl.h"
27 #include "./signal.h"
28 #include "os.h"
29 #include "arch.h"
30 #include "globals.h"
31 #include "interrupt.h"
32 #include "interr.h"
33 #include "lispregs.h"
34 #include "runtime.h"
35 #include "genesis/static-symbols.h"
36 #include "genesis/fdefn.h"
37
38 #include <sys/socket.h>
39 #include <sys/utsname.h>
40 #include <errno.h>
41
42 #include <sys/types.h>
43 #include <signal.h>
44 /* #include <sys/sysinfo.h> */
45 #include <sys/time.h>
46 #include <sys/stat.h>
47 #include <unistd.h>
48 #include <linux/version.h>
49
50 #include "validate.h"
51 #include "thread.h"
52 #include "gc.h"
53 #if defined LISP_FEATURE_GENCGC
54 #include "gencgc-internal.h"
55 #else
56 #include "cheneygc-internal.h"
57 #endif
58
59 #ifdef LISP_FEATURE_X86
60 /* Prototype for personality(2). Done inline here since the header file
61  * for this isn't available on old versions of glibc. */
62 int personality (unsigned long);
63 #endif
64
65 size_t os_vm_page_size;
66
67 #if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_LUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX)
68 #include <sys/syscall.h>
69 #include <unistd.h>
70 #include <errno.h>
71
72 /* values taken from the kernel's linux/futex.h.  This header file
73    doesn't exist in userspace, which is our excuse for not grovelling
74    them automatically */
75 #define FUTEX_WAIT (0)
76 #define FUTEX_WAKE (1)
77 #define FUTEX_FD (2)
78 #define FUTEX_REQUEUE (3)
79
80 #define sys_futex sbcl_sys_futex
81 static inline int sys_futex (void *futex, int op, int val, struct timespec *rel)
82 {
83     return syscall (SYS_futex, futex, op, val, rel);
84 }
85
86 int
87 futex_wait(int *lock_word, int oldval, long sec, unsigned long usec)
88 {
89   struct timespec timeout;
90   int t;
91
92  again:
93   if (sec<0) {
94     t = sys_futex(lock_word,FUTEX_WAIT,oldval, 0);
95   }
96   else {
97     timeout.tv_sec = sec;
98     timeout.tv_nsec = usec * 1000;
99     t = sys_futex(lock_word,FUTEX_WAIT,oldval, &timeout);
100   }
101   if (t==0)
102       return 0;
103   else if (errno==ETIMEDOUT)
104       return 1;
105   else if (errno==EINTR)
106       /* spurious wakeup from interrupt */
107       goto again;
108   else
109       /* EWOULDBLOCK and others, need to check the lock */
110       return -1;
111 }
112
113 int
114 futex_wake(int *lock_word, int n)
115 {
116     return sys_futex(lock_word,FUTEX_WAKE,n,0);
117 }
118 #endif
119
120 \f
121 int linux_sparc_siginfo_bug = 0;
122
123 /* This variable was in real use for a few months, basically for
124  * storing autodetected information about whether the Linux
125  * installation was recent enough to support SBCL threads, and make
126  * some run-time decisions based on that. But this turned out to be
127  * unstable, so now we just flat-out refuse to start on the old installations
128  * when thread support has been compiled in.
129  *
130  * Unfortunately, in the meanwhile Slime started depending on this
131  * variable for deciding which communication style to use. So even
132  * though this variable looks unused, it shouldn't be deleted until
133  * it's no longer used in the versions of Slime that people are
134  * likely to download first. -- JES, 2006-06-07
135  */
136 int linux_no_threads_p = 0;
137
138 #ifdef LISP_FEATURE_SB_THREAD
139 int
140 isnptl (void)
141 {
142   size_t n = confstr (_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
143   if (n > 0) {
144       char *buf = alloca (n);
145       confstr (_CS_GNU_LIBPTHREAD_VERSION, buf, n);
146       if (strstr (buf, "NPTL")) {
147           return 1;
148       }
149   }
150   return 0;
151 }
152 #endif
153
154 void
155 os_init(char *argv[], char *envp[])
156 {
157     /* Conduct various version checks: do we have enough mmap(), is
158      * this a sparc running 2.2, can we do threads? */
159 #if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_LUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX)
160     int *futex=0;
161 #endif
162     struct utsname name;
163     int major_version;
164     int minor_version;
165     int patch_version;
166     char *p;
167     uname(&name);
168     p=name.release;
169     major_version = atoi(p);
170     p=strchr(p,'.')+1;
171     minor_version = atoi(p);
172     p=strchr(p,'.')+1;
173     patch_version = atoi(p);
174     if (major_version<2) {
175         lose("linux kernel version too old: major version=%d (can't run in version < 2.0.0)\n",
176              major_version);
177     }
178     if (!(major_version>2 || minor_version >= 4)) {
179 #ifdef LISP_FEATURE_SPARC
180         FSHOW((stderr,"linux kernel %d.%d predates 2.4;\n enabling workarounds for SPARC kernel bugs in signal handling.\n", major_version,minor_version));
181         linux_sparc_siginfo_bug = 1;
182 #endif
183     }
184 #ifdef LISP_FEATURE_SB_THREAD
185 #if !defined(LISP_FEATURE_SB_LUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX)
186     futex_wait(futex,-1,-1,0);
187     if(errno==ENOSYS) {
188        lose("This version of SBCL is compiled with threading support, but your kernel\n"
189             "is too old to support this. Please use a more recent kernel or\n"
190             "a version of SBCL without threading support.\n");
191     }
192 #endif
193     if(! isnptl()) {
194        lose("This version of SBCL only works correctly with the NPTL threading\n"
195             "library. Please use a newer glibc, use an older SBCL, or stop using\n"
196             "LD_ASSUME_KERNEL\n");
197     }
198 #endif
199
200     /* Don't use getpagesize(), since it's not constant across Linux
201      * kernel versions on some architectures (for example PPC). FIXME:
202      * possibly the same should be done on other architectures too.
203      */
204     os_vm_page_size = BACKEND_PAGE_SIZE;
205
206     /* KLUDGE: Disable memory randomization on new Linux kernels
207      * by setting a personality flag and re-executing. (We need
208      * to re-execute, since the memory maps that can conflict with
209      * the SBCL spaces have already been done at this point).
210      *
211      * Since randomization is currently implemented only on x86 kernels,
212      * don't do this trick on other platforms.
213      */
214 #ifdef LISP_FEATURE_X86
215     if ((major_version == 2
216          /* Some old kernels will apparently lose unsupported personality flags
217           * on exec() */
218          && ((minor_version == 6 && patch_version >= 11)
219              || (minor_version > 6)))
220         || major_version >= 3)
221     {
222         int pers = personality(0xffffffffUL);
223         /* 0x40000 aka. ADDR_NO_RANDOMIZE */
224         if (!(pers & 0x40000)) {
225             int retval = personality(pers | 0x40000);
226             /* Allegedly some Linux kernels (the reported case was
227              * "hardened Linux 2.6.7") won't set the new personality,
228              * but nor will they return -1 for an error. So as a
229              * workaround query the new personality...
230              */
231             int newpers = personality(0xffffffffUL);
232             /* ... and don't re-execute if either the setting resulted
233              * in an error or if the value didn't change. Otherwise
234              * this might result in an infinite loop.
235              */
236             if (retval != -1 && newpers != pers) {
237                 /* Use /proc/self/exe instead of trying to figure out
238                  * the executable path from PATH and argv[0], since
239                  * that's unreliable. We follow the symlink instead of
240                  * executing the file directly in order to prevent top
241                  * from displaying the name of the process as "exe". */
242                 char runtime[PATH_MAX+1];
243                 int i = readlink("/proc/self/exe", runtime, PATH_MAX);
244                 if (i != -1) {
245                     runtime[i] = '\0';
246                     execve(runtime, argv, envp);
247                 }
248             }
249             /* Either changing the personality or execve() failed. Either
250              * way we might as well continue, and hope that the random
251              * memory maps are ok this time around.
252              */
253             fprintf(stderr, "WARNING: Couldn't re-execute SBCL with the proper personality flags (maybe /proc isn't mounted?). Trying to continue anyway.\n");
254         }
255     }
256     /* Use SSE detector.  Recent versions of Linux enable SSE support
257      * on SSE capable CPUs.  */
258     /* FIXME: Are there any old versions that does not support SSE?  */
259     fast_bzero_pointer = fast_bzero_detect;
260 #endif
261 }
262
263
264 #ifdef LISP_FEATURE_ALPHA
265 /* The Alpha is a 64 bit CPU.  SBCL is a 32 bit application.  Due to all
266  * the places that assume we can get a pointer into a fixnum with no
267  * information loss, we have to make sure it allocates all its ram in the
268  * 0-2Gb region.  */
269
270 static void * under_2gb_free_pointer=DYNAMIC_1_SPACE_END;
271 #endif
272
273 os_vm_address_t
274 os_validate(os_vm_address_t addr, os_vm_size_t len)
275 {
276     int flags =  MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
277     os_vm_address_t actual;
278
279 #ifdef LISP_FEATURE_ALPHA
280     if (!addr) {
281         addr=under_2gb_free_pointer;
282     }
283 #endif
284     actual = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
285     if (actual == MAP_FAILED) {
286         perror("mmap");
287         return 0;               /* caller should check this */
288     }
289
290     if (addr && (addr!=actual)) {
291         fprintf(stderr, "mmap: wanted %lu bytes at %p, actually mapped at %p\n",
292                 (unsigned long) len, addr, actual);
293         return 0;
294     }
295
296 #ifdef LISP_FEATURE_ALPHA
297
298     len=(len+(os_vm_page_size-1))&(~(os_vm_page_size-1));
299     under_2gb_free_pointer+=len;
300 #endif
301
302     return actual;
303 }
304
305 void
306 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
307 {
308     if (munmap(addr,len) == -1) {
309         perror("munmap");
310     }
311 }
312
313 os_vm_address_t
314 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
315 {
316     os_vm_address_t actual;
317
318     actual = mmap(addr, len, OS_VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
319                   fd, (off_t) offset);
320     if (actual == MAP_FAILED || (addr && (addr != actual))) {
321         perror("mmap");
322         lose("unexpected mmap(..) failure\n");
323     }
324
325     return actual;
326 }
327
328 void
329 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
330 {
331     if (mprotect(address, length, prot) == -1) {
332         if (errno == ENOMEM) {
333             lose("An mprotect call failed with ENOMEM. This probably means that the maximum amount\n"
334                  "of separate memory mappings was exceeded. To fix the problem, either increase\n"
335                  "the maximum with e.g. 'echo 262144 > /proc/sys/vm/max_map_count' or recompile\n"
336                  "SBCL with a larger value for GENCGC-PAGE-SIZE in 'src/target/parms.lisp'.");
337         } else {
338             perror("mprotect");
339         }
340     }
341 }
342 \f
343 boolean
344 is_valid_lisp_addr(os_vm_address_t addr)
345 {
346     struct thread *th;
347     size_t ad = (size_t) addr;
348
349     if ((READ_ONLY_SPACE_START <= ad && ad < READ_ONLY_SPACE_END)
350         || (STATIC_SPACE_START <= ad && ad < STATIC_SPACE_END)
351 #if defined LISP_FEATURE_GENCGC
352         || (DYNAMIC_SPACE_START <= ad && ad < DYNAMIC_SPACE_END)
353 #else
354         || (DYNAMIC_0_SPACE_START <= ad && ad < DYNAMIC_0_SPACE_END)
355         || (DYNAMIC_1_SPACE_START <= ad && ad < DYNAMIC_1_SPACE_END)
356 #endif
357         )
358         return 1;
359     for_each_thread(th) {
360         if((size_t)(th->control_stack_start) <= ad
361            && ad < (size_t)(th->control_stack_end))
362             return 1;
363         if((size_t)(th->binding_stack_start) <= ad
364            && ad < (size_t)(th->binding_stack_start + BINDING_STACK_SIZE))
365             return 1;
366     }
367     return 0;
368 }
369 \f
370 /*
371  * any OS-dependent special low-level handling for signals
372  */
373
374 /*
375  * The GC needs to be hooked into whatever signal is raised for
376  * page fault on this OS.
377  */
378 static void
379 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
380 {
381     os_context_t *context = arch_os_get_context(&void_context);
382     os_vm_address_t addr = arch_get_bad_addr(signal, info, context);
383
384 #ifdef LISP_FEATURE_ALPHA
385     /* Alpha stuff: This is the end of a pseudo-atomic section during
386        which a signal was received.  We must deal with the pending
387        interrupt (see also interrupt.c, ../code/interrupt.lisp)
388
389        (how we got here: when interrupting, we set bit 63 in reg_ALLOC.
390        At the end of the atomic section we tried to write to reg_ALLOC,
391        got a SIGSEGV (there's nothing mapped there) so ended up here. */
392     if (addr != NULL &&
393         *os_context_register_addr(context, reg_ALLOC) & (1L<<63)) {
394         *os_context_register_addr(context, reg_ALLOC) -= (1L<<63);
395         interrupt_handle_pending(context);
396         return;
397     }
398 #endif
399
400 #ifdef LISP_FEATURE_GENCGC
401     if (!gencgc_handle_wp_violation(addr))
402 #else
403     if (!cheneygc_handle_wp_violation(context, addr))
404 #endif
405         if (!handle_guard_page_triggered(context, addr))
406 #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
407             lisp_memory_fault_error(context, addr);
408 #else
409             interrupt_handle_now(signal, info, context);
410 #endif
411 }
412
413 void
414 os_install_interrupt_handlers(void)
415 {
416     undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT,
417                                                  sigsegv_handler);
418 #ifdef LISP_FEATURE_SB_THREAD
419     undoably_install_low_level_interrupt_handler(SIG_INTERRUPT_THREAD,
420                                                  interrupt_thread_handler);
421     undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC,
422                                                  sig_stop_for_gc_handler);
423 #endif
424 }
425
426 char *
427 os_get_runtime_executable_path()
428 {
429     char path[PATH_MAX + 1];
430     int size;
431
432     size = readlink("/proc/self/exe", path, sizeof(path)-1);
433     if (size < 0)
434         return NULL;
435     else
436         path[size] = '\0';
437
438     return copied_string(path);
439 }