aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/test/util_tests.cpp58
-rw-r--r--src/util.h56
2 files changed, 114 insertions, 0 deletions
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 1b0ccad511..2d05794cc7 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -323,4 +323,62 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
}
}
+static int nCounter = 0;
+
+static void Count()
+{
+ ++nCounter;
+ MilliSleep(10);
+}
+
+static void CountWithArg(int arg)
+{
+ nCounter += arg;
+ MilliSleep(10);
+}
+
+BOOST_AUTO_TEST_CASE(util_loop_forever1)
+{
+ boost::thread_group threadGroup;
+
+ threadGroup.create_thread(boost::bind(&LoopForever<void (*)()>, "count", &Count, 1));
+ MilliSleep(1);
+ threadGroup.interrupt_all();
+ BOOST_CHECK_EQUAL(nCounter, 1);
+ nCounter = 0;
+}
+
+BOOST_AUTO_TEST_CASE(util_loop_forever2)
+{
+ boost::thread_group threadGroup;
+
+ boost::function<void()> f = boost::bind(&CountWithArg, 11);
+ threadGroup.create_thread(boost::bind(&LoopForever<boost::function<void()> >, "count11", f, 11));
+ MilliSleep(1);
+ threadGroup.interrupt_all();
+ BOOST_CHECK_EQUAL(nCounter, 11);
+ nCounter = 0;
+}
+
+BOOST_AUTO_TEST_CASE(util_threadtrace1)
+{
+ boost::thread_group threadGroup;
+
+ threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "count11", &Count));
+ threadGroup.join_all();
+ BOOST_CHECK_EQUAL(nCounter, 1);
+ nCounter = 0;
+}
+
+BOOST_AUTO_TEST_CASE(util_threadtrace2)
+{
+ boost::thread_group threadGroup;
+
+ boost::function<void()> f = boost::bind(&CountWithArg, 11);
+ threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "count11", f));
+ threadGroup.join_all();
+ BOOST_CHECK_EQUAL(nCounter, 11);
+ nCounter = 0;
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/util.h b/src/util.h
index 5173686eda..0c5ed91634 100644
--- a/src/util.h
+++ b/src/util.h
@@ -527,4 +527,60 @@ inline uint32_t ByteReverse(uint32_t value)
return (value<<16) | (value>>16);
}
+// Standard wrapper for do-something-forever thread functions.
+// "Forever" really means until the thread is interrupted.
+// Use it like:
+// new boost::thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 10000));
+// or maybe:
+// boost::function<void()> f = boost::bind(&FunctionWithArg, argument);
+// threadGroup.create_thread(boost::bind(&LoopForever<boost::function<void()> >, "nothing", f, milliseconds));
+template <typename Callable> void LoopForever(const char* name, Callable func, int64 msecs)
+{
+ std::string s = strprintf("bitcoin-%s", name);
+ RenameThread(s.c_str());
+ printf("%s thread start\n", name);
+ try
+ {
+ while (1)
+ {
+ func();
+ MilliSleep(msecs);
+ }
+ }
+ catch (boost::thread_interrupted)
+ {
+ printf("%s thread stop\n", name);
+ throw;
+ }
+ catch (std::exception& e) {
+ PrintException(&e, name);
+ }
+ catch (...) {
+ PrintException(NULL, name);
+ }
+}
+// .. and a wrapper that just calls func once
+template <typename Callable> void TraceThread(const char* name, Callable func)
+{
+ std::string s = strprintf("bitcoin-%s", name);
+ RenameThread(s.c_str());
+ try
+ {
+ printf("%s thread start\n", name);
+ func();
+ printf("%s thread exit\n", name);
+ }
+ catch (boost::thread_interrupted)
+ {
+ printf("%s thread interrupt\n", name);
+ throw;
+ }
+ catch (std::exception& e) {
+ PrintException(&e, name);
+ }
+ catch (...) {
+ PrintException(NULL, name);
+ }
+}
+
#endif