/glibc-2.16-75f0d304/sysdeps/unix/sysv/linux/clock_gettime.c

# · C · 211 lines · 159 code · 25 blank · 27 comment · 30 complexity · b207b3cc0e3a7218fb7ac519116c733e MD5 · raw file

  1. /* clock_gettime -- Get current time from a POSIX clockid_t. Linux version.
  2. Copyright (C) 2003,2004,2005,2006,2007,2010,2011 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <sysdep.h>
  16. #include <errno.h>
  17. #include <time.h>
  18. #include "kernel-posix-cpu-timers.h"
  19. #include <kernel-features.h>
  20. #ifndef HAVE_CLOCK_GETTIME_VSYSCALL
  21. # undef INTERNAL_VSYSCALL
  22. # define INTERNAL_VSYSCALL INTERNAL_SYSCALL
  23. # undef INLINE_VSYSCALL
  24. # define INLINE_VSYSCALL INLINE_SYSCALL
  25. #else
  26. # include <bits/libc-vdso.h>
  27. #endif
  28. #ifndef SYSCALL_GETTIME
  29. # define SYSCALL_GETTIME(id, tp) \
  30. INLINE_VSYSCALL (clock_gettime, 2, id, tp)
  31. #endif
  32. #ifndef INTERNAL_GETTIME
  33. # define INTERNAL_GETTIME(id, tp) \
  34. INTERNAL_VSYSCALL (clock_gettime, err, 2, id, tp)
  35. #endif
  36. #ifdef __ASSUME_POSIX_TIMERS
  37. /* This means the REALTIME and MONOTONIC clock are definitely
  38. supported in the kernel. */
  39. # define SYSDEP_GETTIME \
  40. SYSDEP_GETTIME_CPUTIME; \
  41. case CLOCK_REALTIME: \
  42. case CLOCK_MONOTONIC: \
  43. retval = SYSCALL_GETTIME (clock_id, tp); \
  44. break
  45. # define __libc_missing_posix_timers 0
  46. #elif defined __NR_clock_gettime
  47. /* Is the syscall known to exist? */
  48. int __libc_missing_posix_timers attribute_hidden;
  49. static inline int
  50. maybe_syscall_gettime (clockid_t clock_id, struct timespec *tp)
  51. {
  52. int e = EINVAL;
  53. if (!__libc_missing_posix_timers)
  54. {
  55. INTERNAL_SYSCALL_DECL (err);
  56. int r = INTERNAL_GETTIME (clock_id, tp);
  57. if (!INTERNAL_SYSCALL_ERROR_P (r, err))
  58. return 0;
  59. e = INTERNAL_SYSCALL_ERRNO (r, err);
  60. if (e == ENOSYS)
  61. {
  62. __libc_missing_posix_timers = 1;
  63. e = EINVAL;
  64. }
  65. }
  66. return e;
  67. }
  68. /* The REALTIME and MONOTONIC clock might be available. Try the
  69. syscall first. */
  70. # define SYSDEP_GETTIME \
  71. SYSDEP_GETTIME_CPUTIME; \
  72. case CLOCK_REALTIME: \
  73. case CLOCK_MONOTONIC: \
  74. case CLOCK_MONOTONIC_RAW: \
  75. case CLOCK_REALTIME_COARSE: \
  76. case CLOCK_MONOTONIC_COARSE: \
  77. retval = maybe_syscall_gettime (clock_id, tp); \
  78. if (retval == 0) \
  79. break; \
  80. /* Fallback code. */ \
  81. if (retval == EINVAL && clock_id == CLOCK_REALTIME) \
  82. retval = realtime_gettime (tp); \
  83. else \
  84. { \
  85. __set_errno (retval); \
  86. retval = -1; \
  87. } \
  88. break
  89. #endif
  90. #ifdef __NR_clock_gettime
  91. /* We handled the REALTIME clock here. */
  92. # define HANDLED_REALTIME 1
  93. # define HANDLED_CPUTIME 1
  94. # if __ASSUME_POSIX_CPU_TIMERS > 0
  95. # define SYSDEP_GETTIME_CPU(clock_id, tp) \
  96. retval = SYSCALL_GETTIME (clock_id, tp); \
  97. break
  98. # define SYSDEP_GETTIME_CPUTIME /* Default catches them too. */
  99. # else
  100. int __libc_missing_posix_cpu_timers attribute_hidden;
  101. static int
  102. maybe_syscall_gettime_cpu (clockid_t clock_id, struct timespec *tp)
  103. {
  104. int e = EINVAL;
  105. if (!__libc_missing_posix_cpu_timers)
  106. {
  107. INTERNAL_SYSCALL_DECL (err);
  108. int r = INTERNAL_GETTIME (clock_id, tp);
  109. if (!INTERNAL_SYSCALL_ERROR_P (r, err))
  110. return 0;
  111. e = INTERNAL_SYSCALL_ERRNO (r, err);
  112. # ifndef __ASSUME_POSIX_TIMERS
  113. if (e == ENOSYS)
  114. {
  115. __libc_missing_posix_timers = 1;
  116. __libc_missing_posix_cpu_timers = 1;
  117. e = EINVAL;
  118. }
  119. else
  120. # endif
  121. {
  122. if (e == EINVAL)
  123. {
  124. # ifdef HAVE_CLOCK_GETRES_VSYSCALL
  125. /* Check whether the kernel supports CPU clocks at all.
  126. If not, record it for the future. */
  127. r = INTERNAL_VSYSCALL (clock_getres, err, 2,
  128. MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
  129. NULL);
  130. # else
  131. /* Check whether the kernel supports CPU clocks at all.
  132. If not, record it for the future. */
  133. r = INTERNAL_SYSCALL (clock_getres, err, 2,
  134. MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
  135. NULL);
  136. # endif
  137. if (INTERNAL_SYSCALL_ERROR_P (r, err))
  138. __libc_missing_posix_cpu_timers = 1;
  139. }
  140. }
  141. }
  142. return e;
  143. }
  144. # define SYSDEP_GETTIME_CPU(clock_id, tp) \
  145. retval = maybe_syscall_gettime_cpu (clock_id, tp); \
  146. if (retval == 0) \
  147. break; \
  148. if (retval != EINVAL || !__libc_missing_posix_cpu_timers) \
  149. { \
  150. __set_errno (retval); \
  151. retval = -1; \
  152. break; \
  153. } \
  154. retval = -1 /* Otherwise continue on to the HP_TIMING version. */;
  155. static inline int
  156. maybe_syscall_gettime_cputime (clockid_t clock_id, struct timespec *tp)
  157. {
  158. return maybe_syscall_gettime_cpu
  159. (clock_id == CLOCK_THREAD_CPUTIME_ID
  160. ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED)
  161. : MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
  162. tp);
  163. }
  164. # define SYSDEP_GETTIME_CPUTIME \
  165. case CLOCK_PROCESS_CPUTIME_ID: \
  166. case CLOCK_THREAD_CPUTIME_ID: \
  167. retval = maybe_syscall_gettime_cputime (clock_id, tp); \
  168. if (retval == 0) \
  169. break; \
  170. if (retval != EINVAL || !__libc_missing_posix_cpu_timers) \
  171. { \
  172. __set_errno (retval); \
  173. retval = -1; \
  174. break; \
  175. } \
  176. retval = hp_timing_gettime (clock_id, tp); \
  177. break
  178. # if !HP_TIMING_AVAIL
  179. # define hp_timing_gettime(clock_id, tp) (__set_errno (EINVAL), -1)
  180. # endif
  181. # endif
  182. #endif
  183. #include <sysdeps/unix/clock_gettime.c>