clock_gettime.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /* clock_gettime -- Get current time from a POSIX clockid_t. Linux version.
  2. Copyright (C) 2003, 2004 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 <bits/kernel-features.h>
  20. #define SYSCALL_GETTIME \
  21. retval = INLINE_SYSCALL (clock_gettime, 2, clock_id, tp); \
  22. break
  23. #ifdef __ASSUME_POSIX_TIMERS
  24. /* This means the REALTIME and MONOTONIC clock are definitely
  25. supported in the kernel. */
  26. # define SYSDEP_GETTIME \
  27. SYSDEP_GETTIME_CPUTIME \
  28. case CLOCK_REALTIME: \
  29. case CLOCK_MONOTONIC: \
  30. SYSCALL_GETTIME
  31. # define __libc_missing_posix_timers 0
  32. #elif defined __NR_clock_gettime
  33. /* Is the syscall known to exist? */
  34. int __libc_missing_posix_timers attribute_hidden;
  35. static inline int
  36. maybe_syscall_gettime (clockid_t clock_id, struct timespec *tp)
  37. {
  38. int e = EINVAL;
  39. if (!__libc_missing_posix_timers)
  40. {
  41. INTERNAL_SYSCALL_DECL (err);
  42. int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp);
  43. if (!INTERNAL_SYSCALL_ERROR_P (r, err))
  44. return 0;
  45. e = INTERNAL_SYSCALL_ERRNO (r, err);
  46. if (e == ENOSYS)
  47. {
  48. __libc_missing_posix_timers = 1;
  49. e = EINVAL;
  50. }
  51. }
  52. return e;
  53. }
  54. /* The REALTIME and MONOTONIC clock might be available. Try the
  55. syscall first. */
  56. # define SYSDEP_GETTIME \
  57. SYSDEP_GETTIME_CPUTIME \
  58. case CLOCK_REALTIME: \
  59. case CLOCK_MONOTONIC: \
  60. retval = maybe_syscall_gettime (clock_id, tp); \
  61. if (retval == 0) \
  62. break; \
  63. /* Fallback code. */ \
  64. if (retval == EINVAL && clock_id == CLOCK_REALTIME) \
  65. retval = realtime_gettime (tp); \
  66. else \
  67. { \
  68. __set_errno (retval); \
  69. retval = -1; \
  70. } \
  71. break;
  72. #endif
  73. #ifdef __NR_clock_gettime
  74. /* We handled the REALTIME clock here. */
  75. # define HANDLED_REALTIME 1
  76. # define HANDLED_CPUTIME 1
  77. # if __ASSUME_POSIX_CPU_TIMERS > 0
  78. # define SYSDEP_GETTIME_CPU SYSCALL_GETTIME
  79. # define SYSDEP_GETTIME_CPUTIME /* Default catches them too. */
  80. # else
  81. int __libc_missing_posix_cpu_timers attribute_hidden;
  82. static int
  83. maybe_syscall_gettime_cpu (clockid_t clock_id, struct timespec *tp)
  84. {
  85. int e = EINVAL;
  86. if (!__libc_missing_posix_cpu_timers)
  87. {
  88. INTERNAL_SYSCALL_DECL (err);
  89. int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp);
  90. if (!INTERNAL_SYSCALL_ERROR_P (r, err))
  91. return 0;
  92. e = INTERNAL_SYSCALL_ERRNO (r, err);
  93. # ifndef __ASSUME_POSIX_TIMERS
  94. if (e == ENOSYS)
  95. {
  96. __libc_missing_posix_timers = 1;
  97. __libc_missing_posix_cpu_timers = 1;
  98. e = EINVAL;
  99. }
  100. else
  101. # endif
  102. {
  103. if (e == EINVAL)
  104. {
  105. /* Check whether the kernel supports CPU clocks at all.
  106. If not, record it for the future. */
  107. r = INTERNAL_SYSCALL (clock_getres, err, 2,
  108. MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
  109. NULL);
  110. if (INTERNAL_SYSCALL_ERROR_P (r, err))
  111. __libc_missing_posix_cpu_timers = 1;
  112. }
  113. }
  114. }
  115. return e;
  116. }
  117. # define SYSDEP_GETTIME_CPU \
  118. retval = maybe_syscall_gettime_cpu (clock_id, tp); \
  119. if (retval == 0) \
  120. break; \
  121. if (retval != EINVAL || !__libc_missing_posix_cpu_timers) \
  122. { \
  123. __set_errno (retval); \
  124. retval = -1; \
  125. break; \
  126. } \
  127. retval = -1 /* Otherwise continue on to the HP_TIMING version. */;
  128. static inline int
  129. maybe_syscall_gettime_cputime (clockid_t clock_id, struct timespec *tp)
  130. {
  131. return maybe_syscall_gettime_cpu
  132. (clock_id == CLOCK_THREAD_CPUTIME_ID
  133. ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED)
  134. : MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
  135. tp);
  136. }
  137. # define SYSDEP_GETTIME_CPUTIME \
  138. case CLOCK_PROCESS_CPUTIME_ID: \
  139. case CLOCK_THREAD_CPUTIME_ID: \
  140. retval = maybe_syscall_gettime_cputime (clock_id, tp); \
  141. if (retval == 0) \
  142. break; \
  143. if (retval != EINVAL || !__libc_missing_posix_cpu_timers) \
  144. { \
  145. __set_errno (retval); \
  146. retval = -1; \
  147. break; \
  148. } \
  149. retval = hp_timing_gettime (clock_id, tp); \
  150. break;
  151. # if !HP_TIMING_AVAIL
  152. # define hp_timing_gettime(clock_id, tp) (__set_errno (EINVAL), -1)
  153. # endif
  154. # endif
  155. #endif
  156. #include <errno.h>
  157. #include <stdint.h>
  158. #include <time.h>
  159. #include <sys/time.h>
  160. #include <ldsodefs.h>
  161. #if HP_TIMING_AVAIL
  162. /* Clock frequency of the processor. We make it a 64-bit variable
  163. because some jokers are already playing with processors with more
  164. than 4GHz. */
  165. static hp_timing_t freq;
  166. /* This function is defined in the thread library. */
  167. extern int __pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
  168. struct timespec *tp)
  169. __attribute__ ((__weak__));
  170. static int
  171. hp_timing_gettime (clockid_t clock_id, struct timespec *tp)
  172. {
  173. hp_timing_t tsc;
  174. if (__builtin_expect (freq == 0, 0))
  175. {
  176. /* This can only happen if we haven't initialized the `freq'
  177. variable yet. Do this now. We don't have to protect this
  178. code against multiple execution since all of them should
  179. lead to the same result. */
  180. freq = __get_clockfreq ();
  181. if (__builtin_expect (freq == 0, 0))
  182. /* Something went wrong. */
  183. return -1;
  184. }
  185. if (clock_id != CLOCK_PROCESS_CPUTIME_ID
  186. && __pthread_clock_gettime != NULL)
  187. return __pthread_clock_gettime (clock_id, freq, tp);
  188. /* Get the current counter. */
  189. HP_TIMING_NOW (tsc);
  190. /* Compute the offset since the start time of the process. */
  191. tsc -= GL(dl_cpuclock_offset);
  192. /* Compute the seconds. */
  193. tp->tv_sec = tsc / freq;
  194. /* And the nanoseconds. This computation should be stable until
  195. we get machines with about 16GHz frequency. */
  196. tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq;
  197. return 0;
  198. }
  199. #endif
  200. static inline int
  201. realtime_gettime (struct timespec *tp)
  202. {
  203. struct timeval tv;
  204. int retval = gettimeofday (&tv, NULL);
  205. if (retval == 0)
  206. /* Convert into `timespec'. */
  207. TIMEVAL_TO_TIMESPEC (&tv, tp);
  208. return retval;
  209. }
  210. librt_hidden_proto (clock_gettime)
  211. /* Get current value of CLOCK and store it in TP. */
  212. int
  213. clock_gettime (clockid_t clock_id, struct timespec *tp)
  214. {
  215. int retval = -1;
  216. #ifndef HANDLED_REALTIME
  217. struct timeval tv;
  218. #endif
  219. switch (clock_id)
  220. {
  221. #ifdef SYSDEP_GETTIME
  222. SYSDEP_GETTIME;
  223. #endif
  224. #ifndef HANDLED_REALTIME
  225. case CLOCK_REALTIME:
  226. retval = gettimeofday (&tv, NULL);
  227. if (retval == 0)
  228. TIMEVAL_TO_TIMESPEC (&tv, tp);
  229. break;
  230. #endif
  231. default:
  232. #ifdef SYSDEP_GETTIME_CPU
  233. SYSDEP_GETTIME_CPU;
  234. #endif
  235. #if HP_TIMING_AVAIL
  236. if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1))
  237. == CLOCK_THREAD_CPUTIME_ID)
  238. retval = hp_timing_gettime (clock_id, tp);
  239. else
  240. #endif
  241. __set_errno (EINVAL);
  242. break;
  243. #if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME
  244. case CLOCK_PROCESS_CPUTIME_ID:
  245. retval = hp_timing_gettime (clock_id, tp);
  246. break;
  247. #endif
  248. }
  249. return retval;
  250. }
  251. librt_hidden_def (clock_gettime)