Back to index

glibc  2.9
clock_gettime.c
Go to the documentation of this file.
00001 /* clock_gettime -- Get current time from a POSIX clockid_t.  Linux version.
00002    Copyright (C) 2003,2004,2005,2006,2007 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <sysdep.h>
00021 #include <errno.h>
00022 #include <time.h>
00023 #include "kernel-posix-cpu-timers.h"
00024 #include <kernel-features.h>
00025 
00026 #ifndef HAVE_CLOCK_GETTIME_VSYSCALL
00027 # undef INTERNAL_VSYSCALL
00028 # define INTERNAL_VSYSCALL INTERNAL_SYSCALL
00029 # undef INLINE_VSYSCALL
00030 # define INLINE_VSYSCALL INLINE_SYSCALL
00031 #else
00032 # include <bits/libc-vdso.h>
00033 #endif
00034 
00035 #define SYSCALL_GETTIME \
00036   retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp); \
00037   break
00038 
00039 #ifdef __ASSUME_POSIX_TIMERS
00040 
00041 /* This means the REALTIME and MONOTONIC clock are definitely
00042    supported in the kernel.  */
00043 # define SYSDEP_GETTIME                                                     \
00044   SYSDEP_GETTIME_CPUTIME                                             \
00045   case CLOCK_REALTIME:                                                      \
00046   case CLOCK_MONOTONIC:                                                     \
00047     SYSCALL_GETTIME
00048 
00049 # define __libc_missing_posix_timers 0
00050 #elif defined __NR_clock_gettime
00051 /* Is the syscall known to exist?  */
00052 int __libc_missing_posix_timers attribute_hidden;
00053 
00054 static inline int
00055 maybe_syscall_gettime (clockid_t clock_id, struct timespec *tp)
00056 {
00057   int e = EINVAL;
00058 
00059   if (!__libc_missing_posix_timers)
00060     {
00061       INTERNAL_SYSCALL_DECL (err);
00062       int r = INTERNAL_VSYSCALL (clock_gettime, err, 2, clock_id, tp);
00063       if (!INTERNAL_SYSCALL_ERROR_P (r, err))
00064        return 0;
00065 
00066       e = INTERNAL_SYSCALL_ERRNO (r, err);
00067       if (e == ENOSYS)
00068        {
00069          __libc_missing_posix_timers = 1;
00070          e = EINVAL;
00071        }
00072     }
00073 
00074   return e;
00075 }
00076 
00077 /* The REALTIME and MONOTONIC clock might be available.  Try the
00078    syscall first.  */
00079 # define SYSDEP_GETTIME                                                     \
00080   SYSDEP_GETTIME_CPUTIME                                             \
00081   case CLOCK_REALTIME:                                                      \
00082   case CLOCK_MONOTONIC:                                                     \
00083     retval = maybe_syscall_gettime (clock_id, tp);                          \
00084     if (retval == 0)                                                 \
00085       break;                                                         \
00086     /* Fallback code.  */                                            \
00087     if (retval == EINVAL && clock_id == CLOCK_REALTIME)                     \
00088       retval = realtime_gettime (tp);                                       \
00089     else                                                             \
00090       {                                                                     \
00091        __set_errno (retval);                                                \
00092        retval = -1;                                                  \
00093       }                                                                     \
00094     break;
00095 #endif
00096 
00097 #ifdef __NR_clock_gettime
00098 /* We handled the REALTIME clock here.  */
00099 # define HANDLED_REALTIME   1
00100 # define HANDLED_CPUTIME    1
00101 
00102 # if __ASSUME_POSIX_CPU_TIMERS > 0
00103 
00104 #  define SYSDEP_GETTIME_CPU SYSCALL_GETTIME
00105 #  define SYSDEP_GETTIME_CPUTIME   /* Default catches them too.  */
00106 
00107 # else
00108 
00109 int __libc_missing_posix_cpu_timers attribute_hidden;
00110 
00111 static int
00112 maybe_syscall_gettime_cpu (clockid_t clock_id, struct timespec *tp)
00113 {
00114   int e = EINVAL;
00115 
00116   if (!__libc_missing_posix_cpu_timers)
00117     {
00118       INTERNAL_SYSCALL_DECL (err);
00119       int r = INTERNAL_VSYSCALL (clock_gettime, err, 2, clock_id, tp);
00120       if (!INTERNAL_SYSCALL_ERROR_P (r, err))
00121        return 0;
00122 
00123       e = INTERNAL_SYSCALL_ERRNO (r, err);
00124 # ifndef __ASSUME_POSIX_TIMERS
00125       if (e == ENOSYS)
00126        {
00127          __libc_missing_posix_timers = 1;
00128          __libc_missing_posix_cpu_timers = 1;
00129          e = EINVAL;
00130        }
00131       else
00132 # endif
00133        {
00134          if (e == EINVAL)
00135            {
00136 # ifdef HAVE_CLOCK_GETRES_VSYSCALL
00137              /* Check whether the kernel supports CPU clocks at all.
00138                If not, record it for the future.  */
00139              r = INTERNAL_VSYSCALL (clock_getres, err, 2,
00140                                  MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
00141                                  NULL);
00142 # else
00143              /* Check whether the kernel supports CPU clocks at all.
00144                If not, record it for the future.  */
00145              r = INTERNAL_SYSCALL (clock_getres, err, 2,
00146                                 MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
00147                                 NULL);
00148 # endif
00149              if (INTERNAL_SYSCALL_ERROR_P (r, err))
00150               __libc_missing_posix_cpu_timers = 1;
00151            }
00152        }
00153     }
00154 
00155   return e;
00156 }
00157 
00158 #  define SYSDEP_GETTIME_CPU                                                \
00159   retval = maybe_syscall_gettime_cpu (clock_id, tp);                        \
00160   if (retval == 0)                                                   \
00161     break;                                                           \
00162   if (retval != EINVAL || !__libc_missing_posix_cpu_timers)                 \
00163     {                                                                \
00164       __set_errno (retval);                                          \
00165       retval = -1;                                                   \
00166       break;                                                         \
00167     }                                                                \
00168   retval = -1 /* Otherwise continue on to the HP_TIMING version.  */;
00169 
00170 static inline int
00171 maybe_syscall_gettime_cputime (clockid_t clock_id, struct timespec *tp)
00172 {
00173   return maybe_syscall_gettime_cpu
00174     (clock_id == CLOCK_THREAD_CPUTIME_ID
00175      ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED)
00176      : MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
00177      tp);
00178 }
00179 
00180 #  define SYSDEP_GETTIME_CPUTIME                                     \
00181     case CLOCK_PROCESS_CPUTIME_ID:                                   \
00182     case CLOCK_THREAD_CPUTIME_ID:                                    \
00183       retval = maybe_syscall_gettime_cputime (clock_id, tp);                \
00184       if (retval == 0)                                                      \
00185        break;                                                        \
00186       if (retval != EINVAL || !__libc_missing_posix_cpu_timers)                    \
00187        {                                                             \
00188          __set_errno (retval);                                              \
00189          retval = -1;                                                       \
00190          break;                                                      \
00191        }                                                             \
00192       retval = hp_timing_gettime (clock_id, tp);                     \
00193       break;
00194 #  if !HP_TIMING_AVAIL
00195 #   define hp_timing_gettime(clock_id, tp) (__set_errno (EINVAL), -1)
00196 #  endif
00197 
00198 # endif
00199 #endif
00200 
00201 #include <sysdeps/unix/clock_gettime.c>