diff options
author | wm4 <wm4@nowhere> | 2014-05-18 16:36:08 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-05-18 19:20:32 +0200 |
commit | f47a4fc3d900e14653bc059717e2805ad4964a67 (patch) | |
tree | a8ca8944a10c15bbb46239db62a56940a0d3f7b1 /osdep | |
parent | e209e44ca2fef86ec2ec5513bbb63d4d68ff97b5 (diff) | |
download | mpv-f47a4fc3d900e14653bc059717e2805ad4964a67.tar.bz2 mpv-f47a4fc3d900e14653bc059717e2805ad4964a67.tar.xz |
threads: use mpv time for mpthread_cond_timedwait wrapper
Use the time as returned by mp_time_us() for mpthread_cond_timedwait(),
instead of calculating the struct timespec value based on a timeout.
This (probably) makes it easier to wait for a specific deadline.
Diffstat (limited to 'osdep')
-rw-r--r-- | osdep/threads.c | 55 | ||||
-rw-r--r-- | osdep/threads.h | 12 | ||||
-rw-r--r-- | osdep/timer.c | 66 | ||||
-rw-r--r-- | osdep/timer.h | 7 |
4 files changed, 87 insertions, 53 deletions
diff --git a/osdep/threads.c b/osdep/threads.c index 84a65feddd..8cb03045e4 100644 --- a/osdep/threads.c +++ b/osdep/threads.c @@ -15,61 +15,22 @@ * with mpv. If not, see <http://www.gnu.org/licenses/>. */ -#include <time.h> -#include <unistd.h> -#include <sys/time.h> -#include <limits.h> - -#include "common/common.h" #include "threads.h" +#include "timer.h" -static void get_pthread_time(struct timespec *out_ts) -{ -#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 - clock_gettime(CLOCK_REALTIME, out_ts); -#else - // OSX - struct timeval tv; - gettimeofday(&tv, NULL); - out_ts->tv_sec = tv.tv_sec; - out_ts->tv_nsec = tv.tv_usec * 1000UL; -#endif -} - -static void timespec_add_seconds(struct timespec *ts, double seconds) -{ - // clamp to 1 week to avoid tv_sec overflows - seconds = MPMIN(seconds, 60 * 60 * 24 * 7); - unsigned long secs = (int)seconds; - unsigned long nsecs = (seconds - secs) * 1000000000UL; - if (nsecs + ts->tv_nsec >= 1000000000UL) { - secs += 1; - nsecs -= 1000000000UL; - } - ts->tv_sec += secs; - ts->tv_nsec += nsecs; -} - -// Return the argument to pass to e.g. pthread_cond_timedwait(). -// (Note that pthread_cond_t supports multiple clocks; this function computes -// the time value needed by the default clock.) -struct timespec mpthread_get_deadline(double timeout) +int mpthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + int64_t abstime) { - struct timespec ts; - get_pthread_time(&ts); - timespec_add_seconds(&ts, timeout); - return ts; + struct timespec ts = mp_time_us_to_timespec(abstime); + return pthread_cond_timedwait(cond, mutex, &ts); } -// Call pthread_cond_timedwait() with a relative timeout in seconds -int mpthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, - double timeout) +int mpthread_cond_timedwait_rel(pthread_cond_t *cond, pthread_mutex_t *mutex, + double s) { - struct timespec ts = mpthread_get_deadline(timeout); - return pthread_cond_timedwait(cond, mutex, &ts); + return mpthread_cond_timedwait(cond, mutex, mp_add_timeout(mp_time_us(), s)); } -// Helper to reduce boiler plate. int mpthread_mutex_init_recursive(pthread_mutex_t *mutex) { pthread_mutexattr_t attr; diff --git a/osdep/threads.h b/osdep/threads.h index 02f6ac1489..fa9199d63d 100644 --- a/osdep/threads.h +++ b/osdep/threads.h @@ -2,12 +2,18 @@ #define MP_OSDEP_THREADS_H_ #include <pthread.h> +#include <inttypes.h> -struct timespec mpthread_get_deadline(double timeout); - +// Call pthread_cond_timedwait() with an absolute timeout using the same +// time source/unit as mp_time_us() (microseconds). int mpthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, - double timeout); + int64_t abstime); + +// Wait by a relative amount of time in seconds. +int mpthread_cond_timedwait_rel(pthread_cond_t *cond, pthread_mutex_t *mutex, + double seconds); +// Helper to reduce boiler plate. int mpthread_mutex_init_recursive(pthread_mutex_t *mutex); #endif diff --git a/osdep/timer.c b/osdep/timer.c index 4f506b3d46..de37653a67 100644 --- a/osdep/timer.c +++ b/osdep/timer.c @@ -17,9 +17,15 @@ #include <stdlib.h> #include <pthread.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> +#include <limits.h> +#include <assert.h> -#include "timer.h" +#include "common/common.h" #include "common/msg.h" +#include "timer.h" static uint64_t raw_time_offset; pthread_once_t timer_init_once = PTHREAD_ONCE_INIT; @@ -60,21 +66,75 @@ int64_t mp_time_relative_us(int64_t *t) return r; } +int64_t mp_add_timeout(int64_t time_us, double timeout_sec) +{ + assert(time_us > 0); // mp_time_us() returns strictly positive values + double t = timeout_sec * 1000 * 1000; + if (t >= (double)(INT64_MAX - time_us)) + return INT64_MAX; + if (t <= (double)time_us) + return 1; + return time_us + (int64_t)t; +} + +static void get_realtime(struct timespec *out_ts) +{ +#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 + clock_gettime(CLOCK_REALTIME, out_ts); +#else + // OSX + struct timeval tv; + gettimeofday(&tv, NULL); + out_ts->tv_sec = tv.tv_sec; + out_ts->tv_nsec = tv.tv_usec * 1000UL; +#endif +} + +struct timespec mp_time_us_to_timespec(int64_t time_us) +{ + struct timespec ts; + get_realtime(&ts); + // We don't know what time source mp_time_us() uses, but usually it's not + // CLOCK_REALTIME - so we have to remap the times. + int64_t unow = mp_time_us(); + int64_t diff_us = time_us - unow; + long diff_secs = diff_us / (1000L * 1000L); + unsigned long diff_nsecs = (diff_us - diff_secs * (1000L * 1000L)) * 1000UL; + if (diff_nsecs + ts.tv_nsec >= 1000000000UL) { + diff_secs += 1; + diff_nsecs -= 1000000000UL; + } + ts.tv_sec += diff_secs; + ts.tv_nsec += diff_nsecs; + return ts; +} + #if 0 #include <stdio.h> +#include "threads.h" + +#define TEST_SLEEP 1 int main(void) { - int c = 200; + int c = 2000000; int64_t j, r, t = 0; + pthread_mutex_t mtx; + pthread_mutex_init(&mtx, NULL); + pthread_cond_t cnd; + pthread_cond_init(&cnd, NULL); mp_time_init(); for (int i = 0; i < c; i++) { const int delay = rand() / (RAND_MAX / 1e5); r = mp_time_us(); +#if TEST_SLEEP mp_sleep_us(delay); +#else + mpthread_cond_timedwait(&cnd, &mtx, r + delay); +#endif j = (mp_time_us() - r) - delay; - printf("sleep time: sleep=%8i err=%5i\n", delay, (int)j); + printf("sleep time: t=%"PRId64" sleep=%8i err=%5i\n", r, delay, (int)j); t += j; } fprintf(stderr, "average error:\t%i\n", (int)(t / c)); diff --git a/osdep/timer.h b/osdep/timer.h index efb596765a..bc0e5252c9 100644 --- a/osdep/timer.h +++ b/osdep/timer.h @@ -44,4 +44,11 @@ void mp_sleep_us(int64_t us); // first call will return 0, instead of the absolute current time.) int64_t mp_time_relative_us(int64_t *t); +// Add a time in seconds to the given time in microseconds, and return it. +// Takes care of possible overflows. Never returns a negative or 0 time. +int64_t mp_add_timeout(int64_t time_us, double timeout_sec); + +// Convert the mp time in microseconds to a timespec using CLOCK_REALTIME. +struct timespec mp_time_us_to_timespec(int64_t time_us); + #endif /* MPLAYER_TIMER_H */ |