OSDN Git Service

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