1/* clock_gettime -- Get the current time from a POSIX clockid_t. Unix version.
2 Copyright (C) 1999-2016 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. */
31static hp_timing_t freq;
32
33
34/* This function is defined in the thread library. */
35extern int __pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
36 struct timespec *tp)
37 __attribute__ ((__weak__));
38
39static int
40hp_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
78static inline int
79realtime_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. */
91int
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}
135weak_alias (__clock_gettime, clock_gettime)
136libc_hidden_def (__clock_gettime)
137