diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 1b0ccad51..2d05794cc 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, "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 f = boost::bind(&CountWithArg, 11); + threadGroup.create_thread(boost::bind(&LoopForever >, "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, "count11", &Count)); + threadGroup.join_all(); + BOOST_CHECK_EQUAL(nCounter, 1); + nCounter = 0; +} + +BOOST_AUTO_TEST_CASE(util_threadtrace2) +{ + boost::thread_group threadGroup; + + boost::function f = boost::bind(&CountWithArg, 11); + threadGroup.create_thread(boost::bind(&TraceThread >, "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 5173686ed..0c5ed9163 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, "dumpaddr", &DumpAddresses, 10000)); +// or maybe: +// boost::function f = boost::bind(&FunctionWithArg, argument); +// threadGroup.create_thread(boost::bind(&LoopForever >, "nothing", f, milliseconds)); +template 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 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