diff options
Diffstat (limited to 'src/corelib/tools/qelapsedtimer_unix.cpp')
-rw-r--r-- | src/corelib/tools/qelapsedtimer_unix.cpp | 128 |
1 files changed, 82 insertions, 46 deletions
diff --git a/src/corelib/tools/qelapsedtimer_unix.cpp b/src/corelib/tools/qelapsedtimer_unix.cpp index 4bbcbcabbf..5dc18ce99f 100644 --- a/src/corelib/tools/qelapsedtimer_unix.cpp +++ b/src/corelib/tools/qelapsedtimer_unix.cpp @@ -47,6 +47,7 @@ #include <time.h> #include <unistd.h> +#include <qatomic.h> #include "private/qcore_unix_p.h" #if defined(QT_NO_CLOCK_MONOTONIC) || defined(QT_BOOTSTRAPPED) @@ -59,30 +60,87 @@ QT_BEGIN_NAMESPACE -#if (_POSIX_MONOTONIC_CLOCK-0 != 0) -static const bool monotonicClockChecked = true; -static const bool monotonicClockAvailable = _POSIX_MONOTONIC_CLOCK > 0; +/* + * Design: + * + * POSIX offers a facility to select the system's monotonic clock when getting + * the current timestamp. Whereas the functions are mandatory in POSIX.1-2008, + * the presence of a monotonic clock is a POSIX Option (see the document + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01_06 ) + * + * The macro _POSIX_MONOTONIC_CLOCK can therefore assume the following values: + * -1 monotonic clock is never supported on this sytem + * 0 monotonic clock might be supported, runtime check is needed + * >1 (such as 200809L) monotonic clock is always supported + * + * The unixCheckClockType() function will return the clock to use: either + * CLOCK_MONOTONIC or CLOCK_REALTIME. In the case the POSIX option has a value + * of zero, then this function stores a static that contains the clock to be + * used. + * + * There's one extra case, which is when CLOCK_REALTIME isn't defined. When + * that's the case, we'll emulate the clock_gettime function with gettimeofday. + * + * Conforming to: + * POSIX.1b-1993 section "Clocks and Timers" + * included in UNIX98 (Single Unix Specification v2) + * included in POSIX.1-2001 + * see http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html + */ + +#ifndef CLOCK_REALTIME +# define CLOCK_REALTIME 0 +static inline void qt_clock_gettime(int, struct timespec *ts) +{ + // support clock_gettime with gettimeofday + struct timeval tv; + gettimeofday(&tv, 0); + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; +} + +# ifdef _POSIX_MONOTONIC_CLOCK +# undef _POSIX_MONOTONIC_CLOCK +# define _POSIX_MONOTONIC_CLOCK -1 +# endif #else -static int monotonicClockChecked = false; -static int monotonicClockAvailable = false; -#endif - -#define load_acquire(x) ((volatile const int&)(x)) -#define store_release(x,v) ((volatile int&)(x) = (v)) - -static void unixCheckClockType() +static inline void qt_clock_gettime(clockid_t clock, struct timespec *ts) { -#if (_POSIX_MONOTONIC_CLOCK-0 == 0) - if (Q_LIKELY(load_acquire(monotonicClockChecked))) - return; - -# if defined(_SC_MONOTONIC_CLOCK) - // detect if the system support monotonic timers - long x = sysconf(_SC_MONOTONIC_CLOCK); - store_release(monotonicClockAvailable, x >= 200112L); -# endif + clock_gettime(clock, ts); +} +#endif - store_release(monotonicClockChecked, true); +static int unixCheckClockType() +{ +#if (_POSIX_MONOTONIC_CLOCK-0 == 0) && defined(_SC_MONOTONIC_CLOCK) + // we need a value we can store in a clockid_t that isn't a valid clock + // check if the valid ones are both non-negative or both non-positive +# if CLOCK_MONOTONIC >= 0 && CLOCK_REALTIME >= 0 +# define IS_VALID_CLOCK(clock) (clock >= 0) +# define INVALID_CLOCK -1 +# elif CLOCK_MONOTONIC <= 0 && CLOCK_REALTIME <= 0 +# define IS_VALID_CLOCK(clock) (clock <= 0) +# define INVALID_CLOCK 1 +# else +# error "Sorry, your system has weird values for CLOCK_MONOTONIC and CLOCK_REALTIME" +# endif + + static QBasicAtomicInt clockToUse = Q_BASIC_ATOMIC_INITIALIZER(INVALID_CLOCK); + int clock = clockToUse.loadAcquire(); + if (Q_LIKELY(IS_VALID_CLOCK(clock))) + return clock; + + // detect if the system supports monotonic timers + clock = sysconf(_SC_MONOTONIC_CLOCK) > 0 ? CLOCK_MONOTONIC : CLOCK_REALTIME; + clockToUse.storeRelease(clock); + return clock; + +# undef INVALID_CLOCK +# undef IS_VALID_CLOCK +#elif (_POSIX_MONOTONIC_CLOCK-0) > 0 + return CLOCK_MONOTONIC; +#else + return CLOCK_REALTIME; #endif } @@ -93,42 +151,20 @@ static inline qint64 fractionAdjustment() bool QElapsedTimer::isMonotonic() Q_DECL_NOTHROW { - unixCheckClockType(); - return monotonicClockAvailable; + return clockType() == MonotonicClock; } QElapsedTimer::ClockType QElapsedTimer::clockType() Q_DECL_NOTHROW { - unixCheckClockType(); - return monotonicClockAvailable ? MonotonicClock : SystemTime; + return unixCheckClockType() == CLOCK_REALTIME ? SystemTime : MonotonicClock; } static inline void do_gettime(qint64 *sec, qint64 *frac) { -#if (_POSIX_MONOTONIC_CLOCK-0 >= 0) - unixCheckClockType(); - if (Q_LIKELY(monotonicClockAvailable)) { - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - *sec = ts.tv_sec; - *frac = ts.tv_nsec; - return; - } -#endif -#ifdef CLOCK_REALTIME - // even if we don't have a monotonic clock, - // we can use clock_gettime -> nanosecond resolution timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); + qt_clock_gettime(unixCheckClockType(), &ts); *sec = ts.tv_sec; *frac = ts.tv_nsec; -#else - // use gettimeofday - timeval tv; - ::gettimeofday(&tv, 0); - *sec = tv.tv_sec; - *frac = tv.tv_usec * 1000; -#endif } // used in qcore_unix.cpp and qeventdispatcher_unix.cpp |