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