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
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.
24 #include <sys/param.h>
31 #include "interrupt.h"
35 #include "genesis/static-symbols.h"
36 #include "genesis/fdefn.h"
38 #include <sys/socket.h>
39 #include <sys/utsname.h>
42 #include <sys/types.h>
44 /* #include <sys/sysinfo.h> */
48 #include <linux/version.h>
53 #if defined LISP_FEATURE_GENCGC
54 #include "gencgc-internal.h"
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);
63 size_t os_vm_page_size;
65 #if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_LUTEX)
66 #include <sys/syscall.h>
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
73 #define FUTEX_WAIT (0)
74 #define FUTEX_WAKE (1)
76 #define FUTEX_REQUEUE (3)
78 #define sys_futex sbcl_sys_futex
79 static inline int sys_futex (void *futex, int op, int val, struct timespec *rel)
81 return syscall (SYS_futex, futex, op, val, rel);
85 futex_wait(int *lock_word, int oldval)
89 t = sys_futex(lock_word,FUTEX_WAIT,oldval, 0);
91 /* Interrupted FUTEX_WAIT calls may return early.
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)
103 futex_wake(int *lock_word, int n)
105 return sys_futex(lock_word,FUTEX_WAKE,n,0);
110 int linux_sparc_siginfo_bug = 0;
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.
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
125 int linux_no_threads_p = 0;
127 #ifdef LISP_FEATURE_SB_THREAD
131 size_t n = confstr (_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
133 char *buf = alloca (n);
134 confstr (_CS_GNU_LIBPTHREAD_VERSION, buf, n);
135 if (strstr (buf, "NPTL")) {
144 os_init(char *argv[], char *envp[])
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)
158 major_version = atoi(p);
160 minor_version = atoi(p);
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",
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;
173 #ifdef LISP_FEATURE_SB_THREAD
174 #if !defined(LISP_FEATURE_SB_LUTEX)
175 futex_wait(futex,-1);
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");
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");
188 os_vm_page_size = getpagesize();
190 /* KLUDGE: Disable memory randomization on new Linux kernels
191 * by setting a personality flag and re-executing. (We need
192 * to re-execute, since the memory maps that can conflict with
193 * the SBCL spaces have already been done at this point).
195 * Since randomization is currently implemented only on x86 kernels,
196 * don't do this trick on other platforms.
198 #ifdef LISP_FEATURE_X86
199 if ((major_version == 2
200 /* Some old kernels will apparently lose unsupported personality flags
202 && ((minor_version == 6 && patch_version >= 11)
203 || (minor_version > 6)))
204 || major_version >= 3)
206 int pers = personality(0xffffffffUL);
207 /* 0x40000 aka. ADDR_NO_RANDOMIZE */
208 if (!(pers & 0x40000)) {
209 int retval = personality(pers | 0x40000);
210 /* Allegedly some Linux kernels (the reported case was
211 * "hardened Linux 2.6.7") won't set the new personality,
212 * but nor will they return -1 for an error. So as a
213 * workaround query the new personality...
215 int newpers = personality(0xffffffffUL);
216 /* ... and don't re-execute if either the setting resulted
217 * in an error or if the value didn't change. Otherwise
218 * this might result in an infinite loop.
220 if (retval != -1 && newpers != pers) {
221 /* Use /proc/self/exe instead of trying to figure out
222 * the executable path from PATH and argv[0], since
223 * that's unreliable. We follow the symlink instead of
224 * executing the file directly in order to prevent top
225 * from displaying the name of the process as "exe". */
226 char runtime[PATH_MAX+1];
227 int i = readlink("/proc/self/exe", runtime, PATH_MAX);
230 execve(runtime, argv, envp);
233 /* Either changing the personality or execve() failed. Either
234 * way we might as well continue, and hope that the random
235 * memory maps are ok this time around.
237 fprintf(stderr, "WARNING: Couldn't re-execute SBCL with the proper personality flags (maybe /proc isn't mounted?). Trying to continue anyway.\n");
240 /* Use SSE detector. Recent versions of Linux enable SSE support
241 * on SSE capable CPUs. */
242 /* FIXME: Are there any old versions that does not support SSE? */
243 fast_bzero_pointer = fast_bzero_detect;
248 #ifdef LISP_FEATURE_ALPHA
249 /* The Alpha is a 64 bit CPU. SBCL is a 32 bit application. Due to all
250 * the places that assume we can get a pointer into a fixnum with no
251 * information loss, we have to make sure it allocates all its ram in the
254 static void * under_2gb_free_pointer=DYNAMIC_1_SPACE_END;
258 os_validate(os_vm_address_t addr, os_vm_size_t len)
260 int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
261 os_vm_address_t actual;
263 #ifdef LISP_FEATURE_ALPHA
265 addr=under_2gb_free_pointer;
268 actual = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
269 if (actual == MAP_FAILED) {
271 return 0; /* caller should check this */
274 if (addr && (addr!=actual)) {
275 fprintf(stderr, "mmap: wanted %lu bytes at %p, actually mapped at %p\n",
276 (unsigned long) len, addr, actual);
280 #ifdef LISP_FEATURE_ALPHA
282 len=(len+(os_vm_page_size-1))&(~(os_vm_page_size-1));
283 under_2gb_free_pointer+=len;
290 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
292 if (munmap(addr,len) == -1) {
298 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
300 os_vm_address_t actual;
302 actual = mmap(addr, len, OS_VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
304 if (actual == MAP_FAILED || (addr && (addr != actual))) {
306 lose("unexpected mmap(..) failure\n");
313 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
315 if (mprotect(address, length, prot) == -1) {
316 if (errno == ENOMEM) {
317 lose("An mprotect call failed with ENOMEM. This probably means that the maximum amount\n"
318 "of separate memory mappings was exceeded. To fix the problem, either increase\n"
319 "the maximum with e.g. 'echo 262144 > /proc/sys/vm/max_map_count' or recompile\n"
320 "SBCL with a larger value for GENCGC-PAGE-SIZE in 'src/target/parms.lisp'.");
328 is_valid_lisp_addr(os_vm_address_t addr)
331 size_t ad = (size_t) addr;
333 if ((READ_ONLY_SPACE_START <= ad && ad < READ_ONLY_SPACE_END)
334 || (STATIC_SPACE_START <= ad && ad < STATIC_SPACE_END)
335 #if defined LISP_FEATURE_GENCGC
336 || (DYNAMIC_SPACE_START <= ad && ad < DYNAMIC_SPACE_END)
338 || (DYNAMIC_0_SPACE_START <= ad && ad < DYNAMIC_0_SPACE_END)
339 || (DYNAMIC_1_SPACE_START <= ad && ad < DYNAMIC_1_SPACE_END)
343 for_each_thread(th) {
344 if((size_t)(th->control_stack_start) <= ad
345 && ad < (size_t)(th->control_stack_end))
347 if((size_t)(th->binding_stack_start) <= ad
348 && ad < (size_t)(th->binding_stack_start + BINDING_STACK_SIZE))
355 * any OS-dependent special low-level handling for signals
359 * The GC needs to be hooked into whatever signal is raised for
360 * page fault on this OS.
363 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
365 os_context_t *context = arch_os_get_context(&void_context);
366 os_vm_address_t addr = arch_get_bad_addr(signal, info, context);
368 #ifdef LISP_FEATURE_ALPHA
369 /* Alpha stuff: This is the end of a pseudo-atomic section during
370 which a signal was received. We must deal with the pending
371 interrupt (see also interrupt.c, ../code/interrupt.lisp)
373 (how we got here: when interrupting, we set bit 63 in reg_ALLOC.
374 At the end of the atomic section we tried to write to reg_ALLOC,
375 got a SIGSEGV (there's nothing mapped there) so ended up here. */
377 *os_context_register_addr(context, reg_ALLOC) & (1L<<63)) {
378 *os_context_register_addr(context, reg_ALLOC) -= (1L<<63);
379 interrupt_handle_pending(context);
384 #ifdef LISP_FEATURE_GENCGC
385 if (!gencgc_handle_wp_violation(addr))
387 if (!interrupt_maybe_gc(signal, info, context))
389 if (!handle_guard_page_triggered(context, addr))
390 #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
391 arrange_return_to_lisp_function(context, SymbolFunction(MEMORY_FAULT_ERROR));
393 interrupt_handle_now(signal, info, context);
398 os_install_interrupt_handlers(void)
400 undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT,
402 #ifdef LISP_FEATURE_SB_THREAD
403 undoably_install_low_level_interrupt_handler(SIG_INTERRUPT_THREAD,
404 interrupt_thread_handler);
405 undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC,
406 sig_stop_for_gc_handler);
411 os_get_runtime_executable_path()
413 char path[PATH_MAX + 1];
416 size = readlink("/proc/self/exe", path, sizeof(path)-1);
422 return copied_string(path);