From a869dfea852e0961992b1563b2e14257e7ba3e03 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 14 Aug 2012 19:02:26 +0200 Subject: timer: use monotonic clock if available --- Makefile.am | 9 +++--- NEWS | 2 ++ src/clock.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/clock.h | 41 ++++++++++++++++++++++++++ src/timer.c | 17 +++-------- 5 files changed, 147 insertions(+), 17 deletions(-) create mode 100644 src/clock.c create mode 100644 src/clock.h diff --git a/Makefile.am b/Makefile.am index 332b51d9e..0077eaf59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -227,6 +227,7 @@ src_mpd_SOURCES = \ $(OUTPUT_API_SRC) \ $(MIXER_API_SRC) \ src/glib_socket.h \ + src/clock.c src/clock.h \ src/notify.c \ src/audio_config.c src/audio_config.h \ src/audio_check.c \ @@ -1069,7 +1070,7 @@ test_dump_playlist_SOURCES = test/dump_playlist.c \ src/audio_check.c src/pcm_buffer.c \ src/text_input_stream.c src/fifo_buffer.c \ src/cue/cue_parser.c src/cue/cue_parser.h \ - src/timer.c \ + src/timer.c src/clock.c \ src/fd_util.c if HAVE_FLAC @@ -1096,7 +1097,7 @@ test_run_decoder_SOURCES = test/run_decoder.c \ src/fd_util.c \ src/audio_check.c \ src/audio_format.c \ - src/timer.c \ + src/timer.c src/clock.c \ $(ARCHIVE_SRC) \ $(INPUT_SRC) \ $(TAG_SRC) \ @@ -1118,7 +1119,7 @@ test_read_tags_SOURCES = test/read_tags.c \ src/uri.c \ src/fd_util.c \ src/audio_check.c \ - src/timer.c \ + src/timer.c src/clock.c \ $(DECODER_SRC) if HAVE_ID3TAG @@ -1240,7 +1241,7 @@ test_run_output_SOURCES = test/run_output.c \ src/audio_check.c \ src/audio_format.c \ src/audio_parser.c \ - src/timer.c \ + src/timer.c src/clock.c \ src/tag.c src/tag_pool.c \ src/fifo_buffer.c src/growing_fifo.c \ src/page.c \ diff --git a/NEWS b/NEWS index 812d03908..9b72f6ba0 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ ver 0.17.2 (2012/??/??) * protocol: - fix crash in local file check +* output: + - httpd: use monotonic clock, avoid hiccups after system clock adjustment * mapper: fix non-UTF8 music directory name diff --git a/src/clock.c b/src/clock.c new file mode 100644 index 000000000..4100fa2d8 --- /dev/null +++ b/src/clock.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "clock.h" + +#ifdef WIN32 +#include +#elif defined(__APPLE__) +#include +#else +#include +#endif + +unsigned +monotonic_clock_ms(void) +{ +#ifdef WIN32 + return GetTickCount(); +#elif defined(__APPLE__) /* OS X does not define CLOCK_MONOTONIC */ + static mach_timebase_info_data_t base; + if (base.denom == 0) + (void)mach_timebase_info(&base); + + return (unsigned)((mach_absolute_time() * base.numer) + / (1000000 * base.denom)); +#elif defined(CLOCK_MONOTONIC) + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; +#else + /* we have no monotonic clock, fall back to gettimeofday() */ + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +#endif +} + +uint64_t +monotonic_clock_us(void) +{ +#ifdef WIN32 + LARGE_INTEGER l_value, l_frequency; + + if (!QueryPerformanceCounter(&l_value) || + !QueryPerformanceFrequency(&l_frequency)) + return 0; + + uint64_t value = l_value.QuadPart; + uint64_t frequency = l_frequency.QuadPart; + + if (frequency > 1000000) { + value *= 10000; + value /= frequency / 100; + } else if (frequency < 1000000) { + value *= 10000; + value /= frequency; + value *= 100; + } + + return value; +#elif defined(__APPLE__) /* OS X does not define CLOCK_MONOTONIC */ + static mach_timebase_info_data_t base; + if (base.denom == 0) + (void)mach_timebase_info(&base); + + return ((uint64_t)mach_absolute_time() * (uint64_t)base.numer) + / (1000 * (uint64_t)base.denom); +#elif defined(CLOCK_MONOTONIC) + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000 + (uint64_t)(ts.tv_nsec / 1000); +#else + /* we have no monotonic clock, fall back to gettimeofday() */ + struct timeval tv; + gettimeofday(&tv, 0); + return (uint64_t)tv.tv_sec * 1000 + (uint64_t)(tv.tv_usec) / 1000(; +#endif +} + diff --git a/src/clock.h b/src/clock.h new file mode 100644 index 000000000..4ece35ab1 --- /dev/null +++ b/src/clock.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_CLOCK_H +#define MPD_CLOCK_H + +#include + +#include + +/** + * Returns the value of a monotonic clock in milliseconds. + */ +G_GNUC_PURE +unsigned +monotonic_clock_ms(void); + +/** + * Returns the value of a monotonic clock in microseconds. + */ +G_GNUC_PURE +uint64_t +monotonic_clock_us(void); + +#endif diff --git a/src/timer.c b/src/timer.c index 691ab76be..2d9550706 100644 --- a/src/timer.c +++ b/src/timer.c @@ -20,23 +20,14 @@ #include "config.h" #include "timer.h" #include "audio_format.h" +#include "clock.h" #include #include #include -#include #include -static uint64_t now(void) -{ - struct timeval tv; - - gettimeofday(&tv, NULL); - - return ((uint64_t)tv.tv_sec * 1000000) + tv.tv_usec; -} - struct timer *timer_new(const struct audio_format *af) { struct timer *timer = g_new(struct timer, 1); @@ -54,7 +45,7 @@ void timer_free(struct timer *timer) void timer_start(struct timer *timer) { - timer->time = now(); + timer->time = monotonic_clock_us(); timer->started = 1; } @@ -74,7 +65,7 @@ void timer_add(struct timer *timer, int size) unsigned timer_delay(const struct timer *timer) { - int64_t delay = (int64_t)(timer->time - now()) / 1000; + int64_t delay = (int64_t)(timer->time - monotonic_clock_us()) / 1000; if (delay < 0) return 0; @@ -90,7 +81,7 @@ void timer_sync(struct timer *timer) assert(timer->started); - sleep_duration = timer->time - now(); + sleep_duration = timer->time - monotonic_clock_us(); if (sleep_duration > 0) g_usleep(sleep_duration); } -- cgit v1.2.3