Messages in this thread Patch in this message | | | Date | Fri, 1 Oct 2004 13:01:36 -0700 (PDT) | From | Christoph Lameter <> | Subject | Posix compliant cpu clocks V6 [2/3]: Glibc patch |
| |
The following patch makes glibc not provide the above clocks and use the kernel clocks instead if either of the following condition is met:
1. __ASSUME_POSIX_TIMERS is set
2. A call to probe the posix function is made if the corresponding __NR_clock_* is defined. If the call is successful then the kernel clocks will be used. Otherwise glibc will fall back to its own implementation of the clocks.
The clock_gettime clock_settime and clock_res calls will use the corresponding system calls for other clocks than CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_THREAD_CPUTIME_ID and CLOCK_PROCESS_CPUTIME_ID.
Patch needs some additional testing....
Signed-off-by: Christoph Lameter <clameter@sgi.com>
Index: libc/sysdeps/unix/sysv/linux/clock_gettime.c =================================================================== --- libc.orig/sysdeps/unix/sysv/linux/clock_gettime.c 2004-09-28 15:22:02.359949008 -0700 +++ libc/sysdeps/unix/sysv/linux/clock_gettime.c 2004-10-01 08:57:51.025894976 -0700 @@ -16,61 +16,174 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */
+#include <errno.h> +#include <stdint.h> +#include <time.h> +#include <sys/time.h> +#include <libc-internal.h> #include <sysdep.h> +#include <ldsodefs.h>
#include "kernel-features.h"
#ifdef __ASSUME_POSIX_TIMERS -/* This means the REALTIME and MONOTONIC clock are definitely - supported in the kernel. */ -# define SYSDEP_GETTIME \ - case CLOCK_REALTIME: \ - case CLOCK_MONOTONIC: \ - retval = INLINE_SYSCALL (clock_gettime, 2, clock_id, tp); \ - break -#elif defined __NR_clock_gettime -/* Is the syscall known to exist? */ -int __libc_missing_posix_timers attribute_hidden; - -/* The REALTIME and MONOTONIC clock might be available. Try the - syscall first. */ -# define SYSDEP_GETTIME \ - case CLOCK_REALTIME: \ - case CLOCK_MONOTONIC: \ - { \ - int e = EINVAL; \ - \ - if (!__libc_missing_posix_timers) \ - { \ - INTERNAL_SYSCALL_DECL (err); \ - int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); \ - if (!INTERNAL_SYSCALL_ERROR_P (r, err)) \ - { \ - retval = 0; \ - break; \ - } \ - \ - e = INTERNAL_SYSCALL_ERRNO (r, err); \ - if (e == ENOSYS) \ - { \ - __libc_missing_posix_timers = 1; \ - e = EINVAL; \ - } \ - } \ - \ - /* Fallback code. */ \ - if (e == EINVAL && clock_id == CLOCK_REALTIME) \ - HANDLE_REALTIME; \ - else \ - __set_errno (e); \ - } \ - break +/* This means all clocks are definitely supported in the kernel. */ +int +clock_gettime (clockid_t clock_id, struct timespec *tp) +{ + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + return 0; + return -1; +} + +#else + +/* + * Need to deal with multiple complex fallback and legacy scenarios + * + * Give priority to the clock_gettime syscall but fall back if + * certain clocks are not available + * for CLOCK_REALTIME fall back to gettimeofday + * for CLOCK_PROCESS_CPUTIME_ID fall back to HP_TIMING + * for CLOCK_THREAD_CPUTIME_ID fall back to pthreads + */ + +int __libc_missing_posix_stdtimers attribute_hidden; +int __libc_missing_posix_cputimers attribute_hidden; + +int +clock_gettime (clockid_t clock_id, struct timespec *tp) +{ + int retval = -1; + + switch (clock_id) + { +#if defined __NR_clock_gettime + case CLOCK_REALTIME: case CLOCK_MONOTONIC: + { + int e = EINVAL; + + if (!__libc_missing_posix_stdtimers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + { + retval = 0; + break; + } + + e = INTERNAL_SYSCALL_ERRNO (r, err); + if (e == ENOSYS) + { + __libc_missing_posix_stdtimers = 1; + e = EINVAL; + } + } + + /* Fallback code. */ + if (e != EINVAL || clock_id != CLOCK_REALTIME) + { + __set_errno (e); + break; + } + } + /* Fall through */ +#else + case CLOCK_REALTIME: #endif + struct timeval tv; + retval = gettimeofday (&tv, NULL); + if (retval == 0) + /* Convert into `timespec'. */ + TIMEVAL_TO_TIMESPEC (&tv, tp); + break; + + case CLOCK_PROCESS_CPUTIME_ID: case CLOCK_THREAD_CPUTIME_ID: +#if defined __NR_clock_gettime + if (!__libc_missing_posix_cputimers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + { + retval = 0; + break; + } + + if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS) + __libc_missing_posix_cputimers = 1; + } + +#if HP_TIMING_AVAIL + /* Fallback code. */ + { +/* Clock frequency of the processor. We make it a 64-bit variable + because some jokers are already playing with processors with more + than 4GHz. */ +static hp_timing_t freq; + + +/* This function is defined in the thread library. */ +extern int __pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq, + struct timespec *tp) + __attribute__ ((__weak__)); + + hp_timing_t tsc; + + if (__builtin_expect (freq == 0, 0)) + { + /* This can only happen if we haven't initialized the `freq' + variable yet. Do this now. We don't have to protect this + code against multiple execution since all of them should + lead to the same result. */ + freq = __get_clockfreq (); + if (__builtin_expect (freq == 0, 0)) + /* Something went wrong. */ + break; + } + + if (clock_id != CLOCK_PROCESS_CPUTIME_ID + && __pthread_clock_gettime != NULL) + { + retval = __pthread_clock_gettime (clock_id, freq, tp); + break; + } + + /* Get the current counter. */ + HP_TIMING_NOW (tsc); + + /* Compute the offset since the start time of the process. */ + tsc -= GL(dl_cpuclock_offset); + + /* Compute the seconds. */ + tp->tv_sec = tsc / freq; + + /* And the nanoseconds. This computation should be stable until + we get machines with about 16GHz frequency. */ + tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq; + + retval = 0; + } +#endif +#endif + break; + + default: +#if defined __NR_clock_gettime + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + retval = 0; +#else + __set_errno(EINVAL); +#endif + } + return retval; +}
-#ifdef __NR_clock_gettime -/* We handled the REALTIME clock here. */ -# define HANDLED_REALTIME 1 #endif
-#include <sysdeps/unix/clock_gettime.c> Index: libc/sysdeps/unix/sysv/linux/clock_settime.c =================================================================== --- libc.orig/sysdeps/unix/sysv/linux/clock_settime.c 2004-10-01 10:27:15.007445832 -0700 +++ libc/sysdeps/unix/sysv/linux/clock_settime.c 2004-10-01 11:09:40.938405496 -0700 @@ -1,4 +1,4 @@ -/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or @@ -16,61 +16,160 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */
-#include <sysdep.h> - +#include <errno.h> +#include <time.h> +#include <sys/time.h> +#include <libc-internal.h> +#include <ldsodefs.h> #include "kernel-features.h"
- #ifdef __ASSUME_POSIX_TIMERS -/* This means the REALTIME clock is definitely supported in the - kernel. */ -# define SYSDEP_SETTIME \ - case CLOCK_REALTIME: \ - retval = INLINE_SYSCALL (clock_settime, 2, clock_id, tp); \ - break -#elif defined __NR_clock_settime -/* Is the syscall known to exist? */ -extern int __libc_missing_posix_timers attribute_hidden; - -/* The REALTIME clock might be available. Try the syscall first. */ -# define SYSDEP_SETTIME \ - case CLOCK_REALTIME: \ - { \ - int e = EINVAL; \ - \ - if (!__libc_missing_posix_timers) \ - { \ - INTERNAL_SYSCALL_DECL (err); \ - int r = INTERNAL_SYSCALL (clock_settime, err, 2, clock_id, tp); \ - if (!INTERNAL_SYSCALL_ERROR_P (r, err)) \ - { \ - retval = 0; \ - break; \ - } \ - \ - e = INTERNAL_SYSCALL_ERRNO (r, err); \ - if (e == ENOSYS) \ - { \ - __libc_missing_posix_timers = 1; \ - e = EINVAL; \ - } \ - } \ - \ - /* Fallback code. */ \ - if (e == EINVAL && clock_id == CLOCK_REALTIME) \ - HANDLE_REALTIME; \ - else \ - { \ - __set_errno (e); \ - retval = -1; \ - } \ - } \ - break +/* This means all clocks are definitely supported in the kernel. */ +int +clock_settime (clockid_t clock_id, struct timespec *tp) +{ + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_settime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + return 0; + return -1; +} + +#else +/* + * Need to deal with multiple complex fallback and legacy scenarios + * + * Give priority to the clock_gettime syscall but fall back if + * certain clocks are not available + * for CLOCK_REALTIME fall back to gettimeofday + * for CLOCK_PROCESS_CPUTIME_ID fall back to HP_TIMING + * for CLOCK_THREAD_CPUTIME_ID fall back to pthreads + */ + +int __libc_missing_posix_stdtimers attribute_hidden; +int __libc_missing_posix_cputimers attribute_hidden; + +int +clock_settime (clockid_t clock_id,const struct timespec *tp) +{ + int retval = -1; + + switch (clock_id) + { +#if defined __NR_clock_gettime + case CLOCK_REALTIME: case CLOCK_MONOTONIC: + { + int e = EINVAL; + + if (!__libc_missing_posix_stdtimers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_settime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + { + retval = 0; + break; + } + + e = INTERNAL_SYSCALL_ERRNO (r, err); + if (e == ENOSYS) + { + __libc_missing_posix_stdtimers = 1; + e = EINVAL; + } + } + + /* Fallback code. */ + if (e != EINVAL || clock_id != CLOCK_REALTIME) + { + __set_errno (e); + break; + } + } + /* Fall through */ +#else + case CLOCK_REALTIME: +#endif + struct timeval tv; + TIMESPEC_TO_TIMEVAL (&tv, tp); + retval = settimeofday (&tv, NULL); + break; + + case CLOCK_PROCESS_CPUTIME_ID: case CLOCK_THREAD_CPUTIME_ID: +#if defined __NR_clock_gettime + if (!__libc_missing_posix_cputimers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_settime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + { + retval = 0; + break; + } + + if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS) + __libc_missing_posix_cputimers = 1; + } + +#if HP_TIMING_AVAIL + /* Fallback code. */ + { +/* Clock frequency of the processor. We make it a 64-bit variable + because some jokers are already playing with processors with more + than 4GHz. */ +static hp_timing_t freq; + + +/* This function is defined in the thread library. */ +extern int __pthread_clock_settime (clockid_t clock_id, hp_timing_t offset) + __attribute__ ((__weak__)); + + hp_timing_t tsc; + hp_timing_t usertime; + + if (__builtin_expect (freq == 0, 0)) + { + /* This can only happen if we haven't initialized the `freq' + variable yet. Do this now. We don't have to protect this + code against multiple execution since all of them should + lead to the same result. */ + freq = __get_clockfreq (); + if (__builtin_expect (freq == 0, 0)) + /* Something went wrong. */ + break; + } + + /* Get the current counter. */ + HP_TIMING_NOW (tsc); + + /* Convert the user-provided time into CPU ticks. */ + usertime = tp->tv_sec * freq + (tp->tv_nsec * freq) / 1000000000ull; + + /* Determine the offset and use it as the new base value. */ + if (clock_id == CLOCK_PROCESS_CPUTIME_ID + || __pthread_clock_settime == NULL) + GL(dl_cpuclock_offset) = tsc - usertime; + else + __pthread_clock_settime (clock_id, tsc - usertime); + + retval = 0; + } +#endif +#endif + break; + + default: +#if defined __NR_clock_gettime + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + retval = 0; +#else + __set_errno(EINVAL); #endif + } + return retval; +}
-#ifdef __NR_clock_settime -/* We handled the REALTIME clock here. */ -# define HANDLED_REALTIME 1 #endif
-#include <sysdeps/unix/clock_settime.c> Index: libc/sysdeps/unix/sysv/linux/clock_getres.c =================================================================== --- libc.orig/sysdeps/unix/sysv/linux/clock_getres.c 2004-09-28 15:22:02.351950224 -0700 +++ libc/sysdeps/unix/sysv/linux/clock_getres.c 2004-10-01 12:23:50.099030272 -0700 @@ -16,61 +16,159 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */
+#include <errno.h> +#include <stdint.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> +#include <libc-internal.h> #include <sysdep.h> +#include <ldsodefs.h>
#include "kernel-features.h"
#ifdef __ASSUME_POSIX_TIMERS -/* This means the REALTIME and MONOTONIC clock are definitely - supported in the kernel. */ -# define SYSDEP_GETRES \ - case CLOCK_REALTIME: \ - case CLOCK_MONOTONIC: \ - retval = INLINE_SYSCALL (clock_getres, 2, clock_id, res); \ - break -#elif defined __NR_clock_getres -/* Is the syscall known to exist? */ -extern int __libc_missing_posix_timers attribute_hidden; - -/* The REALTIME and MONOTONIC clock might be available. Try the - syscall first. */ -# define SYSDEP_GETRES \ - case CLOCK_REALTIME: \ - case CLOCK_MONOTONIC: \ - { \ - int e = EINVAL; \ - \ - if (!__libc_missing_posix_timers) \ - { \ - INTERNAL_SYSCALL_DECL (err); \ - int r = INTERNAL_SYSCALL (clock_getres, err, 2, clock_id, res); \ - if (!INTERNAL_SYSCALL_ERROR_P (r, err)) \ - { \ - retval = 0; \ - break; \ - } \ - \ - e = INTERNAL_SYSCALL_ERRNO (r, err); \ - if (e == ENOSYS) \ - { \ - __libc_missing_posix_timers = 1; \ - e = EINVAL; \ - } \ - } \ - \ - /* Fallback code. */ \ - if (e == EINVAL && clock_id == CLOCK_REALTIME) \ - HANDLE_REALTIME; \ - else \ - __set_errno (e); \ - } \ - break +/* This means all clocks are definitely supported in the kernel. */ +int +clock_getres (clockid_t clock_id, struct timespec *res) +{ + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_getres, err, 2, clock_id, res); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + return 0; + return -1; +} + +#else + +/* + * Need to deal with multiple complex fallback and legacy scenarios + * + * Give priority to the clock_gettime syscall but fall back if + * certain clocks are not available + * for CLOCK_REALTIME fall back to gettimeofday + * for CLOCK_PROCESS_CPUTIME_ID fall back to HP_TIMING + * for CLOCK_THREAD_CPUTIME_ID fall back to pthreads + */ + +int __libc_missing_posix_stdtimers attribute_hidden; +int __libc_missing_posix_cputimers attribute_hidden; + +int +clock_getres (clockid_t clock_id, struct timespec *res) +{ + int retval = -1; + + switch (clock_id) + { +#if defined __NR_clock_gettime + case CLOCK_REALTIME: case CLOCK_MONOTONIC: + { + int e = EINVAL; + + if (!__libc_missing_posix_stdtimers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_getres, err, 2, clock_id, res); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + { + retval = 0; + break; + } + + e = INTERNAL_SYSCALL_ERRNO (r, err); + if (e == ENOSYS) + { + __libc_missing_posix_stdtimers = 1; + e = EINVAL; + } + } + + /* Fallback code. */ + if (e != EINVAL || clock_id != CLOCK_REALTIME) + { + __set_errno (e); + break; + } + } + /* Fall through */ +#else + case CLOCK_REALTIME: #endif + { + long int clk_tck = sysconf (_SC_CLK_TCK); + + if (__builtin_expect (clk_tck != -1, 1)) + { + /* This implementation assumes that the realtime clock has a + resolution higher than 1 second. This is the case for any + reasonable implementation. */ + res->tv_sec = 0; + res->tv_nsec = 1000000000 / clk_tck; + + retval = 0; + } + } + break; + + case CLOCK_PROCESS_CPUTIME_ID: case CLOCK_THREAD_CPUTIME_ID: +#if defined __NR_clock_gettime + if (!__libc_missing_posix_cputimers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_getres, err, 2, clock_id, res); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + { + retval = 0; + break; + } + + if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS) + __libc_missing_posix_cputimers = 1; + } + +#if HP_TIMING_AVAIL + /* Fallback code. */ + static long int nsec; + { + if (__builtin_expect (nsec == 0, 0)) + { + hp_timing_t freq; + + /* This can only happen if we haven't initialized the `freq' + variable yet. Do this now. We don't have to protect this + code against multiple execution since all of them should + lead to the same result. */ + freq = __get_clockfreq (); + if (__builtin_expect (freq == 0, 0)) + /* Something went wrong. */ + break; + nsec = MAX (UINT64_C (1000000000) / freq, 1); + } + /* File in the values. The seconds are always zero (unless we + have a 1Hz machine). */ + res->tv_sec = 0; + res->tv_nsec = nsec; + + retval = 0; + } +#endif +#endif + break; + + default: +#if defined __NR_clock_gettime + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_getres, err, 2, clock_id, res); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + retval = 0; +#else + __set_errno(EINVAL); +#endif + } + return retval; +}
-#ifdef __NR_clock_getres -/* We handled the REALTIME clock here. */ -# define HANDLED_REALTIME 1 #endif
-#include <sysdeps/posix/clock_getres.c> - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |