From: Trent Piepho <35062987+xyzzy42@users.noreply.github.com> Date: Wed, 9 Jun 2021 00:52:32 +0000 (-0700) Subject: Have PaUtil_GetTime() use monotonic time on Unix (#559) X-Git-Url: https://andrewgundersen.net/repos?a=commitdiff_plain;h=d859f7d5df98253e9eb16acf201e3551dd01134f;p=portaudio Have PaUtil_GetTime() use monotonic time on Unix (#559) The currently used clock, CLOCK_REALTIME, will have discontinuous jumps, forward and backward, when the system clock is adjusted. This is bad for synchronizing audio. CLOCK_MONOTONIC does not have jumps, and never moves backward, but does have the continuous adjustments done by NTP to increase clock accuracy. Since kernel 2.6.25 ALSA has use CLOCK_MONOTONIC by default for timestamps (commit b751eef1 from Dec 13 2007). This change means the timestamps provided in the PA callbacks can be compared to PaUtil_GetTime(), which currently does not work. The function used on MacOS, mach_absolute_time(), behaves like CLOCK_MONOTONIC. If the system does not have CLOCK_MONOTONIC, fallback to CLOCK_REALTIME, which is what alsa-lib does for such systems. Which at this point would need to be very old. * Use clock monotonic for condition variable This is necessary to match PaUtil_GetTime() also using the monotonic clock. Otherwise the wait time, derived from that function, will be completely incorrect. This will also fix an obscure flaw if the system clock is adjust while waiting for the stream to open, it might not wait at all and fail or wait (effectively) forever instead of timing out, depend on the adjustment direction. --- diff --git a/src/os/unix/pa_unix_util.c b/src/os/unix/pa_unix_util.c index 459b2be..f234c64 100644 --- a/src/os/unix/pa_unix_util.c +++ b/src/os/unix/pa_unix_util.c @@ -160,7 +160,11 @@ PaTime PaUtil_GetTime( void ) return mach_absolute_time() * machSecondsConversionScaler_; #elif defined(HAVE_CLOCK_GETTIME) struct timespec tp; +#if defined(CLOCK_MONOTONIC) + clock_gettime(CLOCK_MONOTONIC, &tp); +#else clock_gettime(CLOCK_REALTIME, &tp); +#endif return (PaTime)(tp.tv_sec + tp.tv_nsec * 1e-9); #else struct timeval tv; @@ -270,11 +274,16 @@ PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void { PaError result = paNoError; pthread_attr_t attr; + pthread_condattr_t cattr; int started = 0; memset( self, 0, sizeof (PaUnixThread) ); PaUnixMutex_Initialize( &self->mtx ); - PA_ASSERT_CALL( pthread_cond_init( &self->cond, NULL ), 0 ); + PA_ASSERT_CALL( pthread_condattr_init( &cattr ), 0 ); +#if defined(CLOCK_MONOTONIC) && !defined(__APPLE__) + PA_ASSERT_CALL( pthread_condattr_setclock( &cattr, CLOCK_MONOTONIC ), 0 ); +#endif + PA_ASSERT_CALL( pthread_cond_init( &self->cond, &cattr), 0 ); self->parentWaiting = 0 != waitForChild;