clock_gettime.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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. static inline int
  162. realtime_gettime (struct timespec *tp)
  163. {
  164. struct timeval tv;
  165. int retval = gettimeofday (&tv, NULL);
  166. if (retval == 0)
  167. /* Convert into `timespec'. */
  168. TIMEVAL_TO_TIMESPEC (&tv, tp);
  169. return retval;
  170. }
  171. librt_hidden_proto (clock_gettime)
  172. /* Get current value of CLOCK and store it in TP. */
  173. int
  174. clock_gettime (clockid_t clock_id, struct timespec *tp)
  175. {
  176. int retval = -1;
  177. #ifndef HANDLED_REALTIME
  178. struct timeval tv;
  179. #endif
  180. switch (clock_id)
  181. {
  182. #ifdef SYSDEP_GETTIME
  183. SYSDEP_GETTIME;
  184. #endif
  185. #ifndef HANDLED_REALTIME
  186. case CLOCK_REALTIME:
  187. retval = gettimeofday (&tv, NULL);
  188. if (retval == 0)
  189. TIMEVAL_TO_TIMESPEC (&tv, tp);
  190. break;
  191. #endif
  192. default:
  193. #ifdef SYSDEP_GETTIME_CPU
  194. SYSDEP_GETTIME_CPU;
  195. #endif
  196. __set_errno (EINVAL);
  197. break;
  198. }
  199. return retval;
  200. }
  201. librt_hidden_def (clock_gettime)