153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 953a5a1b3Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of the 1053a5a1b3Sopenharmony_ci License, or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci Lesser General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 1853a5a1b3Sopenharmony_ci License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#ifdef OS_IS_DARWIN 2653a5a1b3Sopenharmony_ci#define _POSIX_C_SOURCE 1 2753a5a1b3Sopenharmony_ci#endif 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <stddef.h> 3053a5a1b3Sopenharmony_ci#include <time.h> 3153a5a1b3Sopenharmony_ci#include <sys/time.h> 3253a5a1b3Sopenharmony_ci#include <errno.h> 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_PRCTL_H 3553a5a1b3Sopenharmony_ci#include <sys/prctl.h> 3653a5a1b3Sopenharmony_ci#endif 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci#ifdef OS_IS_DARWIN 3953a5a1b3Sopenharmony_ci#include <CoreServices/CoreServices.h> 4053a5a1b3Sopenharmony_ci#include <mach/mach.h> 4153a5a1b3Sopenharmony_ci#include <mach/mach_time.h> 4253a5a1b3Sopenharmony_ci#include <unistd.h> 4353a5a1b3Sopenharmony_ci#endif 4453a5a1b3Sopenharmony_ci 4553a5a1b3Sopenharmony_ci#ifdef HAVE_WINDOWS_H 4653a5a1b3Sopenharmony_ci#include <windows.h> 4753a5a1b3Sopenharmony_ci#endif 4853a5a1b3Sopenharmony_ci 4953a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 5053a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 5153a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 5253a5a1b3Sopenharmony_ci 5353a5a1b3Sopenharmony_ci#include "core-rtclock.h" 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 5653a5a1b3Sopenharmony_cistatic int64_t counter_freq = 0; 5753a5a1b3Sopenharmony_ci#endif 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_cipa_usec_t pa_rtclock_age(const struct timeval *tv) { 6053a5a1b3Sopenharmony_ci struct timeval now; 6153a5a1b3Sopenharmony_ci pa_assert(tv); 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_ci return pa_timeval_diff(pa_rtclock_get(&now), tv); 6453a5a1b3Sopenharmony_ci} 6553a5a1b3Sopenharmony_ci 6653a5a1b3Sopenharmony_cistruct timeval *pa_rtclock_get(struct timeval *tv) { 6753a5a1b3Sopenharmony_ci 6853a5a1b3Sopenharmony_ci#if defined(OS_IS_DARWIN) 6953a5a1b3Sopenharmony_ci uint64_t val, abs_time = mach_absolute_time(); 7053a5a1b3Sopenharmony_ci Nanoseconds nanos; 7153a5a1b3Sopenharmony_ci 7253a5a1b3Sopenharmony_ci nanos = AbsoluteToNanoseconds(*(AbsoluteTime *) &abs_time); 7353a5a1b3Sopenharmony_ci val = *(uint64_t *) &nanos; 7453a5a1b3Sopenharmony_ci 7553a5a1b3Sopenharmony_ci tv->tv_sec = val / PA_NSEC_PER_SEC; 7653a5a1b3Sopenharmony_ci tv->tv_usec = (val % PA_NSEC_PER_SEC) / PA_NSEC_PER_USEC; 7753a5a1b3Sopenharmony_ci 7853a5a1b3Sopenharmony_ci return tv; 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_ci#elif defined(HAVE_CLOCK_GETTIME) 8153a5a1b3Sopenharmony_ci struct timespec ts; 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_ci#ifdef CLOCK_MONOTONIC 8453a5a1b3Sopenharmony_ci /* No locking or atomic ops for no_monotonic here */ 8553a5a1b3Sopenharmony_ci static bool no_monotonic = false; 8653a5a1b3Sopenharmony_ci 8753a5a1b3Sopenharmony_ci if (!no_monotonic) 8853a5a1b3Sopenharmony_ci if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) 8953a5a1b3Sopenharmony_ci no_monotonic = true; 9053a5a1b3Sopenharmony_ci 9153a5a1b3Sopenharmony_ci if (no_monotonic) 9253a5a1b3Sopenharmony_ci#endif /* CLOCK_MONOTONIC */ 9353a5a1b3Sopenharmony_ci pa_assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); 9453a5a1b3Sopenharmony_ci 9553a5a1b3Sopenharmony_ci pa_assert(tv); 9653a5a1b3Sopenharmony_ci 9753a5a1b3Sopenharmony_ci tv->tv_sec = ts.tv_sec; 9853a5a1b3Sopenharmony_ci tv->tv_usec = ts.tv_nsec / PA_NSEC_PER_USEC; 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci return tv; 10153a5a1b3Sopenharmony_ci#elif defined(OS_IS_WIN32) 10253a5a1b3Sopenharmony_ci if (counter_freq > 0) { 10353a5a1b3Sopenharmony_ci LARGE_INTEGER count; 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci pa_assert_se(QueryPerformanceCounter(&count)); 10653a5a1b3Sopenharmony_ci 10753a5a1b3Sopenharmony_ci tv->tv_sec = count.QuadPart / counter_freq; 10853a5a1b3Sopenharmony_ci tv->tv_usec = (count.QuadPart % counter_freq) * PA_USEC_PER_SEC / counter_freq; 10953a5a1b3Sopenharmony_ci 11053a5a1b3Sopenharmony_ci return tv; 11153a5a1b3Sopenharmony_ci } 11253a5a1b3Sopenharmony_ci#endif /* HAVE_CLOCK_GETTIME */ 11353a5a1b3Sopenharmony_ci 11453a5a1b3Sopenharmony_ci return pa_gettimeofday(tv); 11553a5a1b3Sopenharmony_ci} 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_cibool pa_rtclock_hrtimer(void) { 11853a5a1b3Sopenharmony_ci 11953a5a1b3Sopenharmony_ci#if defined (OS_IS_DARWIN) 12053a5a1b3Sopenharmony_ci mach_timebase_info_data_t tbi; 12153a5a1b3Sopenharmony_ci uint64_t time_nsec; 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_ci mach_timebase_info(&tbi); 12453a5a1b3Sopenharmony_ci 12553a5a1b3Sopenharmony_ci /* nsec = nticks * (N/D) - we want 1 tick == resolution !? */ 12653a5a1b3Sopenharmony_ci time_nsec = tbi.numer / tbi.denom; 12753a5a1b3Sopenharmony_ci return time_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC); 12853a5a1b3Sopenharmony_ci 12953a5a1b3Sopenharmony_ci#elif defined(HAVE_CLOCK_GETTIME) 13053a5a1b3Sopenharmony_ci struct timespec ts; 13153a5a1b3Sopenharmony_ci 13253a5a1b3Sopenharmony_ci#ifdef CLOCK_MONOTONIC 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci if (clock_getres(CLOCK_MONOTONIC, &ts) >= 0) 13553a5a1b3Sopenharmony_ci return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC); 13653a5a1b3Sopenharmony_ci 13753a5a1b3Sopenharmony_ci#endif /* CLOCK_MONOTONIC */ 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_ci pa_assert_se(clock_getres(CLOCK_REALTIME, &ts) == 0); 14053a5a1b3Sopenharmony_ci return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC); 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_ci#elif defined(OS_IS_WIN32) 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ci if (counter_freq > 0) 14553a5a1b3Sopenharmony_ci return counter_freq >= (int64_t) (PA_USEC_PER_SEC/PA_HRTIMER_THRESHOLD_USEC); 14653a5a1b3Sopenharmony_ci 14753a5a1b3Sopenharmony_ci#endif /* HAVE_CLOCK_GETTIME */ 14853a5a1b3Sopenharmony_ci 14953a5a1b3Sopenharmony_ci return false; 15053a5a1b3Sopenharmony_ci} 15153a5a1b3Sopenharmony_ci 15253a5a1b3Sopenharmony_ci#define TIMER_SLACK_NS (int) ((500 * PA_NSEC_PER_USEC)) 15353a5a1b3Sopenharmony_ci 15453a5a1b3Sopenharmony_civoid pa_rtclock_hrtimer_enable(void) { 15553a5a1b3Sopenharmony_ci 15653a5a1b3Sopenharmony_ci#ifdef PR_SET_TIMERSLACK 15753a5a1b3Sopenharmony_ci int slack_ns; 15853a5a1b3Sopenharmony_ci 15953a5a1b3Sopenharmony_ci if ((slack_ns = prctl(PR_GET_TIMERSLACK, 0, 0, 0, 0)) < 0) { 16053a5a1b3Sopenharmony_ci pa_log_info("PR_GET_TIMERSLACK/PR_SET_TIMERSLACK not supported."); 16153a5a1b3Sopenharmony_ci return; 16253a5a1b3Sopenharmony_ci } 16353a5a1b3Sopenharmony_ci 16453a5a1b3Sopenharmony_ci pa_log_debug("Timer slack is set to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC)); 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci if (slack_ns > TIMER_SLACK_NS) { 16753a5a1b3Sopenharmony_ci slack_ns = TIMER_SLACK_NS; 16853a5a1b3Sopenharmony_ci 16953a5a1b3Sopenharmony_ci pa_log_debug("Setting timer slack to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC)); 17053a5a1b3Sopenharmony_ci 17153a5a1b3Sopenharmony_ci if (prctl(PR_SET_TIMERSLACK, slack_ns, 0, 0, 0) < 0) { 17253a5a1b3Sopenharmony_ci pa_log_warn("PR_SET_TIMERSLACK failed: %s", pa_cstrerror(errno)); 17353a5a1b3Sopenharmony_ci return; 17453a5a1b3Sopenharmony_ci } 17553a5a1b3Sopenharmony_ci } 17653a5a1b3Sopenharmony_ci 17753a5a1b3Sopenharmony_ci#elif defined(OS_IS_WIN32) 17853a5a1b3Sopenharmony_ci LARGE_INTEGER freq; 17953a5a1b3Sopenharmony_ci 18053a5a1b3Sopenharmony_ci pa_assert_se(QueryPerformanceFrequency(&freq)); 18153a5a1b3Sopenharmony_ci counter_freq = freq.QuadPart; 18253a5a1b3Sopenharmony_ci 18353a5a1b3Sopenharmony_ci#endif 18453a5a1b3Sopenharmony_ci} 18553a5a1b3Sopenharmony_ci 18653a5a1b3Sopenharmony_cistruct timeval* pa_rtclock_from_wallclock(struct timeval *tv) { 18753a5a1b3Sopenharmony_ci struct timeval wc_now, rt_now; 18853a5a1b3Sopenharmony_ci 18953a5a1b3Sopenharmony_ci pa_assert(tv); 19053a5a1b3Sopenharmony_ci 19153a5a1b3Sopenharmony_ci pa_gettimeofday(&wc_now); 19253a5a1b3Sopenharmony_ci pa_rtclock_get(&rt_now); 19353a5a1b3Sopenharmony_ci 19453a5a1b3Sopenharmony_ci /* pa_timeval_sub() saturates on underflow! */ 19553a5a1b3Sopenharmony_ci 19653a5a1b3Sopenharmony_ci if (pa_timeval_cmp(&wc_now, tv) < 0) 19753a5a1b3Sopenharmony_ci pa_timeval_add(&rt_now, pa_timeval_diff(tv, &wc_now)); 19853a5a1b3Sopenharmony_ci else 19953a5a1b3Sopenharmony_ci pa_timeval_sub(&rt_now, pa_timeval_diff(&wc_now, tv)); 20053a5a1b3Sopenharmony_ci 20153a5a1b3Sopenharmony_ci *tv = rt_now; 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci return tv; 20453a5a1b3Sopenharmony_ci} 20553a5a1b3Sopenharmony_ci 20653a5a1b3Sopenharmony_ci#ifdef HAVE_CLOCK_GETTIME 20753a5a1b3Sopenharmony_cipa_usec_t pa_timespec_load(const struct timespec *ts) { 20853a5a1b3Sopenharmony_ci 20953a5a1b3Sopenharmony_ci if (PA_UNLIKELY(!ts)) 21053a5a1b3Sopenharmony_ci return PA_USEC_INVALID; 21153a5a1b3Sopenharmony_ci 21253a5a1b3Sopenharmony_ci return 21353a5a1b3Sopenharmony_ci (pa_usec_t) ts->tv_sec * PA_USEC_PER_SEC + 21453a5a1b3Sopenharmony_ci (pa_usec_t) ts->tv_nsec / PA_NSEC_PER_USEC; 21553a5a1b3Sopenharmony_ci} 21653a5a1b3Sopenharmony_ci 21753a5a1b3Sopenharmony_cistruct timespec* pa_timespec_store(struct timespec *ts, pa_usec_t v) { 21853a5a1b3Sopenharmony_ci pa_assert(ts); 21953a5a1b3Sopenharmony_ci 22053a5a1b3Sopenharmony_ci if (PA_UNLIKELY(v == PA_USEC_INVALID)) { 22153a5a1b3Sopenharmony_ci ts->tv_sec = PA_INT_TYPE_MAX(time_t); 22253a5a1b3Sopenharmony_ci ts->tv_nsec = (long) (PA_NSEC_PER_SEC-1); 22353a5a1b3Sopenharmony_ci return NULL; 22453a5a1b3Sopenharmony_ci } 22553a5a1b3Sopenharmony_ci 22653a5a1b3Sopenharmony_ci ts->tv_sec = (time_t) (v / PA_USEC_PER_SEC); 22753a5a1b3Sopenharmony_ci ts->tv_nsec = (long) ((v % PA_USEC_PER_SEC) * PA_NSEC_PER_USEC); 22853a5a1b3Sopenharmony_ci 22953a5a1b3Sopenharmony_ci return ts; 23053a5a1b3Sopenharmony_ci} 23153a5a1b3Sopenharmony_ci#endif 23253a5a1b3Sopenharmony_ci 23353a5a1b3Sopenharmony_cistatic struct timeval* wallclock_from_rtclock(struct timeval *tv) { 23453a5a1b3Sopenharmony_ci struct timeval wc_now, rt_now; 23553a5a1b3Sopenharmony_ci 23653a5a1b3Sopenharmony_ci pa_assert(tv); 23753a5a1b3Sopenharmony_ci 23853a5a1b3Sopenharmony_ci pa_gettimeofday(&wc_now); 23953a5a1b3Sopenharmony_ci pa_rtclock_get(&rt_now); 24053a5a1b3Sopenharmony_ci 24153a5a1b3Sopenharmony_ci /* pa_timeval_sub() saturates on underflow! */ 24253a5a1b3Sopenharmony_ci 24353a5a1b3Sopenharmony_ci if (pa_timeval_cmp(&rt_now, tv) < 0) 24453a5a1b3Sopenharmony_ci pa_timeval_add(&wc_now, pa_timeval_diff(tv, &rt_now)); 24553a5a1b3Sopenharmony_ci else 24653a5a1b3Sopenharmony_ci pa_timeval_sub(&wc_now, pa_timeval_diff(&rt_now, tv)); 24753a5a1b3Sopenharmony_ci 24853a5a1b3Sopenharmony_ci *tv = wc_now; 24953a5a1b3Sopenharmony_ci 25053a5a1b3Sopenharmony_ci return tv; 25153a5a1b3Sopenharmony_ci} 25253a5a1b3Sopenharmony_ci 25353a5a1b3Sopenharmony_cistruct timeval* pa_timeval_rtstore(struct timeval *tv, pa_usec_t v, bool rtclock) { 25453a5a1b3Sopenharmony_ci pa_assert(tv); 25553a5a1b3Sopenharmony_ci 25653a5a1b3Sopenharmony_ci if (v == PA_USEC_INVALID) 25753a5a1b3Sopenharmony_ci return NULL; 25853a5a1b3Sopenharmony_ci 25953a5a1b3Sopenharmony_ci pa_timeval_store(tv, v); 26053a5a1b3Sopenharmony_ci 26153a5a1b3Sopenharmony_ci if (rtclock) 26253a5a1b3Sopenharmony_ci tv->tv_usec |= PA_TIMEVAL_RTCLOCK; 26353a5a1b3Sopenharmony_ci else 26453a5a1b3Sopenharmony_ci wallclock_from_rtclock(tv); 26553a5a1b3Sopenharmony_ci 26653a5a1b3Sopenharmony_ci return tv; 26753a5a1b3Sopenharmony_ci} 268