Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : : Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 : :
7 : : PulseAudio is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU Lesser General Public License as
9 : : published by the Free Software Foundation; either version 2.1 of the
10 : : License, or (at your option) any later version.
11 : :
12 : : PulseAudio is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : Lesser General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU Lesser General Public
18 : : License along with PulseAudio; if not, write to the Free Software
19 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 : : USA.
21 : : ***/
22 : :
23 : : #ifdef HAVE_CONFIG_H
24 : : #include <config.h>
25 : : #endif
26 : :
27 : : #ifdef OS_IS_DARWIN
28 : : #define _POSIX_C_SOURCE 1
29 : : #endif
30 : :
31 : : #include <stddef.h>
32 : : #include <time.h>
33 : : #include <sys/time.h>
34 : : #include <errno.h>
35 : :
36 : : #ifdef HAVE_SYS_PRCTL_H
37 : : #include <sys/prctl.h>
38 : : #endif
39 : :
40 : : #ifdef OS_IS_DARWIN
41 : : #include <CoreServices/CoreServices.h>
42 : : #include <mach/mach.h>
43 : : #include <mach/mach_time.h>
44 : : #include <unistd.h>
45 : : #endif
46 : :
47 : : #ifdef HAVE_WINDOWS_H
48 : : #include <windows.h>
49 : : #endif
50 : :
51 : : #include <pulse/timeval.h>
52 : : #include <pulsecore/macro.h>
53 : : #include <pulsecore/core-error.h>
54 : :
55 : : #include "core-rtclock.h"
56 : :
57 : : #ifdef OS_IS_WIN32
58 : : static int64_t counter_freq = 0;
59 : : #endif
60 : :
61 : 0 : pa_usec_t pa_rtclock_age(const struct timeval *tv) {
62 : : struct timeval now;
63 [ # # ]: 0 : pa_assert(tv);
64 : :
65 : 0 : return pa_timeval_diff(pa_rtclock_get(&now), tv);
66 : : }
67 : :
68 : 10 : struct timeval *pa_rtclock_get(struct timeval *tv) {
69 : :
70 : : #if defined(OS_IS_DARWIN)
71 : : uint64_t val, abs_time = mach_absolute_time();
72 : : Nanoseconds nanos;
73 : :
74 : : nanos = AbsoluteToNanoseconds(*(AbsoluteTime *) &abs_time);
75 : : val = *(uint64_t *) &nanos;
76 : :
77 : : tv->tv_sec = val / PA_NSEC_PER_SEC;
78 : : tv->tv_usec = (val % PA_NSEC_PER_SEC) / PA_NSEC_PER_USEC;
79 : :
80 : : return tv;
81 : :
82 : : #elif defined(HAVE_CLOCK_GETTIME)
83 : : struct timespec ts;
84 : :
85 : : #ifdef CLOCK_MONOTONIC
86 : : /* No locking or atomic ops for no_monotonic here */
87 : : static pa_bool_t no_monotonic = FALSE;
88 : :
89 [ + - ]: 10 : if (!no_monotonic)
90 [ - + ]: 10 : if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
91 : 0 : no_monotonic = TRUE;
92 : :
93 [ - + ]: 10 : if (no_monotonic)
94 : : #endif /* CLOCK_MONOTONIC */
95 [ # # ]: 0 : pa_assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
96 : :
97 [ - + ]: 10 : pa_assert(tv);
98 : :
99 : 10 : tv->tv_sec = ts.tv_sec;
100 : 10 : tv->tv_usec = ts.tv_nsec / PA_NSEC_PER_USEC;
101 : :
102 : : return tv;
103 : : #elif defined(OS_IS_WIN32)
104 : : if (counter_freq > 0) {
105 : : LARGE_INTEGER count;
106 : :
107 : : pa_assert_se(QueryPerformanceCounter(&count));
108 : :
109 : : tv->tv_sec = count.QuadPart / counter_freq;
110 : : tv->tv_usec = (count.QuadPart % counter_freq) * PA_USEC_PER_SEC / counter_freq;
111 : :
112 : : return tv;
113 : : }
114 : : #endif /* HAVE_CLOCK_GETTIME */
115 : :
116 : : return pa_gettimeofday(tv);
117 : : }
118 : :
119 : 0 : pa_bool_t pa_rtclock_hrtimer(void) {
120 : :
121 : : #if defined (OS_IS_DARWIN)
122 : : mach_timebase_info_data_t tbi;
123 : : uint64_t time_nsec;
124 : :
125 : : mach_timebase_info(&tbi);
126 : :
127 : : /* nsec = nticks * (N/D) - we want 1 tick == resolution !? */
128 : : time_nsec = tbi.numer / tbi.denom;
129 : : return time_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
130 : :
131 : : #elif defined(HAVE_CLOCK_GETTIME)
132 : : struct timespec ts;
133 : :
134 : : #ifdef CLOCK_MONOTONIC
135 : :
136 [ # # ]: 0 : if (clock_getres(CLOCK_MONOTONIC, &ts) >= 0)
137 [ # # ][ # # ]: 0 : return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
138 : :
139 : : #endif /* CLOCK_MONOTONIC */
140 : :
141 [ # # ]: 0 : pa_assert_se(clock_getres(CLOCK_REALTIME, &ts) == 0);
142 [ # # ][ # # ]: 0 : return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
143 : :
144 : : #elif defined(OS_IS_WIN32)
145 : :
146 : : if (counter_freq > 0)
147 : : return counter_freq >= (int64_t) (PA_USEC_PER_SEC/PA_HRTIMER_THRESHOLD_USEC);
148 : :
149 : : #endif /* HAVE_CLOCK_GETTIME */
150 : :
151 : : return FALSE;
152 : : }
153 : :
154 : : #define TIMER_SLACK_NS (int) ((500 * PA_NSEC_PER_USEC))
155 : :
156 : 0 : void pa_rtclock_hrtimer_enable(void) {
157 : :
158 : : #ifdef PR_SET_TIMERSLACK
159 : : int slack_ns;
160 : :
161 [ # # ]: 0 : if ((slack_ns = prctl(PR_GET_TIMERSLACK, 0, 0, 0, 0)) < 0) {
162 : 0 : pa_log_info("PR_GET_TIMERSLACK/PR_SET_TIMERSLACK not supported.");
163 : 0 : return;
164 : : }
165 : :
166 : 0 : pa_log_debug("Timer slack is set to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC));
167 : :
168 [ # # ]: 0 : if (slack_ns > TIMER_SLACK_NS) {
169 : 0 : slack_ns = TIMER_SLACK_NS;
170 : :
171 : 0 : pa_log_debug("Setting timer slack to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC));
172 : :
173 [ # # ]: 0 : if (prctl(PR_SET_TIMERSLACK, slack_ns, 0, 0, 0) < 0) {
174 : 0 : pa_log_warn("PR_SET_TIMERSLACK failed: %s", pa_cstrerror(errno));
175 : 0 : return;
176 : : }
177 : : }
178 : :
179 : : #elif defined(OS_IS_WIN32)
180 : : LARGE_INTEGER freq;
181 : :
182 : : pa_assert_se(QueryPerformanceFrequency(&freq));
183 : : counter_freq = freq.QuadPart;
184 : :
185 : : #endif
186 : : }
187 : :
188 : 0 : struct timeval* pa_rtclock_from_wallclock(struct timeval *tv) {
189 : : struct timeval wc_now, rt_now;
190 : :
191 [ # # ]: 0 : pa_assert(tv);
192 : :
193 : 0 : pa_gettimeofday(&wc_now);
194 : 0 : pa_rtclock_get(&rt_now);
195 : :
196 : : /* pa_timeval_sub() saturates on underflow! */
197 : :
198 [ # # ]: 0 : if (pa_timeval_cmp(&wc_now, tv) < 0)
199 : 0 : pa_timeval_add(&rt_now, pa_timeval_diff(tv, &wc_now));
200 : : else
201 : 0 : pa_timeval_sub(&rt_now, pa_timeval_diff(&wc_now, tv));
202 : :
203 : 0 : *tv = rt_now;
204 : :
205 : 0 : return tv;
206 : : }
207 : :
208 : : #ifdef HAVE_CLOCK_GETTIME
209 : 0 : pa_usec_t pa_timespec_load(const struct timespec *ts) {
210 : :
211 [ # # ]: 0 : if (PA_UNLIKELY(!ts))
212 : : return PA_USEC_INVALID;
213 : :
214 : 0 : return
215 : 0 : (pa_usec_t) ts->tv_sec * PA_USEC_PER_SEC +
216 : 0 : (pa_usec_t) ts->tv_nsec / PA_NSEC_PER_USEC;
217 : : }
218 : :
219 : 1 : struct timespec* pa_timespec_store(struct timespec *ts, pa_usec_t v) {
220 [ - + ]: 1 : pa_assert(ts);
221 : :
222 [ - + ]: 1 : if (PA_UNLIKELY(v == PA_USEC_INVALID)) {
223 : 0 : ts->tv_sec = PA_INT_TYPE_MAX(time_t);
224 : 0 : ts->tv_nsec = (long) (PA_NSEC_PER_SEC-1);
225 : 0 : return NULL;
226 : : }
227 : :
228 : 1 : ts->tv_sec = (time_t) (v / PA_USEC_PER_SEC);
229 : 1 : ts->tv_nsec = (long) ((v % PA_USEC_PER_SEC) * PA_NSEC_PER_USEC);
230 : :
231 : 1 : return ts;
232 : : }
233 : : #endif
234 : :
235 : 0 : static struct timeval* wallclock_from_rtclock(struct timeval *tv) {
236 : : struct timeval wc_now, rt_now;
237 : :
238 [ # # ]: 0 : pa_assert(tv);
239 : :
240 : 0 : pa_gettimeofday(&wc_now);
241 : 0 : pa_rtclock_get(&rt_now);
242 : :
243 : : /* pa_timeval_sub() saturates on underflow! */
244 : :
245 [ # # ]: 0 : if (pa_timeval_cmp(&rt_now, tv) < 0)
246 : 0 : pa_timeval_add(&wc_now, pa_timeval_diff(tv, &rt_now));
247 : : else
248 : 0 : pa_timeval_sub(&wc_now, pa_timeval_diff(&rt_now, tv));
249 : :
250 : 0 : *tv = wc_now;
251 : :
252 : 0 : return tv;
253 : : }
254 : :
255 : 5 : struct timeval* pa_timeval_rtstore(struct timeval *tv, pa_usec_t v, pa_bool_t rtclock) {
256 [ - + ]: 5 : pa_assert(tv);
257 : :
258 [ + - ]: 5 : if (v == PA_USEC_INVALID)
259 : : return NULL;
260 : :
261 : 5 : pa_timeval_store(tv, v);
262 : :
263 [ + - ]: 5 : if (rtclock)
264 : 5 : tv->tv_usec |= PA_TIMEVAL_RTCLOCK;
265 : : else
266 : 5 : wallclock_from_rtclock(tv);
267 : :
268 : : return tv;
269 : : }
|