X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fbsd-os.c;h=4c08b9798a733632d92c32b3eb35abc4c8d247e0;hb=bf40ae88bc289fd765a33861cc4bc0853ed483ba;hp=0ab4fd20464021876487468dd6b42175bd812f8e;hpb=cea4896b2482b7b2b429c1631d774b4cfbc0efba;p=sbcl.git diff --git a/src/runtime/bsd-os.c b/src/runtime/bsd-os.c index 0ab4fd2..4c08b97 100644 --- a/src/runtime/bsd-os.c +++ b/src/runtime/bsd-os.c @@ -21,90 +21,84 @@ #include #include #include +#include +#include +#include +#include +#include "sbcl.h" #include "./signal.h" #include "os.h" #include "arch.h" #include "globals.h" #include "interrupt.h" +#include "interr.h" #include "lispregs.h" -#include "sbcl.h" +#include "thread.h" +#include "runtime.h" +#include "genesis/static-symbols.h" +#include "genesis/fdefn.h" #include #include /* #include */ -#include #include "validate.h" -vm_size_t os_vm_page_size; - -#if defined GENCGC -#include "gencgc.h" +#if defined LISP_FEATURE_GENCGC +#include "gencgc-internal.h" #endif -/* The different BSD variants have diverged in exactly where they - * store signal context information, but at least they tend to use the - * same stems to name the structure fields, so by using this macro we - * can share a fair amount of code between different variants. */ -#if defined __FreeBSD__ -#define CONTEXT_ADDR_FROM_STEM(stem) &context->uc_mcontext.mc_ ## stem -#elif defined __OpenBSD__ -#define CONTEXT_ADDR_FROM_STEM(stem) &context->sc_ ## stem -#else -#error unsupported BSD variant +#if defined(LISP_FEATURE_SB_WTIMER) && !defined(LISP_FEATURE_DARWIN) +# include #endif + -void -os_init(void) -{ - os_vm_page_size = getpagesize(); -} - -/* KLUDGE: There is strong family resemblance in the signal context - * stuff in FreeBSD and OpenBSD, but in detail they're different in - * almost every line of code. It would be nice to find some way to - * factor out the commonality better; failing that, it might be best - * just to split this generic-BSD code into one variant for each BSD. */ - -int * -os_context_register_addr(os_context_t *context, int offset) -{ - switch(offset) { - case 0: - return CONTEXT_ADDR_FROM_STEM(eax); - case 2: - return CONTEXT_ADDR_FROM_STEM(ecx); - case 4: - return CONTEXT_ADDR_FROM_STEM(edx); - case 6: - return CONTEXT_ADDR_FROM_STEM(ebx); - case 8: - return CONTEXT_ADDR_FROM_STEM(esp); - case 10: - return CONTEXT_ADDR_FROM_STEM(ebp); - case 12: - return CONTEXT_ADDR_FROM_STEM(esi); - case 14: - return CONTEXT_ADDR_FROM_STEM(edi); - default: - return 0; - } -} +os_vm_size_t os_vm_page_size; -int * -os_context_pc_addr(os_context_t *context) -{ -#if defined __FreeBSD__ - return CONTEXT_ADDR_FROM_STEM(eip); -#elif defined __OpenBSD__ - return CONTEXT_ADDR_FROM_STEM(pc); -#else -#error unsupported BSD variant +#ifdef __NetBSD__ +#include +#include +#include +#include /* For the stat-family wrappers. */ +#include /* For the opendir()/readdir() wrappers */ +#include /* For the socket() wrapper */ +static void netbsd_init(); +#endif /* __NetBSD__ */ + +#ifdef __FreeBSD__ +#include +#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX) +#include #endif -} -int * -os_context_sp_addr(os_context_t *context) -{ - return CONTEXT_ADDR_FROM_STEM(esp); +static void freebsd_init(); +#endif /* __FreeBSD__ */ + +#ifdef __OpenBSD__ +#include +#include +#include +#include +#include +#ifdef LISP_FEATURE_X86 +#include +#endif + +static void openbsd_init(); +#endif + +void +os_init(char *argv[], char *envp[]) +{ + os_vm_page_size = BACKEND_PAGE_BYTES; + +#ifdef __NetBSD__ + netbsd_init(); +#elif defined(__FreeBSD__) + freebsd_init(); +#elif defined(__OpenBSD__) + openbsd_init(); +#elif defined(LISP_FEATURE_DARWIN) + darwin_init(); +#endif } sigset_t * @@ -113,9 +107,9 @@ os_context_sigmask_addr(os_context_t *context) /* (Unlike most of the other context fields that we access, the * signal mask field is a field of the basic, outermost context * struct itself both in FreeBSD 4.0 and in OpenBSD 2.6.) */ -#if defined __FreeBSD__ +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(LISP_FEATURE_DARWIN) return &context->uc_sigmask; -#elif defined __OpenBSD__ +#elif defined (__OpenBSD__) return &context->sc_mask; #else #error unsupported BSD variant @@ -128,13 +122,13 @@ os_validate(os_vm_address_t addr, os_vm_size_t len) int flags = MAP_PRIVATE | MAP_ANON; if (addr) - flags |= MAP_FIXED; + flags |= MAP_FIXED; addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0); if (addr == MAP_FAILED) { - perror("mmap"); - return NULL; + perror("mmap"); + return NULL; } return addr; @@ -144,35 +138,30 @@ void os_invalidate(os_vm_address_t addr, os_vm_size_t len) { if (munmap(addr, len) == -1) - perror("munmap"); + perror("munmap"); } os_vm_address_t os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len) { addr = mmap(addr, len, - OS_VM_PROT_ALL, - MAP_PRIVATE | MAP_FILE | MAP_FIXED, - fd, (off_t) offset); + OS_VM_PROT_ALL, + MAP_PRIVATE | MAP_FILE | MAP_FIXED, + fd, (off_t) offset); if (addr == MAP_FAILED) { - perror("mmap"); - lose("unexpected mmap(..) failure"); + perror("mmap"); + lose("unexpected mmap(..) failure\n"); } return addr; } void -os_flush_icache(os_vm_address_t address, os_vm_size_t length) -{ -} - -void os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot) { if (mprotect(address, length, prot) == -1) { - perror("mprotect"); + perror("mprotect"); } } @@ -188,335 +177,455 @@ in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen) boolean is_valid_lisp_addr(os_vm_address_t addr) { - return in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE) - || in_range_p(addr, STATIC_SPACE_START , STATIC_SPACE_SIZE ) - || in_range_p(addr, DYNAMIC_SPACE_START , DYNAMIC_SPACE_SIZE ) - || in_range_p(addr, CONTROL_STACK_START , CONTROL_STACK_SIZE ) - || in_range_p(addr, BINDING_STACK_START , BINDING_STACK_SIZE ); + struct thread *th; + + if (in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE) || + in_range_p(addr, STATIC_SPACE_START, STATIC_SPACE_SIZE) || + in_range_p(addr, DYNAMIC_SPACE_START, dynamic_space_size)) + return 1; + for_each_thread(th) { + if (((os_vm_address_t)th->control_stack_start <= addr) && + (addr < (os_vm_address_t)th->control_stack_end)) + return 1; + if (in_range_p(addr, (lispobj) th->binding_stack_start, + BINDING_STACK_SIZE)) + return 1; + } + return 0; } /* * any OS-dependent special low-level handling for signals */ -#if !defined GENCGC - -void -os_install_interrupt_handlers(void) -{} - -#else +#if defined LISP_FEATURE_GENCGC /* * The GENCGC needs to be hooked into whatever signal is raised for * page fault on this OS. */ -static void -memory_fault_handler(int signal, siginfo_t *siginfo, void *void_context) -{ - /* The way that we extract low level information like the fault - * address is not specified by POSIX. */ -#if defined __FreeBSD__ - void *fault_addr = siginfo->si_addr; -#elif defined __OpenBSD__ - void *fault_addr = siginfo->si_addr; -#else -#error unsupported BSD variant -#endif - if (!gencgc_handle_wp_violation(fault_addr)) { - interrupt_handle_now(signal, siginfo, void_context); - } -} + void -os_install_interrupt_handlers(void) +memory_fault_handler(int signal, siginfo_t *siginfo, os_context_t *context) { -#if defined __FreeBSD__ - interrupt_install_low_level_handler(SIGBUS, memory_fault_handler); -#elif defined __OpenBSD__ - interrupt_install_low_level_handler(SIGSEGV, memory_fault_handler); -#else -#error unsupported BSD variant -#endif -} + void *fault_addr = arch_get_bad_addr(signal, siginfo, context); -#endif /* !defined GENCGC */ - -/* - * stuff to help work with dynamically linked libraries - */ - -/* feh! - * - * DL_WORKAROUND enables "stubbing" of various functions from libc et - * al. This is necessary when using dynamic linking in FreeBSD, as the - * symbols in the dynamic libraries will not have known addresses (in - * sbcl.nm). - * - * FIXME: This flag should be set in Config.bsd */ -#if defined __FreeBSD__ -#define DL_WORKAROUND 1 -#elif defined __OpenBSD__ -/* SBCL doesn't (yet?) work at all with dynamic libs on OpenBSD, so we - * wouldn't get any use out of these stubs. -- WHN 20001001 */ -#define DL_WORKAROUND 0 -#else -#error unsupported BSD variant +#if defined(LISP_FEATURE_RESTORE_TLS_SEGMENT_REGISTER_FROM_CONTEXT) + FSHOW_SIGNAL((stderr, "/ TLS: restoring fs: %p in memory_fault_handler\n", + *CONTEXT_ADDR_FROM_STEM(fs))); + os_restore_tls_segment_register(context); #endif -#if DL_WORKAROUND -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + FSHOW((stderr, "Memory fault at: %p, PC: %p\n", fault_addr, *os_context_pc_addr(context))); -void *ldso_stub__dlopen(const char *path, int mode) -{ - return dlopen(path, mode); -} +#ifdef LISP_FEATURE_SB_SAFEPOINT + if (!handle_safepoint_violation(context, fault_addr)) +#endif -void *ldso_stub__dlsym(void *handle, const char *symbol) -{ - return dlsym(handle, symbol); + if (!gencgc_handle_wp_violation(fault_addr)) + if(!handle_guard_page_triggered(context,fault_addr)) + lisp_memory_fault_error(context, fault_addr); } -const char *ldso_stub__dlerror(void) -{ - return dlerror(); -} -int ldso_stub__access(const char *path, int mode) -{ - return access(path, mode); +#if defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) +void +mach_error_memory_fault_handler(int signal, siginfo_t *siginfo, + os_context_t *context) { + lose("Unhandled memory fault. Exiting."); } +#endif -double ldso_stub__acos(double x) +void +os_install_interrupt_handlers(void) { - return acos(x); -} + SHOW("os_install_interrupt_handlers()/bsd-os/defined(GENCGC)"); +#if defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) + undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT, + mach_error_memory_fault_handler); +#else + undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT, +#ifdef LISP_FEATURE_FREEBSD + (__siginfohandler_t *) +#endif + memory_fault_handler); +#endif -double ldso_stub__acosh(double x) -{ - return acosh(x); +#ifdef LISP_FEATURE_SB_THREAD +# ifdef LISP_FEATURE_SB_SAFEPOINT +# ifdef LISP_FEATURE_SB_THRUPTION + undoably_install_low_level_interrupt_handler(SIGPIPE, thruption_handler); +# endif +# else + undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC, + sig_stop_for_gc_handler); +# endif +#endif + SHOW("leaving os_install_interrupt_handlers()"); } -double ldso_stub__asin(double x) -{ - return asin(x); -} +#else /* Currently PPC/Darwin/Cheney only */ -double ldso_stub__asinh(double x) +static void +sigsegv_handler(int signal, siginfo_t *info, os_context_t *context) { - return asin(x); -} +#if 0 + unsigned int pc = (unsigned int *)(*os_context_pc_addr(context)); +#endif + os_vm_address_t addr; -double ldso_stub__atanh(double x) -{ - return atanh(x); + addr = arch_get_bad_addr(signal, info, context); + if (!cheneygc_handle_wp_violation(context, addr)) + if (!handle_guard_page_triggered(context, addr)) + interrupt_handle_now(signal, info, context); } - -int ldso_stub__chdir(const char *path) +void +os_install_interrupt_handlers(void) { - return chdir(path); + SHOW("os_install_interrupt_handlers()/bsd-os/!defined(GENCGC)"); + undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT, + sigsegv_handler); } -int ldso_stub__close(int d) -{ - return close(d); -} +#endif /* defined GENCGC */ -int ldso_stub__closedir(DIR *dirp) +#ifdef __NetBSD__ +static void netbsd_init() { - return closedir(dirp); -} + struct rlimit rl; + int mib[2], osrev; + size_t len; -double ldso_stub__cosh(double x) -{ - return cosh(x); -} + /* Are we running on a sufficiently functional kernel? */ + mib[0] = CTL_KERN; + mib[1] = KERN_OSREV; -void ldso_stub__exit(int status) -{ - exit(status); -} + len = sizeof(osrev); + sysctl(mib, 2, &osrev, &len, NULL, 0); -void ldso_stub__free(void *ptr) -{ - free(ptr); -} + /* If we're older than 2.0... */ + if (osrev < 200000000) { + fprintf(stderr, "osrev = %d (needed at least 200000000).\n", osrev); + lose("NetBSD kernel too old to run sbcl.\n"); + } -int ldso_stub__fstat(int fd, struct stat *sb) -{ - return fstat(fd, sb); + /* NetBSD counts mmap()ed space against the process's data size limit, + * so yank it up. This might be a nasty thing to do? */ + getrlimit (RLIMIT_DATA, &rl); + /* Amazingly for such a new port, the provenance and meaning of + this number are unknown. It might just mean REALLY_BIG_LIMIT, + or possibly it should be calculated from dynamic space size. + -- CSR, 2004-04-08 */ + rl.rlim_cur = 1073741824; + if (setrlimit (RLIMIT_DATA, &rl) < 0) { + fprintf (stderr, + "RUNTIME WARNING: unable to raise process data size limit:\n\ + %s.\n\ +The system may fail to start.\n", + strerror(errno)); + } } -int ldso_stub__fsync(int fd) +/* Various routines in NetBSD's C library are compatibility wrappers + for old versions. Programs must be processed by the C toolchain in + order to get up-to-date definitions of such routines. */ +/* The stat-family, opendir, and readdir are used only in sb-posix, as + of 2007-01-16. -- RMK */ +int +_stat(const char *path, struct stat *sb) { - return fsync(fd); + return stat(path, sb); } - -char *ldso_stub__getenv(const char *name) +int +_lstat(const char *path, struct stat *sb) { - return getenv(name); + return lstat(path, sb); } - -int ldso_stub__gethostname(char *name, int namelen) +int +_fstat(int fd, struct stat *sb) { - return gethostname(name, namelen); + return fstat(fd, sb); } -pid_t ldso_stub__getpid(void) +DIR * +_opendir(const char *filename) { - return getpid(); + return opendir(filename); } - -int ldso_stub__getrusage(int who, struct rusage *rusage) +struct dirent * +_readdir(DIR *dirp) { - return getrusage(who, rusage); + return readdir(dirp); } -int ldso_stub__gettimeofday(struct timeval *tp, struct timezone *tzp) +int +_utime(const char *file, const struct utimbuf *timep) { - return gettimeofday(tp, tzp); + return utime(file, timep); } -uid_t ldso_stub__getuid(void) +/* Used in sb-bsd-sockets. */ +int +_socket(int domain, int type, int protocol) { - return getuid(); + return socket(domain, type, protocol); } +#endif /* __NetBSD__ */ -char *ldso_stub__getwd(char *buf) -{ - return getwd(buf); -} +#ifdef __FreeBSD__ +extern int getosreldate(void); -double ldso_stub__hypot(double x, double y) -{ - return hypot(x, y); -} +int sig_memory_fault; -int ldso_stub__kill(pid_t pid, int sig) +static void freebsd_init() { - return kill(pid, sig); -} + /* Memory fault signal on FreeBSD was changed from SIGBUS to + * SIGSEGV. */ + if (getosreldate() < 700004) + sig_memory_fault = SIGBUS; + else + sig_memory_fault = SIGSEGV; -int ldso_stub__killpg(pid_t pgrp, int sig) -{ - return killpg(pgrp, sig); -} + /* Quote from sbcl-devel (NIIMI Satoshi): "Some OSes, like FreeBSD + * 4.x with GENERIC kernel, does not enable SSE support even on + * SSE capable CPUs". Detect this situation and skip the + * fast_bzero sse/base selection logic that's normally done in + * x86-assem.S. + */ +#ifdef LISP_FEATURE_X86 + { + size_t len; + int instruction_sse; -off_t ldso_stub__lseek(int fildes, off_t offset, int whence) -{ - return lseek(fildes, offset, whence); + len = sizeof(instruction_sse); + if (sysctlbyname("hw.instruction_sse", &instruction_sse, &len, + NULL, 0) == 0 && instruction_sse != 0) { + /* Use the SSE detector */ + fast_bzero_pointer = fast_bzero_detect; + } + } +#endif /* LISP_FEATURE_X86 */ } -int ldso_stub__lstat(const char *path, struct stat *sb) +#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_FUTEX) \ + && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX) +int +futex_wait(int *lock_word, long oldval, long sec, unsigned long usec) { - return lstat(path, sb); -} + struct timespec timeout; + int ret; -void *ldso_stub__malloc(size_t size) -{ - return malloc(size); -} + if (sec < 0) + ret = umtx_wait((void *)lock_word, oldval, NULL); + else { + timeout.tv_sec = sec; + timeout.tv_nsec = usec * 1000; + ret = umtx_wait((void *)lock_word, oldval, &timeout); + } -int ldso_stub__mkdir(const char *path, mode_t mode) -{ - return mkdir(path, mode); + switch (ret) { + case 0: + return 0; + case ETIMEDOUT: + return 1; + case EINTR: + return 2; + default: + /* EWOULDBLOCK and others, need to check the lock */ + return -1; + } } -int ldso_stub__open(const char *path, int flags, mode_t mode) +int +futex_wake(int *lock_word, int n) { - return open(path, flags, mode); + return umtx_wake((void *)lock_word, n); } +#endif +#endif /* __FreeBSD__ */ -DIR *ldso_stub__opendir(const char *filename) -{ - return opendir(filename); -} +#ifdef LISP_FEATURE_DARWIN +/* defined in ppc-darwin-os.c instead */ +#elif defined(LISP_FEATURE_FREEBSD) +#ifndef KERN_PROC_PATHNAME +#define KERN_PROC_PATHNAME 12 +#endif -double ldso_stub__pow(double x, double y) -{ - return pow(x, y); +char * +os_get_runtime_executable_path(int external) +{ + char path[PATH_MAX + 1]; + + if (getosreldate() >= 600024) { + /* KERN_PROC_PATHNAME is available */ + size_t len = PATH_MAX + 1; + int mib[4]; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + if (sysctl(mib, 4, &path, &len, NULL, 0) != 0) + return NULL; + } else { + int size; + size = readlink("/proc/curproc/file", path, sizeof(path) - 1); + if (size < 0) + return NULL; + path[size] = '\0'; + } + if (strcmp(path, "unknown") == 0) + return NULL; + return copied_string(path); } - -ssize_t ldso_stub__read(int d, void *buf, size_t nbytes) +#elif defined(LISP_FEATURE_NETBSD) || defined(LISP_FEATURE_OPENBSD) +char * +os_get_runtime_executable_path(int external) { - return read(d, buf, nbytes); + struct stat sb; + if (!external && stat("/proc/curproc/file", &sb) == 0) + return copied_string("/proc/curproc/file"); + return NULL; } - -struct dirent *ldso_stub__readdir(DIR *dirp) +#else /* Not DARWIN or FREEBSD or NETBSD or OPENBSD */ +char * +os_get_runtime_executable_path(int external) { - return readdir(dirp); + return NULL; } +#endif -int ldso_stub__readlink(const char *path, char *buf, int bufsiz) -{ - return readlink(path, buf, bufsiz); -} +#ifdef __OpenBSD__ -int ldso_stub__rename(const char *from, const char *to) -{ - return rename(from, to); -} +int openbsd_use_fxsave = 0; -int ldso_stub__select(int nfds, fd_set *readfs, fd_set *writefds, - fd_set *exceptfds, struct timeval *timeout) +void +openbsd_init() { - return select(nfds, readfs, writefds, exceptfds, timeout); -} +#ifdef LISP_FEATURE_X86 + int mib[2]; + size_t size; +#endif + /* + * Show a warning if it looks like the memory available after + * allocating the spaces won't be at least this much. + */ +#ifdef LISP_FEATURE_X86_64 + const int wantfree = 64 * 1024 * 1024; +#else + const int wantfree = 32 * 1024 * 1024; +#endif + struct rlimit rl; + +#ifdef LISP_FEATURE_X86 + /* Save the machdep.osfxsr sysctl for use by os_restore_fp_control() */ + mib[0] = CTL_MACHDEP; + mib[1] = CPU_OSFXSR; + size = sizeof (openbsd_use_fxsave); + sysctl(mib, 2, &openbsd_use_fxsave, &size, NULL, 0); +#endif -int ldso_stub__sigblock(int mask) -{ - return sigblock(mask); -} + /* OpenBSD, like NetBSD, counts mmap()ed space against the + * process's data size limit. If the soft limit is lower than the + * hard limit then try to yank it up, this lets users in the + * "staff" or "daemon" login classes run sbcl with larger dynamic + * space sizes. + */ + getrlimit (RLIMIT_DATA, &rl); + if (rl.rlim_cur < rl.rlim_max) { + rl.rlim_cur = rl.rlim_max; + if (setrlimit (RLIMIT_DATA, &rl) < 0) { + fprintf (stderr, + "RUNTIME WARNING: unable to raise process data size limit:\n\ + %s.\n\ +The system may fail to start.\n", + strerror(errno)); + } + } -int ldso_stub__sigpause(int sigmask) -{ - return sigpause(sigmask); + /* + * Display a (hopefully) helpful warning if it looks like we won't + * be able to allocate enough memory. + */ + getrlimit (RLIMIT_DATA, &rl); + if (dynamic_space_size + READ_ONLY_SPACE_SIZE + STATIC_SPACE_SIZE + + LINKAGE_TABLE_SPACE_SIZE + wantfree > rl.rlim_cur) + fprintf (stderr, + "RUNTIME WARNING: data size resource limit may be too low,\n" + " try decreasing the dynamic space size with --dynamic-space-size\n" + " or raising the datasize or datasize-max limits in /etc/login.conf\n"); +} + +/* OpenBSD's dlsym() relies on the gcc bulitin + * __builtin_return_address(0) returning an address in the + * executable's text segment, but when called from lisp it will return + * an address in the dynamic space. Work around this by calling this + * wrapper function instead. Note that tail-call optimization will + * defeat this, disable it by saving the dlsym() return value in a + * volatile variable. +*/ +void * +os_dlsym(void *handle, const char *symbol) +{ + void * volatile ret = dlsym(handle, symbol); + return ret; } -int ldso_stub__sigsetmask(int mask) -{ - return sigsetmask(mask); -} +#endif -double ldso_stub__sinh(double x) +#if defined(LISP_FEATURE_SB_WTIMER) && !defined(LISP_FEATURE_DARWIN) +/* + * Waitable timer implementation for the safepoint-based (SIGALRM-free) + * timer facility using kqueue. + */ +int +os_create_wtimer() { - return sin(x); + int kq = kqueue(); + if (kq == -1) + lose("os_create_wtimer: kqueue"); + return kq; } -int ldso_stub__stat(const char *path, struct stat *sb) +int +os_wait_for_wtimer(int kq) { - return stat(path, sb); + struct kevent ev; + int n; + if ( (n = kevent(kq, 0, 0, &ev, 1, 0)) == -1) { + if (errno != EINTR) + lose("os_wtimer_listen failed"); + n = 0; + } + return n != 1; } -double ldso_stub__tanh(double x) +void +os_close_wtimer(int kq) { - return tanh(x); + if (close(kq) == -1) + lose("os_close_wtimer failed"); } -/* tzname */ - -int ldso_stub__unlink(const char *path) +void +os_set_wtimer(int kq, int sec, int nsec) { - return unlink(path); -} + long long msec + = ((long long) sec) * 1000 + (long long) (nsec+999999) / 1000000; + if (msec > INT_MAX) msec = INT_MAX; -ssize_t ldso_stub__write(int d, const void *buf, size_t nbytes) -{ - return write(d, buf, nbytes); + struct kevent ev; + EV_SET(&ev, 1, EVFILT_TIMER, EV_ADD|EV_ENABLE|EV_ONESHOT, 0, (int)msec, 0); + if (kevent(kq, &ev, 1, 0, 0, 0) == -1) + perror("os_set_wtimer: kevent"); } -pid_t ldso_stub__wait3(int *status, int options, struct rusage *rusage) +void +os_cancel_wtimer(int kq) { - return wait3(status, options, rusage); + struct kevent ev; + EV_SET(&ev, 1, EVFILT_TIMER, EV_DISABLE, 0, 0, 0); + if (kevent(kq, &ev, 1, 0, 0, 0) == -1 && errno != ENOENT) + perror("os_cancel_wtimer: kevent"); } - -#endif /* DL_WORKAROUND */ +#endif