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