summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--compat/timer-resolution.cpp55
-rw-r--r--compat/timer-resolution.hpp45
2 files changed, 76 insertions, 24 deletions
diff --git a/compat/timer-resolution.cpp b/compat/timer-resolution.cpp
index 597ee91e..d59c250d 100644
--- a/compat/timer-resolution.cpp
+++ b/compat/timer-resolution.cpp
@@ -8,12 +8,11 @@
#include "timer-resolution.hpp"
#if defined _WIN32
-# include <windows.h>
-
# include <QLibrary>
# include <QDebug>
-typedef LONG (__stdcall *funptr_NtSetTimerResolution) (ULONG, BOOLEAN, PULONG);
+using namespace timer_impl;
+
static funptr_NtSetTimerResolution init_timer_resolution_funptr();
static funptr_NtSetTimerResolution get_funptr();
@@ -41,62 +40,72 @@ static funptr_NtSetTimerResolution init_timer_resolution_funptr()
static funptr_NtSetTimerResolution get_funptr()
{
+ // starting with C++11 static initializers are fully
+ // thread-safe and run the first time function is called
+
+ // cf. http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11
+
static auto ret = init_timer_resolution_funptr();
return ret;
}
-timer_resolution::timer_resolution(int msecs) : old_value(-1)
+timer_resolution::timer_resolution(int msecs) : old_value(fail_())
{
- if (msecs <= 0 || msecs > 30)
+ if (msecs <= 0 || msecs > 100)
{
qDebug() << "can't set timer resolution to" << msecs << "ms";
return;
}
- funptr_NtSetTimerResolution f = get_funptr();
- if (f == nullptr)
+ funptr_NtSetTimerResolution set_timer_res = get_funptr();
+ if (set_timer_res == nullptr)
return;
// hundredth of a nanosecond
- const ULONG value = msecs * ULONG(10000);
- NTSTATUS error = f(value, TRUE, &old_value);
- ULONG old_value_ = -1;
+ const ulong_ value = msecs * ulong_(10000);
+ ntstatus_ res;
- if (error != 0)
+ res = set_timer_res(value, true_(), &old_value);
+
+ if (res < 0)
{
- old_value = -1;
- qDebug() << "NtSetTimerResolution erred with" << error;
+ old_value = fail_();
+ qDebug() << "NtSetTimerResolution erred with" << res;
return;
}
// see if it stuck
- error = f(value, TRUE, &old_value_);
- if (error != 0)
+ ulong_ old_value_ = fail_();
+
+ res = set_timer_res(value, true_(), &old_value_);
+ if (res < 0)
{
- old_value = -1;
- qDebug() << "NtSetTimerResolution check erred with" << error;
+ old_value = fail_();
+ qDebug() << "NtSetTimerResolution check erred with" << res;
return;
}
if (old_value_ != old_value)
{
+ using t = long long;
+
qDebug() << "NtSetTimerResolution:"
<< "old value didn't stick"
- << "current resolution" << old_value_
- << "* 100 ns";
- old_value = -1;
+ << "current resolution" << (t(old_value_) * t(100))
+ << "ns";
+ old_value = fail_();
return;
}
}
timer_resolution::~timer_resolution()
{
- if (old_value != ULONG(-1))
+ if (old_value != fail_())
{
funptr_NtSetTimerResolution f = get_funptr();
- ULONG fuzz = -1;
- (void) f(old_value, TRUE, &fuzz);
+ ulong_ fuzz = fail_();
+ (void) f(old_value, true_(), &fuzz);
}
}
diff --git a/compat/timer-resolution.hpp b/compat/timer-resolution.hpp
index 5db877c0..8c18a600 100644
--- a/compat/timer-resolution.hpp
+++ b/compat/timer-resolution.hpp
@@ -3,14 +3,57 @@
#if defined _WIN32
# include "export.hpp"
+#include <type_traits>
+
+namespace timer_impl
+{
+
+// cf. https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
+// for NTSTATUS, see http://stackoverflow.com/questions/3378622/how-to-understand-the-ntstatus-nt-success-typedef-in-windows-ddk
+
+using ulong_ = unsigned long;
+using long_ = long;
+using byte_ = unsigned char;
+using boolean_ = byte_;
+
+using true_ = std::integral_constant<int, 1>;
+
+using fail_ = std::integral_constant<byte_, byte_(-1)>;
+
+// cf. http://stackoverflow.com/questions/3378622/how-to-understand-the-ntstatus-nt-success-typedef-in-windows-ddk
+
+// typedef __success(return >= 0) LONG NTSTATUS;
+
+// __success(expr) T f() : indicates whether function f succeeded or
+// not. If is true at exit, all the function's guarantees (as given
+// by other annotations) must hold. If is false at exit, the caller
+// should not expect any of the function's guarantees to hold. If not used,
+// the function must always satisfy its guarantees. Added automatically to
+// functions that indicate success in standard ways, such as by returning an
+// HRESULT.
+
+using ntstatus_ = long_;
+
+// finally what we want
+// this is equivalent to typedef syntax
+
+using funptr_NtSetTimerResolution = ntstatus_ (__stdcall *)(ulong_, boolean_, ulong_*);
+
+// RAII wrapper
+
class OTR_COMPAT_EXPORT timer_resolution final
{
- unsigned long old_value;
+ ulong_ old_value;
public:
timer_resolution(int msecs);
~timer_resolution();
};
+
+}
+
+using timer_impl::timer_resolution;
+
#else
struct timer_resolution final
{