Remove more disassembler bogosity
[sbcl.git] / src / runtime / linux-os.c
blob95e8cfa180a37bfd910848a1575c2a47ac54bdfc
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
58 #include <fcntl.h>
59 #ifdef LISP_FEATURE_SB_WTIMER
60 # include <sys/timerfd.h>
61 #endif
63 #ifdef LISP_FEATURE_X86
64 /* Prototype for personality(2). Done inline here since the header file
65 * for this isn't available on old versions of glibc. */
66 int personality (unsigned long);
67 #define ADDR_NO_RANDOMIZE 0x0040000
68 #else
69 #include <sys/personality.h>
70 #endif
72 size_t os_vm_page_size;
74 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_FUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX)
75 #include <sys/syscall.h>
76 #include <unistd.h>
77 #include <errno.h>
79 /* values taken from the kernel's linux/futex.h. This header file
80 doesn't exist in userspace, which is our excuse for not grovelling
81 them automatically */
82 #define FUTEX_WAIT 0
83 #define FUTEX_WAKE 1
84 /* This is also copied from linux/futex.h so that a binary compiled on
85 * a not so recent Linux system can still take advantage of private
86 * futexes when available.*/
87 #define FUTEX_WAIT_PRIVATE (0+128)
88 #define FUTEX_WAKE_PRIVATE (1+128)
89 #define FUTEX_FD (2)
90 #define FUTEX_REQUEUE (3)
92 /* Not static so that Lisp may query it. */
93 boolean futex_private_supported_p;
95 static inline int
96 futex_wait_op()
98 return (futex_private_supported_p ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT);
101 static inline int
102 futex_wake_op()
104 return (futex_private_supported_p ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE);
107 static inline int sys_futex(void *futex, int op, int val, struct timespec *rel)
109 return syscall(SYS_futex, futex, op, val, rel);
112 static void
113 futex_init()
115 int x = 0;
116 sys_futex(&x, FUTEX_WAIT, 1, 0);
117 if (errno == ENOSYS)
118 lose("This version of SBCL is compiled with threading support, but your kernel\n"
119 "is too old to support this. Please use a more recent kernel or\n"
120 "a version of SBCL without threading support.\n");
121 sys_futex(&x, FUTEX_WAIT_PRIVATE, 1, 0);
122 if (errno == EWOULDBLOCK) {
123 futex_private_supported_p = 1;
124 } else {
125 futex_private_supported_p = 0;
126 SHOW("No futex private suppport\n");
131 futex_wait(int *lock_word, int oldval, long sec, unsigned long usec)
133 struct timespec timeout;
134 int t;
136 if (sec<0) {
137 t = sys_futex(lock_word, futex_wait_op(), oldval, 0);
139 else {
140 timeout.tv_sec = sec;
141 timeout.tv_nsec = usec * 1000;
142 t = sys_futex(lock_word, futex_wait_op(), oldval, &timeout);
144 if (t==0)
145 return 0;
146 else if (errno==ETIMEDOUT)
147 return 1;
148 else if (errno==EINTR)
149 return 2;
150 else
151 /* EWOULDBLOCK and others, need to check the lock */
152 return -1;
156 futex_wake(int *lock_word, int n)
158 return sys_futex(lock_word, futex_wake_op(),n,0);
160 #endif
163 int linux_sparc_siginfo_bug = 0;
165 /* This variable was in real use for a few months, basically for
166 * storing autodetected information about whether the Linux
167 * installation was recent enough to support SBCL threads, and make
168 * some run-time decisions based on that. But this turned out to be
169 * unstable, so now we just flat-out refuse to start on the old installations
170 * when thread support has been compiled in.
172 * Unfortunately, in the meanwhile Slime started depending on this
173 * variable for deciding which communication style to use. So even
174 * though this variable looks unused, it shouldn't be deleted until
175 * it's no longer used in the versions of Slime that people are
176 * likely to download first. -- JES, 2006-06-07
178 int linux_no_threads_p = 0;
180 #ifdef LISP_FEATURE_SB_THREAD
182 isnptl (void)
184 size_t n = confstr (_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
185 if (n > 0) {
186 char *buf = alloca (n);
187 confstr (_CS_GNU_LIBPTHREAD_VERSION, buf, n);
188 if (strstr (buf, "NPTL")) {
189 return 1;
192 return 0;
194 #endif
196 void
197 os_init(char *argv[], char *envp[])
199 /* Conduct various version checks: do we have enough mmap(), is
200 * this a sparc running 2.2, can we do threads? */
201 struct utsname name;
202 int major_version;
203 int minor_version;
204 int patch_version;
205 char *p;
206 uname(&name);
208 p=name.release;
209 major_version = atoi(p);
210 minor_version = patch_version = 0;
211 p=strchr(p,'.');
212 if (p != NULL) {
213 minor_version = atoi(++p);
214 p=strchr(p,'.');
215 if (p != NULL)
216 patch_version = atoi(++p);
219 if (major_version<2) {
220 lose("linux kernel version too old: major version=%d (can't run in version < 2.0.0)\n",
221 major_version);
223 if (!(major_version>2 || minor_version >= 4)) {
224 #ifdef LISP_FEATURE_SPARC
225 FSHOW((stderr,"linux kernel %d.%d predates 2.4;\n enabling workarounds for SPARC kernel bugs in signal handling.\n", major_version,minor_version));
226 linux_sparc_siginfo_bug = 1;
227 #endif
229 #ifdef LISP_FEATURE_SB_THREAD
230 #if defined(LISP_FEATURE_SB_FUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX)
231 futex_init();
232 #endif
233 if(! isnptl()) {
234 lose("This version of SBCL only works correctly with the NPTL threading\n"
235 "library. Please use a newer glibc, use an older SBCL, or stop using\n"
236 "LD_ASSUME_KERNEL\n");
238 #endif
240 /* Don't use getpagesize(), since it's not constant across Linux
241 * kernel versions on some architectures (for example PPC). FIXME:
242 * possibly the same should be done on other architectures too.
244 os_vm_page_size = BACKEND_PAGE_BYTES;
246 /* KLUDGE: Disable memory randomization on new Linux kernels
247 * by setting a personality flag and re-executing. (We need
248 * to re-execute, since the memory maps that can conflict with
249 * the SBCL spaces have already been done at this point).
251 * Since randomization is currently implemented only on x86 kernels,
252 * don't do this trick on other platforms.
254 #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)
255 if ((major_version == 2
256 /* Some old kernels will apparently lose unsupported personality flags
257 * on exec() */
258 && ((minor_version == 6 && patch_version >= 11)
259 || (minor_version > 6)
260 /* This is what RHEL 3 reports */
261 || (minor_version == 4 && patch_version > 20)))
262 || major_version >= 3)
264 int pers = personality(0xffffffffUL);
265 if (!(pers & ADDR_NO_RANDOMIZE)) {
266 int retval = personality(pers | ADDR_NO_RANDOMIZE);
267 /* Allegedly some Linux kernels (the reported case was
268 * "hardened Linux 2.6.7") won't set the new personality,
269 * but nor will they return -1 for an error. So as a
270 * workaround query the new personality...
272 int newpers = personality(0xffffffffUL);
273 /* ... and don't re-execute if either the setting resulted
274 * in an error or if the value didn't change. Otherwise
275 * this might result in an infinite loop.
278 if (!getenv("SBCL_IS_RESTARTING") &&
279 retval != -1 && newpers != pers) {
280 /* Use /proc/self/exe instead of trying to figure out
281 * the executable path from PATH and argv[0], since
282 * that's unreliable. We follow the symlink instead of
283 * executing the file directly in order to prevent top
284 * from displaying the name of the process as "exe". */
285 char runtime[PATH_MAX+1];
286 int i = readlink("/proc/self/exe", runtime, PATH_MAX);
287 if (i != -1) {
288 environ = envp;
289 setenv("SBCL_IS_RESTARTING", "T", 1);
290 runtime[i] = '\0';
291 execv(runtime, argv);
294 /* Either changing the personality or execve() failed. Either
295 * way we might as well continue, and hope that the random
296 * memory maps are ok this time around.
298 fprintf(stderr, "WARNING:\
299 \nCouldn't re-execute SBCL with proper personality flags (/proc isn't mounted? setuid?)\
300 \nTrying to continue anyway.\n");
301 } else if (getenv("SBCL_IS_RESTARTING")) {
302 /* We restarted due to previously enabled ASLR. Now,
303 * reenable it for fork()'ed children. */
304 int pers = personality(0xffffffffUL);
305 personality(pers & ~ADDR_NO_RANDOMIZE);
307 unsetenv("SBCL_IS_RESTARTING");
310 #ifdef LISP_FEATURE_X86
311 /* Use SSE detector. Recent versions of Linux enable SSE support
312 * on SSE capable CPUs. */
313 /* FIXME: Are there any old versions that does not support SSE? */
314 fast_bzero_pointer = fast_bzero_detect;
315 #endif
316 #endif
320 #ifdef LISP_FEATURE_ALPHA
321 /* The Alpha is a 64 bit CPU. SBCL is a 32 bit application. Due to all
322 * the places that assume we can get a pointer into a fixnum with no
323 * information loss, we have to make sure it allocates all its ram in the
324 * 0-2Gb region. */
326 static void * under_2gb_free_pointer=DYNAMIC_1_SPACE_END;
327 #endif
329 os_vm_address_t
330 os_validate(os_vm_address_t addr, os_vm_size_t len)
332 int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
333 os_vm_address_t actual;
335 #ifdef LISP_FEATURE_ALPHA
336 if (!addr) {
337 addr=under_2gb_free_pointer;
339 #endif
340 actual = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
341 if (actual == MAP_FAILED) {
342 perror("mmap");
343 return 0; /* caller should check this */
346 if (addr && (addr!=actual)) {
347 fprintf(stderr, "mmap: wanted %lu bytes at %p, actually mapped at %p\n",
348 (unsigned long) len, addr, actual);
349 return 0;
352 #ifdef LISP_FEATURE_ALPHA
354 len=(len+(os_vm_page_size-1))&(~(os_vm_page_size-1));
355 under_2gb_free_pointer+=len;
356 #endif
358 return actual;
361 void
362 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
364 if (munmap(addr,len) == -1) {
365 perror("munmap");
369 os_vm_address_t
370 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
372 os_vm_address_t actual;
374 actual = mmap(addr, len, OS_VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
375 fd, (off_t) offset);
376 if (actual == MAP_FAILED || (addr && (addr != actual))) {
377 perror("mmap");
378 lose("unexpected mmap(..) failure\n");
381 return actual;
384 void
385 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
387 if (mprotect(address, length, prot) == -1) {
388 if (errno == ENOMEM) {
389 lose("An mprotect call failed with ENOMEM. This probably means that the maximum amount\n"
390 "of separate memory mappings was exceeded. To fix the problem, either increase\n"
391 "the maximum with e.g. 'echo 262144 > /proc/sys/vm/max_map_count' or recompile\n"
392 "SBCL with a larger value for GENCGC-CARD-BYTES in\n"
393 "'src/compiler/target/backend-parms.lisp'.");
394 } else {
395 perror("mprotect");
400 boolean
401 is_valid_lisp_addr(os_vm_address_t addr)
403 struct thread *th;
404 size_t ad = (size_t) addr;
406 if ((READ_ONLY_SPACE_START <= ad && ad < READ_ONLY_SPACE_END)
407 || (STATIC_SPACE_START <= ad && ad < STATIC_SPACE_END)
408 #if defined LISP_FEATURE_GENCGC
409 || (DYNAMIC_SPACE_START <= ad && ad < DYNAMIC_SPACE_END)
410 #else
411 || (DYNAMIC_0_SPACE_START <= ad && ad < DYNAMIC_0_SPACE_END)
412 || (DYNAMIC_1_SPACE_START <= ad && ad < DYNAMIC_1_SPACE_END)
413 #endif
415 return 1;
416 for_each_thread(th) {
417 if((size_t)(th->control_stack_start) <= ad
418 && ad < (size_t)(th->control_stack_end))
419 return 1;
420 if((size_t)(th->binding_stack_start) <= ad
421 && ad < (size_t)(th->binding_stack_start + BINDING_STACK_SIZE))
422 return 1;
424 return 0;
428 * any OS-dependent special low-level handling for signals
432 * The GC needs to be hooked into whatever signal is raised for
433 * page fault on this OS.
435 static void
436 sigsegv_handler(int signal, siginfo_t *info, os_context_t *context)
438 os_vm_address_t addr = arch_get_bad_addr(signal, info, context);
440 #ifdef LISP_FEATURE_ALPHA
441 /* Alpha stuff: This is the end of a pseudo-atomic section during
442 which a signal was received. We must deal with the pending
443 interrupt (see also interrupt.c, ../code/interrupt.lisp)
445 (how we got here: when interrupting, we set bit 63 in reg_ALLOC.
446 At the end of the atomic section we tried to write to reg_ALLOC,
447 got a SIGSEGV (there's nothing mapped there) so ended up here. */
448 if (addr != NULL &&
449 *os_context_register_addr(context, reg_ALLOC) & (1L<<63)) {
450 *os_context_register_addr(context, reg_ALLOC) -= (1L<<63);
451 interrupt_handle_pending(context);
452 return;
454 #endif
456 #ifdef LISP_FEATURE_SB_SAFEPOINT
457 if (!handle_safepoint_violation(context, addr))
458 #endif
460 #ifdef LISP_FEATURE_GENCGC
461 if (!gencgc_handle_wp_violation(addr))
462 #else
463 if (!cheneygc_handle_wp_violation(context, addr))
464 #endif
465 if (!handle_guard_page_triggered(context, addr))
466 lisp_memory_fault_error(context, addr);
469 void
470 os_install_interrupt_handlers(void)
472 undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT,
473 sigsegv_handler);
475 /* OAOOM c.f. sunos-os.c.
476 * Should we have a reusable function gc_install_interrupt_handlers? */
477 #ifdef LISP_FEATURE_SB_THREAD
478 # ifdef LISP_FEATURE_SB_SAFEPOINT
479 # ifdef LISP_FEATURE_SB_THRUPTION
480 undoably_install_low_level_interrupt_handler(SIGPIPE, thruption_handler);
481 # endif
482 # else
483 undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC,
484 sig_stop_for_gc_handler);
485 # endif
486 #endif
489 char *
490 os_get_runtime_executable_path(int external)
492 char path[PATH_MAX + 1];
493 int size;
495 size = readlink("/proc/self/exe", path, sizeof(path)-1);
496 if (size < 0)
497 return NULL;
498 else
499 path[size] = '\0';
501 return copied_string(path);
504 #ifdef LISP_FEATURE_SB_WTIMER
506 * Waitable timer implementation for the safepoint-based (SIGALRM-free)
507 * timer facility using timerfd_create().
510 os_create_wtimer()
512 int fd = timerfd_create(CLOCK_MONOTONIC, 0);
513 if (fd == -1)
514 lose("os_create_wtimer: timerfd_create");
516 /* Cannot count on TFD_CLOEXEC availability, so do it manually: */
517 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
518 lose("os_create_wtimer: fcntl");
520 return fd;
524 os_wait_for_wtimer(int fd)
526 unsigned char buf[8];
527 int n = read(fd, buf, sizeof(buf));
528 if (n == -1) {
529 if (errno == EINTR)
530 return -1;
531 lose("os_wtimer_listen failed");
533 if (n != sizeof(buf))
534 lose("os_wtimer_listen read too little");
535 return 0;
538 void
539 os_close_wtimer(int fd)
541 if (close(fd) == -1)
542 lose("os_close_wtimer failed");
545 void
546 os_set_wtimer(int fd, int sec, int nsec)
548 struct itimerspec spec = { {0,0}, {0,0} };
549 spec.it_value.tv_sec = sec;
550 spec.it_value.tv_nsec = nsec;
551 if (timerfd_settime(fd, 0, &spec, 0) == -1)
552 lose("timerfd_settime");
555 void
556 os_cancel_wtimer(int fd)
558 os_set_wtimer(fd, 0, 0);
560 #endif