1.0.27.46: Fix build on systems with "src" in the path.
[sbcl/tcr.git] / src / runtime / linux-os.c
blob1635132cddc325f7dd2f26a3de20160cb3190098
1 /*
2 * the Linux incarnation of OS-dependent routines. See also
3 * $(sbcl_arch)-linux-os.c
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.
13 * This software is part of the SBCL system. See the README file for
14 * more information.
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.
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"
38 #include <sys/socket.h>
39 #include <sys/utsname.h>
40 #include <errno.h>
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>
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
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
65 size_t os_vm_page_size;
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>
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 /* This is also copied from linux/futex.h so that a binary compiled on
78 * a not so recent Linux system can still take advantage of private
79 * futexes when available.*/
80 #define FUTEX_WAIT_PRIVATE (0+128)
81 #define FUTEX_WAKE_PRIVATE (1+128)
82 #define FUTEX_FD (2)
83 #define FUTEX_REQUEUE (3)
85 /* Not static so that Lisp may query it. */
86 boolean futex_private_supported_p;
88 static inline int
89 futex_wait_op()
91 return (futex_private_supported_p ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT);
94 static inline int
95 futex_wake_op()
97 return (futex_private_supported_p ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE);
100 #define sys_futex sbcl_sys_futex
101 static inline int sys_futex (void *futex, int op, int val, struct timespec *rel)
103 return syscall (SYS_futex, futex, op, val, rel);
106 static void
107 futex_init()
109 int x = 0;
110 sys_futex(&x, FUTEX_WAIT, 1, 0);
111 if (errno == ENOSYS)
112 lose("This version of SBCL is compiled with threading support, but your kernel\n"
113 "is too old to support this. Please use a more recent kernel or\n"
114 "a version of SBCL without threading support.\n");
115 sys_futex(&x, FUTEX_WAIT_PRIVATE, 1, 0);
116 if (errno == EWOULDBLOCK) {
117 futex_private_supported_p = 1;
118 } else {
119 futex_private_supported_p = 0;
120 SHOW("No futex private suppport\n");
125 futex_wait(int *lock_word, int oldval, long sec, unsigned long usec)
127 struct timespec timeout;
128 int t;
130 if (sec<0) {
131 t = sys_futex(lock_word, futex_wait_op(), oldval, 0);
133 else {
134 timeout.tv_sec = sec;
135 timeout.tv_nsec = usec * 1000;
136 t = sys_futex(lock_word, futex_wait_op(), oldval, &timeout);
138 if (t==0)
139 return 0;
140 else if (errno==ETIMEDOUT)
141 return 1;
142 else if (errno==EINTR)
143 return 2;
144 else
145 /* EWOULDBLOCK and others, need to check the lock */
146 return -1;
150 futex_wake(int *lock_word, int n)
152 return sys_futex(lock_word, futex_wake_op(),n,0);
154 #endif
157 int linux_sparc_siginfo_bug = 0;
159 /* This variable was in real use for a few months, basically for
160 * storing autodetected information about whether the Linux
161 * installation was recent enough to support SBCL threads, and make
162 * some run-time decisions based on that. But this turned out to be
163 * unstable, so now we just flat-out refuse to start on the old installations
164 * when thread support has been compiled in.
166 * Unfortunately, in the meanwhile Slime started depending on this
167 * variable for deciding which communication style to use. So even
168 * though this variable looks unused, it shouldn't be deleted until
169 * it's no longer used in the versions of Slime that people are
170 * likely to download first. -- JES, 2006-06-07
172 int linux_no_threads_p = 0;
174 #ifdef LISP_FEATURE_SB_THREAD
176 isnptl (void)
178 size_t n = confstr (_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
179 if (n > 0) {
180 char *buf = alloca (n);
181 confstr (_CS_GNU_LIBPTHREAD_VERSION, buf, n);
182 if (strstr (buf, "NPTL")) {
183 return 1;
186 return 0;
188 #endif
190 void
191 os_init(char *argv[], char *envp[])
193 /* Conduct various version checks: do we have enough mmap(), is
194 * this a sparc running 2.2, can we do threads? */
195 struct utsname name;
196 int major_version;
197 int minor_version;
198 int patch_version;
199 char *p;
200 uname(&name);
201 p=name.release;
202 major_version = atoi(p);
203 p=strchr(p,'.')+1;
204 minor_version = atoi(p);
205 p=strchr(p,'.')+1;
206 patch_version = atoi(p);
207 if (major_version<2) {
208 lose("linux kernel version too old: major version=%d (can't run in version < 2.0.0)\n",
209 major_version);
211 if (!(major_version>2 || minor_version >= 4)) {
212 #ifdef LISP_FEATURE_SPARC
213 FSHOW((stderr,"linux kernel %d.%d predates 2.4;\n enabling workarounds for SPARC kernel bugs in signal handling.\n", major_version,minor_version));
214 linux_sparc_siginfo_bug = 1;
215 #endif
217 #ifdef LISP_FEATURE_SB_THREAD
218 #if !defined(LISP_FEATURE_SB_LUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX)
219 futex_init();
220 #endif
221 if(! isnptl()) {
222 lose("This version of SBCL only works correctly with the NPTL threading\n"
223 "library. Please use a newer glibc, use an older SBCL, or stop using\n"
224 "LD_ASSUME_KERNEL\n");
226 #endif
228 /* Don't use getpagesize(), since it's not constant across Linux
229 * kernel versions on some architectures (for example PPC). FIXME:
230 * possibly the same should be done on other architectures too.
232 os_vm_page_size = BACKEND_PAGE_BYTES;
234 /* KLUDGE: Disable memory randomization on new Linux kernels
235 * by setting a personality flag and re-executing. (We need
236 * to re-execute, since the memory maps that can conflict with
237 * the SBCL spaces have already been done at this point).
239 * Since randomization is currently implemented only on x86 kernels,
240 * don't do this trick on other platforms.
242 #ifdef LISP_FEATURE_X86
243 if ((major_version == 2
244 /* Some old kernels will apparently lose unsupported personality flags
245 * on exec() */
246 && ((minor_version == 6 && patch_version >= 11)
247 || (minor_version > 6)
248 /* This is what RHEL 3 reports */
249 || (minor_version == 4 && patch_version > 20)))
250 || major_version >= 3)
252 int pers = personality(0xffffffffUL);
253 /* 0x40000 aka. ADDR_NO_RANDOMIZE */
254 if (!(pers & 0x40000)) {
255 int retval = personality(pers | 0x40000);
256 /* Allegedly some Linux kernels (the reported case was
257 * "hardened Linux 2.6.7") won't set the new personality,
258 * but nor will they return -1 for an error. So as a
259 * workaround query the new personality...
261 int newpers = personality(0xffffffffUL);
262 /* ... and don't re-execute if either the setting resulted
263 * in an error or if the value didn't change. Otherwise
264 * this might result in an infinite loop.
266 if (retval != -1 && newpers != pers) {
267 /* Use /proc/self/exe instead of trying to figure out
268 * the executable path from PATH and argv[0], since
269 * that's unreliable. We follow the symlink instead of
270 * executing the file directly in order to prevent top
271 * from displaying the name of the process as "exe". */
272 char runtime[PATH_MAX+1];
273 int i = readlink("/proc/self/exe", runtime, PATH_MAX);
274 if (i != -1) {
275 runtime[i] = '\0';
276 execve(runtime, argv, envp);
279 /* Either changing the personality or execve() failed. Either
280 * way we might as well continue, and hope that the random
281 * memory maps are ok this time around.
283 fprintf(stderr, "WARNING: Couldn't re-execute SBCL with the proper personality flags (maybe /proc isn't mounted?). Trying to continue anyway.\n");
286 /* Use SSE detector. Recent versions of Linux enable SSE support
287 * on SSE capable CPUs. */
288 /* FIXME: Are there any old versions that does not support SSE? */
289 fast_bzero_pointer = fast_bzero_detect;
290 #endif
294 #ifdef LISP_FEATURE_ALPHA
295 /* The Alpha is a 64 bit CPU. SBCL is a 32 bit application. Due to all
296 * the places that assume we can get a pointer into a fixnum with no
297 * information loss, we have to make sure it allocates all its ram in the
298 * 0-2Gb region. */
300 static void * under_2gb_free_pointer=DYNAMIC_1_SPACE_END;
301 #endif
303 os_vm_address_t
304 os_validate(os_vm_address_t addr, os_vm_size_t len)
306 int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
307 os_vm_address_t actual;
309 #ifdef LISP_FEATURE_ALPHA
310 if (!addr) {
311 addr=under_2gb_free_pointer;
313 #endif
314 actual = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
315 if (actual == MAP_FAILED) {
316 perror("mmap");
317 return 0; /* caller should check this */
320 if (addr && (addr!=actual)) {
321 fprintf(stderr, "mmap: wanted %lu bytes at %p, actually mapped at %p\n",
322 (unsigned long) len, addr, actual);
323 return 0;
326 #ifdef LISP_FEATURE_ALPHA
328 len=(len+(os_vm_page_size-1))&(~(os_vm_page_size-1));
329 under_2gb_free_pointer+=len;
330 #endif
332 return actual;
335 void
336 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
338 if (munmap(addr,len) == -1) {
339 perror("munmap");
343 os_vm_address_t
344 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
346 os_vm_address_t actual;
348 actual = mmap(addr, len, OS_VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
349 fd, (off_t) offset);
350 if (actual == MAP_FAILED || (addr && (addr != actual))) {
351 perror("mmap");
352 lose("unexpected mmap(..) failure\n");
355 return actual;
358 void
359 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
361 if (mprotect(address, length, prot) == -1) {
362 if (errno == ENOMEM) {
363 lose("An mprotect call failed with ENOMEM. This probably means that the maximum amount\n"
364 "of separate memory mappings was exceeded. To fix the problem, either increase\n"
365 "the maximum with e.g. 'echo 262144 > /proc/sys/vm/max_map_count' or recompile\n"
366 "SBCL with a larger value for GENCGC-PAGE-BYTES in\n"
367 "'src/compiler/target/backend-parms.lisp'.");
368 } else {
369 perror("mprotect");
374 boolean
375 is_valid_lisp_addr(os_vm_address_t addr)
377 struct thread *th;
378 size_t ad = (size_t) addr;
380 if ((READ_ONLY_SPACE_START <= ad && ad < READ_ONLY_SPACE_END)
381 || (STATIC_SPACE_START <= ad && ad < STATIC_SPACE_END)
382 #if defined LISP_FEATURE_GENCGC
383 || (DYNAMIC_SPACE_START <= ad && ad < DYNAMIC_SPACE_END)
384 #else
385 || (DYNAMIC_0_SPACE_START <= ad && ad < DYNAMIC_0_SPACE_END)
386 || (DYNAMIC_1_SPACE_START <= ad && ad < DYNAMIC_1_SPACE_END)
387 #endif
389 return 1;
390 for_each_thread(th) {
391 if((size_t)(th->control_stack_start) <= ad
392 && ad < (size_t)(th->control_stack_end))
393 return 1;
394 if((size_t)(th->binding_stack_start) <= ad
395 && ad < (size_t)(th->binding_stack_start + BINDING_STACK_SIZE))
396 return 1;
398 return 0;
402 * any OS-dependent special low-level handling for signals
406 * The GC needs to be hooked into whatever signal is raised for
407 * page fault on this OS.
409 static void
410 sigsegv_handler(int signal, siginfo_t *info, os_context_t *context)
412 os_vm_address_t addr = arch_get_bad_addr(signal, info, context);
414 #ifdef LISP_FEATURE_ALPHA
415 /* Alpha stuff: This is the end of a pseudo-atomic section during
416 which a signal was received. We must deal with the pending
417 interrupt (see also interrupt.c, ../code/interrupt.lisp)
419 (how we got here: when interrupting, we set bit 63 in reg_ALLOC.
420 At the end of the atomic section we tried to write to reg_ALLOC,
421 got a SIGSEGV (there's nothing mapped there) so ended up here. */
422 if (addr != NULL &&
423 *os_context_register_addr(context, reg_ALLOC) & (1L<<63)) {
424 *os_context_register_addr(context, reg_ALLOC) -= (1L<<63);
425 interrupt_handle_pending(context);
426 return;
428 #endif
430 #ifdef LISP_FEATURE_GENCGC
431 if (!gencgc_handle_wp_violation(addr))
432 #else
433 if (!cheneygc_handle_wp_violation(context, addr))
434 #endif
435 if (!handle_guard_page_triggered(context, addr))
436 lisp_memory_fault_error(context, addr);
439 void
440 os_install_interrupt_handlers(void)
442 undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT,
443 sigsegv_handler);
444 #ifdef LISP_FEATURE_SB_THREAD
445 undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC,
446 sig_stop_for_gc_handler);
447 #endif
450 char *
451 os_get_runtime_executable_path()
453 char path[PATH_MAX + 1];
454 int size;
456 size = readlink("/proc/self/exe", path, sizeof(path)-1);
457 if (size < 0)
458 return NULL;
459 else
460 path[size] = '\0';
462 return copied_string(path);