1 | /* clock_gettime -- Get the current time from a POSIX clockid_t. Unix version. |
2 | Copyright (C) 1999-2019 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <errno.h> |
20 | #include <stdint.h> |
21 | #include <time.h> |
22 | #include <sys/time.h> |
23 | #include <libc-internal.h> |
24 | #include <ldsodefs.h> |
25 | |
26 | |
27 | #if HP_TIMING_AVAIL |
28 | /* Clock frequency of the processor. We make it a 64-bit variable |
29 | because some jokers are already playing with processors with more |
30 | than 4GHz. */ |
31 | static hp_timing_t freq; |
32 | |
33 | |
34 | /* This function is defined in the thread library. */ |
35 | extern int __pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq, |
36 | struct timespec *tp) |
37 | __attribute__ ((__weak__)); |
38 | |
39 | static int |
40 | hp_timing_gettime (clockid_t clock_id, struct timespec *tp) |
41 | { |
42 | hp_timing_t tsc; |
43 | |
44 | if (__glibc_unlikely (freq == 0)) |
45 | { |
46 | /* This can only happen if we haven't initialized the `freq' |
47 | variable yet. Do this now. We don't have to protect this |
48 | code against multiple execution since all of them should |
49 | lead to the same result. */ |
50 | freq = __get_clockfreq (); |
51 | if (__glibc_unlikely (freq == 0)) |
52 | /* Something went wrong. */ |
53 | return -1; |
54 | } |
55 | |
56 | if (clock_id != CLOCK_PROCESS_CPUTIME_ID |
57 | && __pthread_clock_gettime != NULL) |
58 | return __pthread_clock_gettime (clock_id, freq, tp); |
59 | |
60 | /* Get the current counter. */ |
61 | HP_TIMING_NOW (tsc); |
62 | |
63 | /* Compute the offset since the start time of the process. */ |
64 | tsc -= GL(dl_cpuclock_offset); |
65 | |
66 | /* Compute the seconds. */ |
67 | tp->tv_sec = tsc / freq; |
68 | |
69 | /* And the nanoseconds. This computation should be stable until |
70 | we get machines with about 16GHz frequency. */ |
71 | tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq; |
72 | |
73 | return 0; |
74 | } |
75 | #endif |
76 | |
77 | |
78 | static inline int |
79 | realtime_gettime (struct timespec *tp) |
80 | { |
81 | struct timeval tv; |
82 | int retval = __gettimeofday (&tv, NULL); |
83 | if (retval == 0) |
84 | /* Convert into `timespec'. */ |
85 | TIMEVAL_TO_TIMESPEC (&tv, tp); |
86 | return retval; |
87 | } |
88 | |
89 | |
90 | /* Get current value of CLOCK and store it in TP. */ |
91 | int |
92 | __clock_gettime (clockid_t clock_id, struct timespec *tp) |
93 | { |
94 | int retval = -1; |
95 | |
96 | switch (clock_id) |
97 | { |
98 | #ifdef SYSDEP_GETTIME |
99 | SYSDEP_GETTIME; |
100 | #endif |
101 | |
102 | #ifndef HANDLED_REALTIME |
103 | case CLOCK_REALTIME: |
104 | { |
105 | struct timeval tv; |
106 | retval = __gettimeofday (&tv, NULL); |
107 | if (retval == 0) |
108 | TIMEVAL_TO_TIMESPEC (&tv, tp); |
109 | } |
110 | break; |
111 | #endif |
112 | |
113 | default: |
114 | #ifdef SYSDEP_GETTIME_CPU |
115 | SYSDEP_GETTIME_CPU (clock_id, tp); |
116 | #endif |
117 | #if HP_TIMING_AVAIL |
118 | if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1)) |
119 | == CLOCK_THREAD_CPUTIME_ID) |
120 | retval = hp_timing_gettime (clock_id, tp); |
121 | else |
122 | #endif |
123 | __set_errno (EINVAL); |
124 | break; |
125 | |
126 | #if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME |
127 | case CLOCK_PROCESS_CPUTIME_ID: |
128 | retval = hp_timing_gettime (clock_id, tp); |
129 | break; |
130 | #endif |
131 | } |
132 | |
133 | return retval; |
134 | } |
135 | weak_alias (__clock_gettime, clock_gettime) |
136 | libc_hidden_def (__clock_gettime) |
137 | |