diff --git a/lib/libc/amd64/sys/Makefile.inc b/lib/libc/amd64/sys/Makefile.inc index c7b17e06121e..51583d35b74c 100644 --- a/lib/libc/amd64/sys/Makefile.inc +++ b/lib/libc/amd64/sys/Makefile.inc @@ -1,7 +1,8 @@ # from: Makefile.inc,v 1.1 1993/09/03 19:04:23 jtc Exp # $FreeBSD$ -SRCS+= amd64_get_fsbase.c amd64_get_gsbase.c amd64_set_fsbase.c amd64_set_gsbase.c +SRCS+= amd64_get_fsbase.c amd64_get_gsbase.c amd64_set_fsbase.c \ + amd64_set_gsbase.c __vdso_gettc.c MDASM= vfork.S brk.S cerror.S exect.S getcontext.S pipe.S ptrace.S \ reboot.S sbrk.S setlogin.S sigreturn.S diff --git a/lib/libc/amd64/sys/__vdso_gettc.c b/lib/libc/amd64/sys/__vdso_gettc.c new file mode 100644 index 000000000000..091fe26d3ba7 --- /dev/null +++ b/lib/libc/amd64/sys/__vdso_gettc.c @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2012 Konstantin Belousov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +static u_int +__vdso_gettc_low(const struct vdso_timehands *th) +{ + uint32_t rv; + + __asm __volatile("rdtsc; shrd %%cl, %%edx, %0" + : "=a" (rv) : "c" (th->th_x86_shift) : "edx"); + return (rv); +} + +u_int +__vdso_gettc(const struct vdso_timehands *th) +{ + + return (th->th_x86_shift > 0 ? __vdso_gettc_low(th) : rdtsc32()); +} diff --git a/lib/libc/gen/aux.c b/lib/libc/gen/aux.c index 4bf8643af166..3767ac0a263c 100644 --- a/lib/libc/gen/aux.c +++ b/lib/libc/gen/aux.c @@ -66,6 +66,7 @@ __init_elf_aux_vector(void) static pthread_once_t aux_once = PTHREAD_ONCE_INIT; static int pagesize, osreldate, canary_len, ncpus, pagesizes_len; static char *canary, *pagesizes; +static void *timekeep; static void init_aux(void) @@ -101,6 +102,10 @@ init_aux(void) case AT_NCPUS: ncpus = aux->a_un.a_val; break; + + case AT_TIMEKEEP: + timekeep = aux->a_un.a_ptr; + break; } } } @@ -163,6 +168,16 @@ _elf_aux_info(int aux, void *buf, int buflen) } else res = EINVAL; break; + case AT_TIMEKEEP: + if (buflen == sizeof(void *)) { + if (timekeep != NULL) { + *(void **)buf = timekeep; + res = 0; + } else + res = ENOENT; + } else + res = EINVAL; + break; default: res = ENOENT; break; diff --git a/lib/libc/i386/sys/Makefile.inc b/lib/libc/i386/sys/Makefile.inc index 98a9c9e7d394..9eefabca2ac3 100644 --- a/lib/libc/i386/sys/Makefile.inc +++ b/lib/libc/i386/sys/Makefile.inc @@ -5,7 +5,8 @@ SRCS+= i386_clr_watch.c i386_set_watch.c i386_vm86.c .endif SRCS+= i386_get_fsbase.c i386_get_gsbase.c i386_get_ioperm.c i386_get_ldt.c \ - i386_set_fsbase.c i386_set_gsbase.c i386_set_ioperm.c i386_set_ldt.c + i386_set_fsbase.c i386_set_gsbase.c i386_set_ioperm.c i386_set_ldt.c \ + __vdso_gettc.c MDASM= Ovfork.S brk.S cerror.S exect.S getcontext.S pipe.S ptrace.S \ reboot.S sbrk.S setlogin.S sigreturn.S syscall.S diff --git a/lib/libc/i386/sys/__vdso_gettc.c b/lib/libc/i386/sys/__vdso_gettc.c new file mode 100644 index 000000000000..4419141a5197 --- /dev/null +++ b/lib/libc/i386/sys/__vdso_gettc.c @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2012 Konstantin Belousov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +static u_int +__vdso_gettc_low(const struct vdso_timehands *th) +{ + uint32_t rv; + + __asm __volatile("rdtsc; shrd %%cl, %%edx, %0" + : "=a" (rv) : "c" (th->th_x86_shift) : "edx"); + return (rv); +} + +#pragma weak __vdso_gettc +u_int +__vdso_gettc(const struct vdso_timehands *th) +{ + + return (th->th_x86_shift > 0 ? __vdso_gettc_low(th) : rdtsc32()); +} diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index 2182f4689719..faae02811d17 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -34,6 +34,7 @@ #ifndef _LIBC_PRIVATE_H_ #define _LIBC_PRIVATE_H_ +#include #include /* @@ -245,6 +246,12 @@ extern void * __sys_freebsd6_mmap(void *, __size_t, int, int, int, int, __off_t) /* Without back-compat translation */ extern int __sys_fcntl(int, int, ...); +struct timespec; +struct timeval; +struct timezone; +int __sys_gettimeofday(struct timeval *, struct timezone *); +int __sys_clock_gettime(__clockid_t, struct timespec *ts); + /* execve() with PATH processing to implement posix_spawnp() */ int _execvpe(const char *, char * const *, char * const *); diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 61d1713193e1..df4ef4279404 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -15,6 +15,10 @@ # .sinclude "${.CURDIR}/${LIBC_ARCH}/sys/Makefile.inc" +SRCS+= clock_gettime.c gettimeofday.c __vdso_gettimeofday.c +NOASM+= clock_gettime.o gettimeofday.o +PSEUDO+= _clock_gettime.o _gettimeofday.o + # Sources common to both syscall interfaces: SRCS+= stack_protector.c stack_protector_compat.c __error.c .if !defined(WITHOUT_SYSCALL_COMPAT) diff --git a/lib/libc/sys/__vdso_gettimeofday.c b/lib/libc/sys/__vdso_gettimeofday.c new file mode 100644 index 000000000000..32abb6970d82 --- /dev/null +++ b/lib/libc/sys/__vdso_gettimeofday.c @@ -0,0 +1,142 @@ +/*- + * Copyright (c) 2012 Konstantin Belousov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include "libc_private.h" + +static u_int +tc_delta(const struct vdso_timehands *th) +{ + + return ((__vdso_gettc(th) - th->th_offset_count) & + th->th_counter_mask); +} + +static int +binuptime(struct bintime *bt, struct vdso_timekeep *tk, int abs) +{ + struct vdso_timehands *th; + uint32_t curr, gen; + + do { + if (!tk->tk_enabled) + return (ENOSYS); + + /* + * XXXKIB. The load of tk->tk_current should use + * atomic_load_acq_32 to provide load barrier. But + * since tk points to r/o mapped page, x86 + * implementation of atomic_load_acq faults. + */ + curr = tk->tk_current; + rmb(); + th = &tk->tk_th[curr]; + if (th->th_algo != VDSO_TH_ALGO_1) + return (ENOSYS); + gen = th->th_gen; + *bt = th->th_offset; + bintime_addx(bt, th->th_scale * tc_delta(th)); + if (abs) + bintime_add(bt, &th->th_boottime); + + /* + * Barrier for load of both tk->tk_current and th->th_gen. + */ + rmb(); + } while (curr != tk->tk_current || gen == 0 || gen != th->th_gen); + return (0); +} + +static struct vdso_timekeep *tk; + +int +__vdso_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + struct bintime bt; + int error; + + if (tz != NULL) + return (ENOSYS); + if (tk == NULL) { + error = _elf_aux_info(AT_TIMEKEEP, &tk, sizeof(tk)); + if (error != 0 || tk == NULL) + return (ENOSYS); + } + if (tk->tk_ver != VDSO_TK_VER_CURR) + return (ENOSYS); + error = binuptime(&bt, tk, 1); + if (error != 0) + return (error); + bintime2timeval(&bt, tv); + return (0); +} + +int +__vdso_clock_gettime(clockid_t clock_id, struct timespec *ts) +{ + struct bintime bt; + int abs, error; + + if (tk == NULL) { + error = _elf_aux_info(AT_TIMEKEEP, &tk, sizeof(tk)); + if (error != 0 || tk == NULL) + return (ENOSYS); + } + if (tk->tk_ver != VDSO_TK_VER_CURR) + return (ENOSYS); + switch (clock_id) { + case CLOCK_REALTIME: + case CLOCK_REALTIME_PRECISE: + case CLOCK_REALTIME_FAST: + case CLOCK_SECOND: + abs = 1; + break; + case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_PRECISE: + case CLOCK_MONOTONIC_FAST: + case CLOCK_UPTIME: + case CLOCK_UPTIME_PRECISE: + case CLOCK_UPTIME_FAST: + abs = 0; + break; + default: + return (ENOSYS); + } + error = binuptime(&bt, tk, abs); + if (error != 0) + return (error); + bintime2timespec(&bt, ts); + if (clock_id == CLOCK_SECOND) + ts->tv_nsec = 0; + return (0); +} diff --git a/lib/libc/sys/clock_gettime.c b/lib/libc/sys/clock_gettime.c new file mode 100644 index 000000000000..e7e701b2e509 --- /dev/null +++ b/lib/libc/sys/clock_gettime.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2012 Konstantin Belousov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include "libc_private.h" + +int __clock_gettime(clockid_t, struct timespec *ts); + +__weak_reference(__clock_gettime, clock_gettime); + +int +__clock_gettime(clockid_t clock_id, struct timespec *ts) +{ + int error; + + if (__vdso_clock_gettime != NULL && __vdso_gettc != NULL) + error = __vdso_clock_gettime(clock_id, ts); + else + error = ENOSYS; + if (error == ENOSYS) + error = __sys_clock_gettime(clock_id, ts); + return (error); +} diff --git a/lib/libc/sys/gettimeofday.c b/lib/libc/sys/gettimeofday.c new file mode 100644 index 000000000000..4cc87e1b5281 --- /dev/null +++ b/lib/libc/sys/gettimeofday.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2012 Konstantin Belousov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include "libc_private.h" + +int __gettimeofday(struct timeval *tv, struct timezone *tz); + +__weak_reference(__gettimeofday, gettimeofday); + +int +__gettimeofday(struct timeval *tv, struct timezone *tz) +{ + int error; + + if (__vdso_gettimeofday != NULL && __vdso_gettc != NULL) + error = __vdso_gettimeofday(tv, tz); + else + error = ENOSYS; + if (error == ENOSYS) + error = __sys_gettimeofday(tv, tz); + return (error); +}