]>
Commit | Line | Data |
---|---|---|
2f4f3bd4 | 1 | /* clock_gettime -- Get current time from a POSIX clockid_t. Linux version. |
a77d3c17 | 2 | Copyright (C) 2003,2004,2005,2006,2007,2010,2011 Free Software Foundation, Inc. |
ad0e8eb0 UD |
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 | |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
ad0e8eb0 UD |
18 | |
19 | #include <sysdep.h> | |
2f4f3bd4 | 20 | #include <errno.h> |
6ba85a6d | 21 | #include <time.h> |
2f4f3bd4 | 22 | #include "kernel-posix-cpu-timers.h" |
6ddd37a4 | 23 | #include <kernel-features.h> |
ad0e8eb0 | 24 | |
8c2e201b UD |
25 | #ifndef HAVE_CLOCK_GETTIME_VSYSCALL |
26 | # undef INTERNAL_VSYSCALL | |
27 | # define INTERNAL_VSYSCALL INTERNAL_SYSCALL | |
28 | # undef INLINE_VSYSCALL | |
29 | # define INLINE_VSYSCALL INLINE_SYSCALL | |
30 | #else | |
31 | # include <bits/libc-vdso.h> | |
32 | #endif | |
ad0e8eb0 | 33 | |
a77d3c17 UD |
34 | #ifndef SYSCALL_GETTIME |
35 | # define SYSCALL_GETTIME(id, tp) \ | |
36 | INLINE_VSYSCALL (clock_gettime, 2, id, tp) | |
37 | #endif | |
38 | #ifndef INTERNAL_GETTIME | |
39 | # define INTERNAL_GETTIME(id, tp) \ | |
40 | INTERNAL_VSYSCALL (clock_gettime, err, 2, id, tp) | |
41 | #endif | |
2f4f3bd4 | 42 | |
ad0e8eb0 | 43 | #ifdef __ASSUME_POSIX_TIMERS |
2f4f3bd4 | 44 | |
ad0e8eb0 UD |
45 | /* This means the REALTIME and MONOTONIC clock are definitely |
46 | supported in the kernel. */ | |
7edb22ef UD |
47 | # define SYSDEP_GETTIME \ |
48 | SYSDEP_GETTIME_CPUTIME; \ | |
ad0e8eb0 UD |
49 | case CLOCK_REALTIME: \ |
50 | case CLOCK_MONOTONIC: \ | |
a77d3c17 UD |
51 | retval = SYSCALL_GETTIME (clock_id, tp); \ |
52 | break | |
2f4f3bd4 RM |
53 | |
54 | # define __libc_missing_posix_timers 0 | |
ad0e8eb0 UD |
55 | #elif defined __NR_clock_gettime |
56 | /* Is the syscall known to exist? */ | |
57 | int __libc_missing_posix_timers attribute_hidden; | |
58 | ||
2f4f3bd4 RM |
59 | static inline int |
60 | maybe_syscall_gettime (clockid_t clock_id, struct timespec *tp) | |
61 | { | |
62 | int e = EINVAL; | |
63 | ||
64 | if (!__libc_missing_posix_timers) | |
65 | { | |
66 | INTERNAL_SYSCALL_DECL (err); | |
a77d3c17 | 67 | int r = INTERNAL_GETTIME (clock_id, tp); |
2f4f3bd4 RM |
68 | if (!INTERNAL_SYSCALL_ERROR_P (r, err)) |
69 | return 0; | |
70 | ||
71 | e = INTERNAL_SYSCALL_ERRNO (r, err); | |
72 | if (e == ENOSYS) | |
73 | { | |
74 | __libc_missing_posix_timers = 1; | |
75 | e = EINVAL; | |
76 | } | |
77 | } | |
78 | ||
79 | return e; | |
80 | } | |
81 | ||
ad0e8eb0 UD |
82 | /* The REALTIME and MONOTONIC clock might be available. Try the |
83 | syscall first. */ | |
7edb22ef UD |
84 | # define SYSDEP_GETTIME \ |
85 | SYSDEP_GETTIME_CPUTIME; \ | |
ad0e8eb0 UD |
86 | case CLOCK_REALTIME: \ |
87 | case CLOCK_MONOTONIC: \ | |
89a4419c UD |
88 | case CLOCK_MONOTONIC_RAW: \ |
89 | case CLOCK_REALTIME_COARSE: \ | |
90 | case CLOCK_MONOTONIC_COARSE: \ | |
2f4f3bd4 RM |
91 | retval = maybe_syscall_gettime (clock_id, tp); \ |
92 | if (retval == 0) \ | |
93 | break; \ | |
94 | /* Fallback code. */ \ | |
95 | if (retval == EINVAL && clock_id == CLOCK_REALTIME) \ | |
96 | retval = realtime_gettime (tp); \ | |
a77d3c17 | 97 | else \ |
2f4f3bd4 RM |
98 | { \ |
99 | __set_errno (retval); \ | |
100 | retval = -1; \ | |
101 | } \ | |
7edb22ef | 102 | break |
ad0e8eb0 UD |
103 | #endif |
104 | ||
105 | #ifdef __NR_clock_gettime | |
106 | /* We handled the REALTIME clock here. */ | |
107 | # define HANDLED_REALTIME 1 | |
2f4f3bd4 RM |
108 | # define HANDLED_CPUTIME 1 |
109 | ||
110 | # if __ASSUME_POSIX_CPU_TIMERS > 0 | |
111 | ||
446514f9 AS |
112 | # define SYSDEP_GETTIME_CPU(clock_id, tp) \ |
113 | retval = SYSCALL_GETTIME (clock_id, tp); \ | |
114 | break | |
2f4f3bd4 RM |
115 | # define SYSDEP_GETTIME_CPUTIME /* Default catches them too. */ |
116 | ||
117 | # else | |
118 | ||
119 | int __libc_missing_posix_cpu_timers attribute_hidden; | |
120 | ||
121 | static int | |
122 | maybe_syscall_gettime_cpu (clockid_t clock_id, struct timespec *tp) | |
123 | { | |
124 | int e = EINVAL; | |
125 | ||
126 | if (!__libc_missing_posix_cpu_timers) | |
127 | { | |
128 | INTERNAL_SYSCALL_DECL (err); | |
a77d3c17 | 129 | int r = INTERNAL_GETTIME (clock_id, tp); |
2f4f3bd4 RM |
130 | if (!INTERNAL_SYSCALL_ERROR_P (r, err)) |
131 | return 0; | |
132 | ||
133 | e = INTERNAL_SYSCALL_ERRNO (r, err); | |
134 | # ifndef __ASSUME_POSIX_TIMERS | |
135 | if (e == ENOSYS) | |
136 | { | |
137 | __libc_missing_posix_timers = 1; | |
138 | __libc_missing_posix_cpu_timers = 1; | |
139 | e = EINVAL; | |
140 | } | |
141 | else | |
142 | # endif | |
143 | { | |
144 | if (e == EINVAL) | |
145 | { | |
4eb375fe | 146 | # ifdef HAVE_CLOCK_GETRES_VSYSCALL |
2f4f3bd4 RM |
147 | /* Check whether the kernel supports CPU clocks at all. |
148 | If not, record it for the future. */ | |
8c2e201b | 149 | r = INTERNAL_VSYSCALL (clock_getres, err, 2, |
4eb375fe UD |
150 | MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED), |
151 | NULL); | |
152 | # else | |
153 | /* Check whether the kernel supports CPU clocks at all. | |
154 | If not, record it for the future. */ | |
155 | r = INTERNAL_SYSCALL (clock_getres, err, 2, | |
2f4f3bd4 RM |
156 | MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED), |
157 | NULL); | |
4eb375fe | 158 | # endif |
2f4f3bd4 RM |
159 | if (INTERNAL_SYSCALL_ERROR_P (r, err)) |
160 | __libc_missing_posix_cpu_timers = 1; | |
161 | } | |
162 | } | |
163 | } | |
164 | ||
165 | return e; | |
166 | } | |
167 | ||
7edb22ef | 168 | # define SYSDEP_GETTIME_CPU(clock_id, tp) \ |
2f4f3bd4 RM |
169 | retval = maybe_syscall_gettime_cpu (clock_id, tp); \ |
170 | if (retval == 0) \ | |
171 | break; \ | |
172 | if (retval != EINVAL || !__libc_missing_posix_cpu_timers) \ | |
173 | { \ | |
174 | __set_errno (retval); \ | |
175 | retval = -1; \ | |
176 | break; \ | |
177 | } \ | |
178 | retval = -1 /* Otherwise continue on to the HP_TIMING version. */; | |
179 | ||
180 | static inline int | |
181 | maybe_syscall_gettime_cputime (clockid_t clock_id, struct timespec *tp) | |
182 | { | |
183 | return maybe_syscall_gettime_cpu | |
184 | (clock_id == CLOCK_THREAD_CPUTIME_ID | |
185 | ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED) | |
186 | : MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED), | |
187 | tp); | |
188 | } | |
189 | ||
190 | # define SYSDEP_GETTIME_CPUTIME \ | |
191 | case CLOCK_PROCESS_CPUTIME_ID: \ | |
192 | case CLOCK_THREAD_CPUTIME_ID: \ | |
193 | retval = maybe_syscall_gettime_cputime (clock_id, tp); \ | |
194 | if (retval == 0) \ | |
195 | break; \ | |
196 | if (retval != EINVAL || !__libc_missing_posix_cpu_timers) \ | |
197 | { \ | |
198 | __set_errno (retval); \ | |
199 | retval = -1; \ | |
200 | break; \ | |
201 | } \ | |
202 | retval = hp_timing_gettime (clock_id, tp); \ | |
7edb22ef | 203 | break |
2f4f3bd4 RM |
204 | # if !HP_TIMING_AVAIL |
205 | # define hp_timing_gettime(clock_id, tp) (__set_errno (EINVAL), -1) | |
206 | # endif | |
207 | ||
208 | # endif | |
ad0e8eb0 UD |
209 | #endif |
210 | ||
211 | #include <sysdeps/unix/clock_gettime.c> |