summaryrefslogtreecommitdiffstats
path: root/src/uscxml/concurrency
diff options
context:
space:
mode:
Diffstat (limited to 'src/uscxml/concurrency')
-rw-r--r--src/uscxml/concurrency/DelayedEventQueue.cpp10
-rw-r--r--src/uscxml/concurrency/DelayedEventQueue.h3
-rw-r--r--src/uscxml/concurrency/Timer.cpp116
-rw-r--r--src/uscxml/concurrency/Timer.h68
4 files changed, 196 insertions, 1 deletions
diff --git a/src/uscxml/concurrency/DelayedEventQueue.cpp b/src/uscxml/concurrency/DelayedEventQueue.cpp
index 642c4a0..ca43c8e 100644
--- a/src/uscxml/concurrency/DelayedEventQueue.cpp
+++ b/src/uscxml/concurrency/DelayedEventQueue.cpp
@@ -99,6 +99,15 @@ void DelayedEventQueue::addEvent(std::string eventId, void (*callback)(void*, co
event_add(event, &delay);
}
+void DelayedEventQueue::cancelAllEvents() {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ while(_callbackData.size() > 0) {
+ event_del(_callbackData[_callbackData.begin()->first].event);
+ event_free(_callbackData[_callbackData.begin()->first].event);
+ _callbackData.erase(_callbackData.begin());
+ }
+}
+
void DelayedEventQueue::cancelEvent(std::string eventId) {
tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
@@ -122,6 +131,7 @@ void DelayedEventQueue::stop() {
if (_thread) {
_thread->join();
delete _thread;
+ _thread = NULL;
}
}
diff --git a/src/uscxml/concurrency/DelayedEventQueue.h b/src/uscxml/concurrency/DelayedEventQueue.h
index 2248c47..d89b715 100644
--- a/src/uscxml/concurrency/DelayedEventQueue.h
+++ b/src/uscxml/concurrency/DelayedEventQueue.h
@@ -57,7 +57,8 @@ public:
void addEvent(std::string eventId, int fd, short opMask, void (*callback)(void*, const std::string eventId), void* userData, bool persist = true);
void addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData, bool persist = false);
- void cancelEvent(std::string eventId);
+ void cancelEvent(std::string eventId);
+ void cancelAllEvents();
void start();
void stop();
diff --git a/src/uscxml/concurrency/Timer.cpp b/src/uscxml/concurrency/Timer.cpp
new file mode 100644
index 0000000..b05a907
--- /dev/null
+++ b/src/uscxml/concurrency/Timer.cpp
@@ -0,0 +1,116 @@
+// Copyright 2013 Alex Reece.
+//
+// A cross platform monotonic timer.
+
+// see https://github.com/awreece/monotonic_timer
+
+#include <unistd.h>
+#include "Timer.h"
+
+#define NANOS_PER_SECF 1000000000.0
+#define USECS_PER_SEC 1000000
+
+#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
+ // If we have it, use clock_gettime and CLOCK_MONOTONIC.
+
+ #include <time.h>
+
+ double uscxml::Timer::monotonic_seconds() {
+ struct timespec time;
+ // Note: Make sure to link with -lrt to define clock_gettime.
+ clock_gettime(CLOCK_MONOTONIC, &time);
+ return ((double) time.tv_sec) + ((double) time.tv_nsec / (NANOS_PER_SECF));
+ }
+
+#elif defined(__APPLE__)
+ // If we don't have CLOCK_MONOTONIC, we might be on a Mac. There we instead
+ // use mach_absolute_time().
+
+ #include <mach/mach_time.h>
+
+ static mach_timebase_info_data_t info;
+ static void __attribute__((constructor)) init_info() {
+ mach_timebase_info(&info);
+ }
+
+ double uscxml::Timer::monotonic_seconds() {
+ uint64_t time = mach_absolute_time();
+ double dtime = (double) time;
+ dtime *= (double) info.numer;
+ dtime /= (double) info.denom;
+ return dtime / NANOS_PER_SECF;
+ }
+
+#elif defined(_MSC_VER)
+ // On Windows, use QueryPerformanceCounter and QueryPerformanceFrequency.
+
+ #include <windows.h>
+
+ static double PCFreq = 0.0;
+
+ // According to http://stackoverflow.com/q/1113409/447288, this will
+ // make this function a constructor.
+ // TODO(awreece) Actually attempt to compile on windows.
+ static void __cdecl init_pcfreq();
+ __declspec(allocate(".CRT$XCU")) void (__cdecl*init_pcfreq_)() = init_pcfreq;
+ static void __cdecl init_pcfreq() {
+ // Accoring to http://stackoverflow.com/a/1739265/447288, this will
+ // properly initialize the QueryPerformanceCounter.
+ LARGE_INTEGER li;
+ int has_qpc = QueryPerformanceFrequency(&li);
+ assert(has_qpc);
+
+ PCFreq = ((double) li.QuadPart) / 1000.0;
+ }
+
+ double uscxml::Timer::monotonic_seconds() {
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ return ((double) li.QuadPart) / PCFreq;
+ }
+
+#else
+ // Fall back to rdtsc. The reason we don't use clock() is this scary message
+ // from the man page:
+ // "On several other implementations, the value returned by clock() also
+ // includes the times of any children whose status has been collected via
+ // wait(2) (or another wait-type call)."
+ //
+ // Also, clock() only has microsecond accuracy.
+ //
+ // This whitepaper offered excellent advice on how to use rdtscp for
+ // profiling: http://download.intel.com/embedded/software/IA/324264.pdf
+ //
+ // Unfortunately, we can't follow its advice exactly with our semantics,
+ // so we're just going to use rdtscp with cpuid.
+ //
+ // Note that rdtscp will only be available on new processors.
+
+ #include <stdint.h>
+
+ static inline uint64_t rdtsc() {
+ uint32_t hi, lo;
+ asm volatile("rdtscp\n"
+ "movl %%edx, %0\n"
+ "movl %%eax, %1\n"
+ "cpuid"
+ : "=r" (hi), "=r" (lo) : : "%rax", "%rbx", "%rcx", "%rdx");
+ return (((uint64_t)hi) << 32) | (uint64_t)lo;
+ }
+
+ static uint64_t rdtsc_per_sec = 0;
+ static void __attribute__((constructor)) init_rdtsc_per_sec() {
+ uint64_t before, after;
+
+ before = rdtsc();
+ usleep(USECS_PER_SEC);
+ after = rdtsc();
+
+ rdtsc_per_sec = after - before;
+ }
+
+ double uscxml::Timer::monotonic_seconds() {
+ return (double) rdtsc() / (double) rdtsc_per_sec;
+ }
+
+#endif
diff --git a/src/uscxml/concurrency/Timer.h b/src/uscxml/concurrency/Timer.h
new file mode 100644
index 0000000..60a20a3
--- /dev/null
+++ b/src/uscxml/concurrency/Timer.h
@@ -0,0 +1,68 @@
+// Copyright 2013 Alex Reece.
+//
+// A cross platform monotonic timer.
+
+// see https://github.com/awreece/monotonic_timer
+
+#ifndef MONOTONIC_TIMER_H_
+#define MONOTONIC_TIMER_H_
+
+// Returns seconds since some unspecified start time (guaranteed to be
+// monotonicly increasing).
+
+// Copyright 2015 Stefan Radomski.
+
+namespace uscxml {
+
+class USCXML_API Timer {
+public:
+
+ static double monotonic_seconds();
+
+ Timer() {
+ invocations = 0;
+ elapsed = 0;
+ }
+
+ void start() {
+ if (invocations == 0) {
+ started = monotonic_seconds();
+ }
+ invocations++;
+ }
+
+ void stop() {
+ if (invocations == 0)
+ return;
+
+ invocations--;
+ if (invocations == 0) {
+ elapsed += monotonic_seconds() - started;
+ }
+ }
+
+ ~Timer() {
+ }
+ double elapsed;
+
+protected:
+ size_t invocations;
+ double started;
+};
+
+class USCXML_API Measurement {
+public:
+ Measurement(Timer* timer) : timer(timer) {
+ timer->start();
+ }
+
+ ~Measurement() {
+ timer->stop();
+ }
+
+protected:
+ Timer* timer;
+};
+
+}
+#endif // MONOTONIC_TIMER_H_