OSDN Git Service

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