0.9.13.22:
[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 #endif
56
57 #ifdef LISP_FEATURE_X86
58 /* Prototype for personality(2). Done inline here since the header file
59  * for this isn't available on old versions of glibc. */
60 int personality (unsigned long);
61 #endif
62
63 size_t os_vm_page_size;
64
65 #if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_LUTEX)
66 #include <sys/syscall.h>
67 #include <unistd.h>
68 #include <errno.h>
69
70 /* values taken from the kernel's linux/futex.h.  This header file
71    doesn't exist in userspace, which is our excuse for not grovelling
72    them automatically */
73 #define FUTEX_WAIT (0)
74 #define FUTEX_WAKE (1)
75 #define FUTEX_FD (2)
76 #define FUTEX_REQUEUE (3)
77
78 #define sys_futex sbcl_sys_futex
79 static inline int sys_futex (void *futex, int op, int val, struct timespec *rel)
80 {
81     return syscall (SYS_futex, futex, op, val, rel);
82 }
83
84 int
85 futex_wait(int *lock_word, int oldval)
86 {
87     int t= sys_futex(lock_word,FUTEX_WAIT,oldval, 0);
88     return t;
89 }
90
91 int
92 futex_wake(int *lock_word, int n)
93 {
94     return sys_futex(lock_word,FUTEX_WAKE,n,0);
95 }
96 #endif
97
98 \f
99 int linux_sparc_siginfo_bug = 0;
100
101 #ifdef LISP_FEATURE_SB_THREAD
102 int
103 isnptl (void)
104 {
105   size_t n = confstr (_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
106   if (n > 0) {
107       char *buf = alloca (n);
108       confstr (_CS_GNU_LIBPTHREAD_VERSION, buf, n);
109       if (strstr (buf, "NPTL")) {
110           return 1;
111       }
112   }
113   return 0;
114 }
115 #endif
116
117 void
118 os_init(char *argv[], char *envp[])
119 {
120     /* Conduct various version checks: do we have enough mmap(), is
121      * this a sparc running 2.2, can we do threads? */
122 #if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_LUTEX)
123     int *futex=0;
124 #endif
125     struct utsname name;
126     int major_version;
127     int minor_version;
128     int patch_version;
129     char *p;
130     uname(&name);
131     p=name.release;
132     major_version = atoi(p);
133     p=strchr(p,'.')+1;
134     minor_version = atoi(p);
135     p=strchr(p,'.')+1;
136     patch_version = atoi(p);
137     if (major_version<2) {
138         lose("linux kernel version too old: major version=%d (can't run in version < 2.0.0)\n",
139              major_version);
140     }
141     if (!(major_version>2 || minor_version >= 4)) {
142 #ifdef LISP_FEATURE_SPARC
143         FSHOW((stderr,"linux kernel %d.%d predates 2.4;\n enabling workarounds for SPARC kernel bugs in signal handling.\n", major_version,minor_version));
144         linux_sparc_siginfo_bug = 1;
145 #endif
146     }
147 #ifdef LISP_FEATURE_SB_THREAD
148 #if !defined(LISP_FEATURE_SB_LUTEX)
149     futex_wait(futex,-1);
150     if(errno==ENOSYS) {
151        lose("This version of SBCL is compiled with threading support, but your kernel\n"
152             "is too old to support this. Please use a more recent kernel or\n"
153             "a version of SBCL without threading support.\n");
154     }
155 #endif
156     if(! isnptl()) {
157        lose("This version of SBCL only works correctly with the NPTL threading\n"
158             "library. Please use a newer glibc, use an older SBCL, or stop using\n"
159             "LD_ASSUME_KERNEL\n");
160     }
161 #endif
162     os_vm_page_size = getpagesize();
163
164     /* KLUDGE: Disable memory randomization on new Linux kernels
165      * by setting a personality flag and re-executing. (We need
166      * to re-execute, since the memory maps that can conflict with
167      * the SBCL spaces have already been done at this point).
168      *
169      * Since randomization is currently implemented only on x86 kernels,
170      * don't do this trick on other platforms.
171      */
172 #ifdef LISP_FEATURE_X86
173     if ((major_version == 2
174          /* Some old kernels will apparently lose unsupported personality flags
175           * on exec() */
176          && ((minor_version == 6 && patch_version >= 11)
177              || (minor_version > 6)))
178         || major_version >= 3)
179     {
180         int pers = personality(0xffffffffUL);
181         /* 0x40000 aka. ADDR_NO_RANDOMIZE */
182         if (!(pers & 0x40000)) {
183             int retval = personality(pers | 0x40000);
184             /* Allegedly some Linux kernels (the reported case was
185              * "hardened Linux 2.6.7") won't set the new personality,
186              * but nor will they return -1 for an error. So as a
187              * workaround query the new personality...
188              */
189             int newpers = personality(0xffffffffUL);
190             /* ... and don't re-execute if either the setting resulted
191              * in an error or if the value didn't change. Otherwise
192              * this might result in an infinite loop.
193              */
194             if (retval != -1 && newpers != pers) {
195                 /* Use /proc/self/exe instead of trying to figure out
196                  * the executable path from PATH and argv[0], since
197                  * that's unreliable. We follow the symlink instead of
198                  * executing the file directly in order to prevent top
199                  * from displaying the name of the process as "exe". */
200                 char runtime[PATH_MAX+1];
201                 int i = readlink("/proc/self/exe", runtime, PATH_MAX);
202                 if (i != -1) {
203                     runtime[i] = '\0';
204                     execve(runtime, argv, envp);
205                 }
206             }
207             /* Either changing the personality or execve() failed. Either
208              * way we might as well continue, and hope that the random
209              * memory maps are ok this time around.
210              */
211             fprintf(stderr, "WARNING: Couldn't re-execute SBCL with the proper personality flags (maybe /proc isn't mounted?). Trying to continue anyway.\n");
212         }
213     }
214     /* Use SSE detector.  Recent versions of Linux enable SSE support
215      * on SSE capable CPUs.  */
216     /* FIXME: Are there any old versions that does not support SSE?  */
217     fast_bzero_pointer = fast_bzero_detect;
218 #endif
219 }
220
221
222 #ifdef LISP_FEATURE_ALPHA
223 /* The Alpha is a 64 bit CPU.  SBCL is a 32 bit application.  Due to all
224  * the places that assume we can get a pointer into a fixnum with no
225  * information loss, we have to make sure it allocates all its ram in the
226  * 0-2Gb region.  */
227
228 static void * under_2gb_free_pointer=DYNAMIC_1_SPACE_END;
229 #endif
230
231 os_vm_address_t
232 os_validate(os_vm_address_t addr, os_vm_size_t len)
233 {
234     int flags =  MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
235     os_vm_address_t actual;
236
237 #ifdef LISP_FEATURE_ALPHA
238     if (!addr) {
239         addr=under_2gb_free_pointer;
240     }
241 #endif
242     actual = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
243     if (actual == MAP_FAILED) {
244         perror("mmap");
245         return 0;               /* caller should check this */
246     }
247
248     if (addr && (addr!=actual)) {
249         fprintf(stderr, "mmap: wanted %lu bytes at %p, actually mapped at %p\n",
250                 (unsigned long) len, addr, actual);
251         return 0;
252     }
253
254 #ifdef LISP_FEATURE_ALPHA
255
256     len=(len+(os_vm_page_size-1))&(~(os_vm_page_size-1));
257     under_2gb_free_pointer+=len;
258 #endif
259
260     return actual;
261 }
262
263 void
264 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
265 {
266     if (munmap(addr,len) == -1) {
267         perror("munmap");
268     }
269 }
270
271 os_vm_address_t
272 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
273 {
274     os_vm_address_t actual;
275
276     actual = mmap(addr, len, OS_VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
277                   fd, (off_t) offset);
278     if (actual == MAP_FAILED || (addr && (addr != actual))) {
279         perror("mmap");
280         lose("unexpected mmap(..) failure\n");
281     }
282
283     return actual;
284 }
285
286 void
287 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
288 {
289     if (mprotect(address, length, prot) == -1) {
290         if (errno == ENOMEM) {
291             lose("An mprotect call failed with ENOMEM. This probably means that the maximum amount\n"
292                  "of separate memory mappings was exceeded. To fix the problem, either increase\n"
293                  "the maximum with e.g. 'echo 262144 > /proc/sys/vm/max_map_count' or recompile\n"
294                  "SBCL with a larger value for GENCGC-PAGE-SIZE in 'src/target/parms.lisp'.");
295         } else {
296             perror("mprotect");
297         }
298     }
299 }
300 \f
301 boolean
302 is_valid_lisp_addr(os_vm_address_t addr)
303 {
304     struct thread *th;
305     size_t ad = (size_t) addr;
306
307     if ((READ_ONLY_SPACE_START <= ad && ad < READ_ONLY_SPACE_END)
308         || (STATIC_SPACE_START <= ad && ad < STATIC_SPACE_END)
309 #if defined LISP_FEATURE_GENCGC
310         || (DYNAMIC_SPACE_START <= ad && ad < DYNAMIC_SPACE_END)
311 #else
312         || (DYNAMIC_0_SPACE_START <= ad && ad < DYNAMIC_0_SPACE_END)
313         || (DYNAMIC_1_SPACE_START <= ad && ad < DYNAMIC_1_SPACE_END)
314 #endif
315         )
316         return 1;
317     for_each_thread(th) {
318         if((size_t)(th->control_stack_start) <= ad
319            && ad < (size_t)(th->control_stack_end))
320             return 1;
321         if((size_t)(th->binding_stack_start) <= ad
322            && ad < (size_t)(th->binding_stack_start + BINDING_STACK_SIZE))
323             return 1;
324     }
325     return 0;
326 }
327 \f
328 /*
329  * any OS-dependent special low-level handling for signals
330  */
331
332 /*
333  * The GC needs to be hooked into whatever signal is raised for
334  * page fault on this OS.
335  */
336 static void
337 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
338 {
339     os_context_t *context = arch_os_get_context(&void_context);
340     os_vm_address_t addr = arch_get_bad_addr(signal, info, context);
341
342 #ifdef LISP_FEATURE_ALPHA
343     /* Alpha stuff: This is the end of a pseudo-atomic section during
344        which a signal was received.  We must deal with the pending
345        interrupt (see also interrupt.c, ../code/interrupt.lisp)
346
347        (how we got here: when interrupting, we set bit 63 in reg_ALLOC.
348        At the end of the atomic section we tried to write to reg_ALLOC,
349        got a SIGSEGV (there's nothing mapped there) so ended up here. */
350     if (addr != NULL &&
351         *os_context_register_addr(context, reg_ALLOC) & (1L<<63)) {
352         *os_context_register_addr(context, reg_ALLOC) -= (1L<<63);
353         interrupt_handle_pending(context);
354         return;
355     }
356 #endif
357
358 #ifdef LISP_FEATURE_GENCGC
359     if (!gencgc_handle_wp_violation(addr))
360 #else
361     if (!interrupt_maybe_gc(signal, info, context))
362 #endif
363         if (!handle_guard_page_triggered(context, addr))
364 #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
365             arrange_return_to_lisp_function(context, SymbolFunction(MEMORY_FAULT_ERROR));
366 #else
367             interrupt_handle_now(signal, info, context);
368 #endif
369 }
370
371 void
372 os_install_interrupt_handlers(void)
373 {
374     undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT,
375                                                  sigsegv_handler);
376 #ifdef LISP_FEATURE_SB_THREAD
377     undoably_install_low_level_interrupt_handler(SIG_INTERRUPT_THREAD,
378                                                  interrupt_thread_handler);
379     undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC,
380                                                  sig_stop_for_gc_handler);
381 #endif
382 }
383
384 char *
385 os_get_runtime_executable_path()
386 {
387     char path[PATH_MAX + 1];
388     int size;
389
390     size = readlink("/proc/self/exe", path, sizeof(path)-1);
391     if (size < 0)
392         return NULL;
393     else
394         path[size] = '\0';
395
396     return copied_string(path);
397 }