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