2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
26 #define _POSIX_C_SOURCE 1
34 #ifdef HAVE_SYS_PRCTL_H
35 #include <sys/prctl.h>
39 #include <CoreServices/CoreServices.h>
40 #include <mach/mach.h>
41 #include <mach/mach_time.h>
49 #include <pulse/timeval.h>
50 #include <pulsecore/macro.h>
51 #include <pulsecore/core-error.h>
53 #include "core-rtclock.h"
56 static int64_t counter_freq = 0;
59 pa_usec_t pa_rtclock_age(const struct timeval *tv) {
63 return pa_timeval_diff(pa_rtclock_get(&now), tv);
66 struct timeval *pa_rtclock_get(struct timeval *tv) {
68 #if defined(OS_IS_DARWIN)
69 uint64_t val, abs_time = mach_absolute_time();
72 nanos = AbsoluteToNanoseconds(*(AbsoluteTime *) &abs_time);
73 val = *(uint64_t *) &nanos;
75 tv->tv_sec = val / PA_NSEC_PER_SEC;
76 tv->tv_usec = (val % PA_NSEC_PER_SEC) / PA_NSEC_PER_USEC;
80 #elif defined(HAVE_CLOCK_GETTIME)
83 #ifdef CLOCK_MONOTONIC
84 /* No locking or atomic ops for no_monotonic here */
85 static bool no_monotonic = false;
88 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
92 #endif /* CLOCK_MONOTONIC */
93 pa_assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
97 tv->tv_sec = ts.tv_sec;
98 tv->tv_usec = ts.tv_nsec / PA_NSEC_PER_USEC;
101 #elif defined(OS_IS_WIN32)
102 if (counter_freq > 0) {
105 pa_assert_se(QueryPerformanceCounter(&count));
107 tv->tv_sec = count.QuadPart / counter_freq;
108 tv->tv_usec = (count.QuadPart % counter_freq) * PA_USEC_PER_SEC / counter_freq;
112 #endif /* HAVE_CLOCK_GETTIME */
114 return pa_gettimeofday(tv);
117 bool pa_rtclock_hrtimer(void) {
119 #if defined (OS_IS_DARWIN)
120 mach_timebase_info_data_t tbi;
123 mach_timebase_info(&tbi);
125 /* nsec = nticks * (N/D) - we want 1 tick == resolution !? */
126 time_nsec = tbi.numer / tbi.denom;
127 return time_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
129 #elif defined(HAVE_CLOCK_GETTIME)
132 #ifdef CLOCK_MONOTONIC
134 if (clock_getres(CLOCK_MONOTONIC, &ts) >= 0)
135 return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
137 #endif /* CLOCK_MONOTONIC */
139 pa_assert_se(clock_getres(CLOCK_REALTIME, &ts) == 0);
140 return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
142 #elif defined(OS_IS_WIN32)
144 if (counter_freq > 0)
145 return counter_freq >= (int64_t) (PA_USEC_PER_SEC/PA_HRTIMER_THRESHOLD_USEC);
147 #endif /* HAVE_CLOCK_GETTIME */
152 #define TIMER_SLACK_NS (int) ((500 * PA_NSEC_PER_USEC))
154 void pa_rtclock_hrtimer_enable(void) {
156 #ifdef PR_SET_TIMERSLACK
159 if ((slack_ns = prctl(PR_GET_TIMERSLACK, 0, 0, 0, 0)) < 0) {
160 pa_log_info("PR_GET_TIMERSLACK/PR_SET_TIMERSLACK not supported.");
164 pa_log_debug("Timer slack is set to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC));
166 if (slack_ns > TIMER_SLACK_NS) {
167 slack_ns = TIMER_SLACK_NS;
169 pa_log_debug("Setting timer slack to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC));
171 if (prctl(PR_SET_TIMERSLACK, slack_ns, 0, 0, 0) < 0) {
172 pa_log_warn("PR_SET_TIMERSLACK failed: %s", pa_cstrerror(errno));
177 #elif defined(OS_IS_WIN32)
180 pa_assert_se(QueryPerformanceFrequency(&freq));
181 counter_freq = freq.QuadPart;
186 struct timeval* pa_rtclock_from_wallclock(struct timeval *tv) {
187 struct timeval wc_now, rt_now;
191 pa_gettimeofday(&wc_now);
192 pa_rtclock_get(&rt_now);
194 /* pa_timeval_sub() saturates on underflow! */
196 if (pa_timeval_cmp(&wc_now, tv) < 0)
197 pa_timeval_add(&rt_now, pa_timeval_diff(tv, &wc_now));
199 pa_timeval_sub(&rt_now, pa_timeval_diff(&wc_now, tv));
206 #ifdef HAVE_CLOCK_GETTIME
207 pa_usec_t pa_timespec_load(const struct timespec *ts) {
209 if (PA_UNLIKELY(!ts))
210 return PA_USEC_INVALID;
213 (pa_usec_t) ts->tv_sec * PA_USEC_PER_SEC +
214 (pa_usec_t) ts->tv_nsec / PA_NSEC_PER_USEC;
217 struct timespec* pa_timespec_store(struct timespec *ts, pa_usec_t v) {
220 if (PA_UNLIKELY(v == PA_USEC_INVALID)) {
221 ts->tv_sec = PA_INT_TYPE_MAX(time_t);
222 ts->tv_nsec = (long) (PA_NSEC_PER_SEC-1);
226 ts->tv_sec = (time_t) (v / PA_USEC_PER_SEC);
227 ts->tv_nsec = (long) ((v % PA_USEC_PER_SEC) * PA_NSEC_PER_USEC);
233 static struct timeval* wallclock_from_rtclock(struct timeval *tv) {
234 struct timeval wc_now, rt_now;
238 pa_gettimeofday(&wc_now);
239 pa_rtclock_get(&rt_now);
241 /* pa_timeval_sub() saturates on underflow! */
243 if (pa_timeval_cmp(&rt_now, tv) < 0)
244 pa_timeval_add(&wc_now, pa_timeval_diff(tv, &rt_now));
246 pa_timeval_sub(&wc_now, pa_timeval_diff(&rt_now, tv));
253 struct timeval* pa_timeval_rtstore(struct timeval *tv, pa_usec_t v, bool rtclock) {
256 if (v == PA_USEC_INVALID)
259 pa_timeval_store(tv, v);
262 tv->tv_usec |= PA_TIMEVAL_RTCLOCK;
264 wallclock_from_rtclock(tv);