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