Log uncaught exceptions at the top of threads (RIPD-1166)

This commit is contained in:
Scott Schurr
2016-05-25 19:13:34 -07:00
committed by Nik Bougalis
parent 7295d7f4bb
commit fdd1f2ec36
21 changed files with 452 additions and 21 deletions

View File

@@ -2047,6 +2047,8 @@
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\core\LoadMonitor.h"> <ClInclude Include="..\..\src\ripple\core\LoadMonitor.h">
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\core\ReportUncaughtException.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\core\SociDB.h"> <ClInclude Include="..\..\src\ripple\core\SociDB.h">
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\core\Stoppable.h"> <ClInclude Include="..\..\src\ripple\core\Stoppable.h">
@@ -2069,6 +2071,12 @@
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\ripple\core\tests\ReportUncaughtException.test.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<ClCompile Include="..\..\src\ripple\core\tests\SociDB.test.cpp"> <ClCompile Include="..\..\src\ripple\core\tests\SociDB.test.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>

View File

@@ -2592,6 +2592,9 @@
<ClInclude Include="..\..\src\ripple\core\LoadMonitor.h"> <ClInclude Include="..\..\src\ripple\core\LoadMonitor.h">
<Filter>ripple\core</Filter> <Filter>ripple\core</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\core\ReportUncaughtException.h">
<Filter>ripple\core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\core\SociDB.h"> <ClInclude Include="..\..\src\ripple\core\SociDB.h">
<Filter>ripple\core</Filter> <Filter>ripple\core</Filter>
</ClInclude> </ClInclude>
@@ -2607,6 +2610,9 @@
<ClCompile Include="..\..\src\ripple\core\tests\LoadFeeTrack.test.cpp"> <ClCompile Include="..\..\src\ripple\core\tests\LoadFeeTrack.test.cpp">
<Filter>ripple\core\tests</Filter> <Filter>ripple\core\tests</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\ripple\core\tests\ReportUncaughtException.test.cpp">
<Filter>ripple\core\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\core\tests\SociDB.test.cpp"> <ClCompile Include="..\..\src\ripple\core\tests\SociDB.test.cpp">
<Filter>ripple\core\tests</Filter> <Filter>ripple\core\tests</Filter>
</ClCompile> </ClCompile>

View File

@@ -22,6 +22,7 @@
#include <ripple/app/ledger/InboundLedgers.h> #include <ripple/app/ledger/InboundLedgers.h>
#include <ripple/app/ledger/LedgerMaster.h> #include <ripple/app/ledger/LedgerMaster.h>
#include <ripple/core/LoadFeeTrack.h> #include <ripple/core/LoadFeeTrack.h>
#include <ripple/core/ReportUncaughtException.h>
#include <ripple/protocol/JsonFields.h> #include <ripple/protocol/JsonFields.h>
#include <ripple/beast/core/Thread.h> #include <ripple/beast/core/Thread.h>
@@ -241,6 +242,12 @@ private:
} }
void run () void run ()
{
reportUncaughtException (
this, &LedgerCleanerImp::runImpl, "LedgerCleanerImp::run()");
}
void runImpl ()
{ {
beast::Thread::setCurrentThreadName ("LedgerCleaner"); beast::Thread::setCurrentThreadName ("LedgerCleaner");
JLOG (j_.debug()) << "Started"; JLOG (j_.debug()) << "Started";

View File

@@ -23,6 +23,7 @@
#include <ripple/app/misc/NetworkOPs.h> #include <ripple/app/misc/NetworkOPs.h>
#include <ripple/basics/UptimeTimer.h> #include <ripple/basics/UptimeTimer.h>
#include <ripple/core/LoadFeeTrack.h> #include <ripple/core/LoadFeeTrack.h>
#include <ripple/core/ReportUncaughtException.h>
#include <ripple/json/to_string.h> #include <ripple/json/to_string.h>
#include <ripple/beast/core/Thread.h> #include <ripple/beast/core/Thread.h>
#include <memory> #include <memory>
@@ -106,6 +107,11 @@ void LoadManager::onStop ()
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void LoadManager::run () void LoadManager::run ()
{
reportUncaughtException (this, &LoadManager::runImpl, "LoadManager::run()");
}
void LoadManager::runImpl ()
{ {
beast::Thread::setCurrentThreadName ("LoadManager"); beast::Thread::setCurrentThreadName ("LoadManager");

View File

@@ -97,6 +97,7 @@ public:
private: private:
void run (); void run ();
void runImpl ();
private: private:
Application& app_; Application& app_;

View File

@@ -25,6 +25,7 @@
#include <ripple/app/main/Application.h> #include <ripple/app/main/Application.h>
#include <ripple/basics/contract.h> #include <ripple/basics/contract.h>
#include <ripple/core/ConfigSections.h> #include <ripple/core/ConfigSections.h>
#include <ripple/core/ReportUncaughtException.h>
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
@@ -296,6 +297,13 @@ SHAMapStoreImp::copyNode (std::uint64_t& nodeCount,
void void
SHAMapStoreImp::run() SHAMapStoreImp::run()
{
reportUncaughtException (
this, &SHAMapStoreImp::runImpl, "SHAMapStoreImp::run()");
}
void
SHAMapStoreImp::runImpl()
{ {
LedgerIndex lastRotated = state_db_.getState().lastRotated; LedgerIndex lastRotated = state_db_.getState().lastRotated;
netOPs_ = &app_.getOPs(); netOPs_ = &app_.getOPs();

View File

@@ -175,6 +175,7 @@ private:
// callback for visitNodes // callback for visitNodes
bool copyNode (std::uint64_t& nodeCount, SHAMapAbstractNode const &node); bool copyNode (std::uint64_t& nodeCount, SHAMapAbstractNode const &node);
void run(); void run();
void runImpl();
void dbPaths(); void dbPaths();
std::shared_ptr <NodeStore::Backend> makeBackendRotating ( std::shared_ptr <NodeStore::Backend> makeBackendRotating (
std::string path = std::string()); std::string path = std::string());

View File

@@ -249,8 +249,12 @@ private:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Debug logging: // Debug logging:
/** Set the sink for the debug journal. */ /** Set the sink for the debug journal.
void
@param sink unique_ptr to new debug Sink.
@return unique_ptr to the previous Sink. nullptr if there was no Sink.
*/
std::unique_ptr<beast::Journal::Sink>
setDebugLogSink( setDebugLogSink(
std::unique_ptr<beast::Journal::Sink> sink); std::unique_ptr<beast::Journal::Sink> sink);

View File

@@ -364,17 +364,20 @@ public:
DebugSink(DebugSink&&) = delete; DebugSink(DebugSink&&) = delete;
DebugSink& operator=(DebugSink&&) = delete; DebugSink& operator=(DebugSink&&) = delete;
void std::unique_ptr<beast::Journal::Sink>
set(std::unique_ptr<beast::Journal::Sink> sink) set(std::unique_ptr<beast::Journal::Sink> sink)
{ {
std::lock_guard<std::mutex> _(m_); std::lock_guard<std::mutex> _(m_);
holder_ = std::move(sink); using std::swap;
swap (holder_, sink);
if (holder_) if (holder_)
sink_ = *holder_; sink_ = *holder_;
else else
sink_ = beast::Journal::getNullSink(); sink_ = beast::Journal::getNullSink();
return sink;
} }
beast::Journal::Sink& beast::Journal::Sink&
@@ -393,11 +396,11 @@ debugSink()
return _; return _;
} }
void std::unique_ptr<beast::Journal::Sink>
setDebugLogSink( setDebugLogSink(
std::unique_ptr<beast::Journal::Sink> sink) std::unique_ptr<beast::Journal::Sink> sink)
{ {
debugSink().set(std::move(sink)); return debugSink().set(std::move(sink));
} }
beast::Journal::Stream beast::Journal::Stream

View File

@@ -134,6 +134,9 @@ public:
bool operator<= (const Job& j) const; bool operator<= (const Job& j) const;
bool operator>= (const Job& j) const; bool operator>= (const Job& j) const;
private:
void doJobImpl();
private: private:
CancelCallback m_cancelCallback; CancelCallback m_cancelCallback;
JobType mType; JobType mType;

View File

@@ -0,0 +1,153 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2016, Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_CORE_REPORT_UNCAUGHT_EXCEPTION_H_INCLUDED
#define RIPPLE_CORE_REPORT_UNCAUGHT_EXCEPTION_H_INCLUDED
#include <ripple/basics/Log.h>
#include <boost/coroutine/exceptions.hpp> // forced_unwind exception
#include <exception>
#include <iostream>
#include <sstream>
#include <string>
#include <type_traits>
namespace ripple
{
/**
Report uncaught exceptions to DebugLog and cerr
Catch all exceptions that escape the called function. Report as much
information as can be extracted from the exception to both the DebugLog
and cerr.
The idea is to use this routine at the top of a thread, since on
many platforms the stack trace for an uncaught exception on a thread
is almost useless.
For those platforms where the stack trace from an uncaught exception is
useful (e.g., OS X) this routine is a no-op. That way a catch will not
interfere with the stack trace showing the real source of the uncaught
exception.
Note that any extra information is passed using a lambda because we only
want to do the work of building the string in the unlikely event of an
uncaught exception. The lambda is only called in the error case.
Usage example
#include <ripple/core/ReportUncaughtException.h>
#include <chrono>
#include <exception>
#include <thread>
class ThreadedHandler
{
public:
void operator() ()
{
reportUncaughtException (
this, &ThreadedHandler::runImpl, "ThreadedHandler::operator()");
}
void runImpl()
{
// do stuff.
throw std::logic_error("logic_error: What was I thinking?");
}
};
int main ()
{
using namespace std::chrono_literals;
ThreadedHandler handler;
std::thread t {handler};
std::this_thread::sleep_for (1s);
t.join();
return 0;
}
@param t Pointer to object to call.
@param threadTop Pointer to member function of t to call.
@param name Name of function to log.
@param lamdba Optional lambda that returns additional text for the log.
*/
template <typename T, typename R, typename L>
void reportUncaughtException (
T* t, R (T::*threadTop) (), char const* name, L&& lambda)
{
// Enforce that lambda takes no parameters and returns std::string.
static_assert (
std::is_convertible<decltype (lambda()), std::string const>::value,
"Last argument must be a lamdba taking no arguments "
"and returning std::string.");
#ifdef __APPLE__
// Don't use a try block so we can get a good call stack.
((t)->*(threadTop)) ();
#else
// Local lambda for string formatting and re-throwing.
auto logUncaughtException =
[name, &lambda] (char const* exName)
{
std::stringstream ss;
ss << "Unhandled exception in " << name
<< "; Exception: " << exName;
std::string extra = lambda();
if (! extra.empty())
ss << "; " << extra;
JLOG(debugLog()) << ss.str();
std::cerr << ss.str() << std::endl;
throw;
};
try
{
// Call passed in member function.
((t)->*(threadTop)) ();
}
catch (std::exception const& ex)
{
logUncaughtException (ex.what());
}
catch (boost::coroutines::detail::forced_unwind const& ex)
{
logUncaughtException ("forced_unwind");
}
catch (...)
{
logUncaughtException ("unknown exception type");
}
#endif // __APPLE__ else
}
// Handle the common case where there is no additional local information.
template <typename T, typename R>
inline void reportUncaughtException (
T* t, R (T::*threadTop) (), char const* name)
{
reportUncaughtException (t, threadTop, name, []{ return std::string(); });
}
} // namespace ripple
#endif

View File

@@ -19,6 +19,7 @@
#include <BeastConfig.h> #include <BeastConfig.h>
#include <ripple/core/DeadlineTimer.h> #include <ripple/core/DeadlineTimer.h>
#include <ripple/core/ReportUncaughtException.h>
#include <ripple/beast/core/Thread.h> #include <ripple/beast/core/Thread.h>
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
@@ -97,7 +98,13 @@ public:
} }
} }
void run () void run () override
{
reportUncaughtException (
this, &Manager::runImpl, "DeadlineTimer::Manager::run()");
}
void runImpl ()
{ {
while (! threadShouldExit ()) while (! threadShouldExit ())
{ {

View File

@@ -19,6 +19,7 @@
#include <BeastConfig.h> #include <BeastConfig.h>
#include <ripple/core/Job.h> #include <ripple/core/Job.h>
#include <ripple/core/ReportUncaughtException.h>
#include <cassert> #include <cassert>
namespace ripple { namespace ripple {
@@ -76,14 +77,15 @@ bool Job::shouldCancel () const
void Job::doJob () void Job::doJob ()
{ {
m_loadEvent->start (); reportUncaughtException (this, &Job::doJobImpl, "Job::doJob()",
m_loadEvent->reName (mName); [this] ()
{
mJob (*this); std::stringstream ss;
ss << "Job name: " << this->mName
// Destroy the lambda, otherwise we won't include << "; Job type: " << this->mType
// its duration in the time measurement << "; Job info: " << this->mJob.target_type().name();
mJob = std::function<void(Job&)>(); return ss.str();
});
} }
void Job::rename (std::string const& newName) void Job::rename (std::string const& newName)
@@ -135,4 +137,16 @@ bool Job::operator<= (const Job& j) const
return mJobIndex <= j.mJobIndex; return mJobIndex <= j.mJobIndex;
} }
void Job::doJobImpl ()
{
m_loadEvent->start ();
m_loadEvent->reName (mName);
mJob (*this);
// Destroy the lambda, otherwise we won't include
// its duration in the time measurement
mJob = std::function<void(Job&)>();
}
} }

View File

@@ -18,12 +18,13 @@
//============================================================================== //==============================================================================
#include <BeastConfig.h> #include <BeastConfig.h>
#include <ripple/core/impl/SNTPClock.h>
#include <ripple/basics/Log.h> #include <ripple/basics/Log.h>
#include <ripple/basics/ThreadName.h> #include <ripple/basics/ThreadName.h>
#include <ripple/basics/random.h> #include <ripple/basics/random.h>
#include <ripple/core/impl/SNTPClock.h>
#include <beast/core/placeholders.hpp>
#include <ripple/beast/core/Thread.h> #include <ripple/beast/core/Thread.h>
#include <ripple/core/ReportUncaughtException.h>
#include <beast/core/placeholders.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <cmath> #include <cmath>
@@ -203,7 +204,12 @@ public:
void doRun () void doRun ()
{ {
setCallingThreadName("SNTPClock"); setCallingThreadName("SNTPClock");
io_service_.run();
// Get the address of an overloaded asio method
using Pio_service_mem = std::size_t (boost::asio::io_service::*)();
Pio_service_mem pRun = &boost::asio::io_service::run;
reportUncaughtException (&io_service_, pRun, "SNTPClientImp::doRun()");
} }
void void

View File

@@ -18,6 +18,7 @@
//============================================================================== //==============================================================================
#include <ripple/core/impl/Workers.h> #include <ripple/core/impl/Workers.h>
#include <ripple/core/ReportUncaughtException.h>
#include <ripple/beast/unit_test.h> #include <ripple/beast/unit_test.h>
#include <cassert> #include <cassert>
@@ -156,6 +157,16 @@ Workers::Worker::~Worker ()
} }
void Workers::Worker::run () void Workers::Worker::run ()
{
// Call runImpl() and report if any exceptions escape runImpl.
reportUncaughtException (this, &Workers::Worker::runImpl,
"Workers::Worker::run()", [this] ()
{
return "Thread: " + Thread::getThreadName();
});
}
void Workers::Worker::runImpl ()
{ {
while (! threadShouldExit ()) while (! threadShouldExit ())
{ {

View File

@@ -114,7 +114,7 @@ private:
Active: Running the task processing loop. Active: Running the task processing loop.
Idle: Active, but blocked on waiting for a task. Idle: Active, but blocked on waiting for a task.
Pausd: Blocked waiting to exit or become active. Paused: Blocked waiting to exit or become active.
*/ */
class Worker class Worker
: public beast::LockFreeStack <Worker>::Node : public beast::LockFreeStack <Worker>::Node
@@ -127,7 +127,8 @@ private:
~Worker (); ~Worker ();
private: private:
void run (); void run () override;
void runImpl ();
private: private:
Workers& m_workers; Workers& m_workers;

View File

@@ -0,0 +1,169 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2016 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <BeastConfig.h>
#include <ripple/basics/Log.h>
#include <ripple/basics/TestSuite.h>
#include <ripple/core/ReportUncaughtException.h>
namespace ripple {
// reportUncaughtException is disabled if __APPLE__ is defined.
#ifndef __APPLE__
class ReportUncaughtException_test : public TestSuite
{
public:
class TestSink : public beast::Journal::Sink
{
std::stringstream ss_;
public:
TestSink()
: Sink (beast::severities::kFatal, false)
{
}
std::string getText() const
{
return ss_.str();
}
void reset()
{
ss_.str("");
}
void
write (beast::severities::Severity level, std::string const& s) override
{
if (level >= threshold())
ss_ << s;
}
};
class ExceptionGen
{
public:
// A place to keep methods that throw.
void dontThrow()
{
return;
}
void throwStdExcept()
{
throw std::logic_error ("logic_error");
}
void throwForcedUnwind()
{
throw boost::coroutines::detail::forced_unwind ();
}
void throwWeird()
{
throw std::string ("Pretty unusual...");
}
};
void test ()
{
// Install our own debug Sink so we can see what gets written.
// Retain the old Sink so we can put it back.
auto testSink = std::make_unique<TestSink>();
TestSink& sinkRef = *testSink;
std::unique_ptr<beast::Journal::Sink> oldSink =
setDebugLogSink (std::move (testSink));
ExceptionGen exGen;
// Make sure nothing gets logged if there's no exception.
reportUncaughtException (&exGen, &ExceptionGen::dontThrow, "noThrow");
expect (sinkRef.getText() == "");
sinkRef.reset();
reportUncaughtException (&exGen, &ExceptionGen::dontThrow, "noThrow",
[] { return "Just noise"; });
expect (sinkRef.getText() == "");
sinkRef.reset();
using PExGenMemFn = void (ExceptionGen::*) ();
auto testCase = [this, &exGen, &sinkRef] (
PExGenMemFn call, char const* description)
{
std::string want = std::string ("Unhandled exception in "
"testFn; Exception: ") + description;
// Test the case without the closing lambda.
bool gotException = false;
try
{
reportUncaughtException (&exGen, call, "testFn");
}
catch (...)
{
gotException = true;
}
expect (gotException == true);
expect (sinkRef.getText() == want);
sinkRef.reset();
// Try the case with the closing lambda.
gotException = false;
try
{
reportUncaughtException (&exGen, call, "testFn",
[]{ return "extra info"; });
}
catch (...)
{
gotException = true;
}
expect (gotException == true);
expect (sinkRef.getText() == want + "; extra info");
sinkRef.reset();
};
// Test logging for a stad::exception.
testCase (&ExceptionGen::throwStdExcept, "logic_error");
// Test logging for a forced_unwind.
testCase (&ExceptionGen::throwForcedUnwind, "forced_unwind");
// Test logging for none of the above.
testCase (&ExceptionGen::throwWeird, "unknown exception type");
// We're done with TestSink. Re-install the old Sink.
setDebugLogSink (std::move (oldSink));
}
void run ()
{
test ();
}
};
BEAST_DEFINE_TESTSUITE (ReportUncaughtException, core, ripple);
#endif // __APPLE__
} // ripple

View File

@@ -26,6 +26,7 @@
#include <ripple/basics/KeyCache.h> #include <ripple/basics/KeyCache.h>
#include <ripple/basics/Log.h> #include <ripple/basics/Log.h>
#include <ripple/basics/chrono.h> #include <ripple/basics/chrono.h>
#include <ripple/core/ReportUncaughtException.h>
#include <ripple/protocol/digest.h> #include <ripple/protocol/digest.h>
#include <ripple/basics/Slice.h> #include <ripple/basics/Slice.h>
#include <ripple/basics/TaggedCache.h> #include <ripple/basics/TaggedCache.h>
@@ -333,8 +334,15 @@ public:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Entry point for async read threads // Uncaught exception handling for async read threads
void threadEntry () void threadEntry ()
{
reportUncaughtException (
this, &DatabaseImp::threadEntryImpl, "DatabaseImp::threadEntry()");
}
// Entry point for async read threads
void threadEntryImpl ()
{ {
beast::Thread::setCurrentThreadName ("prefetch"); beast::Thread::setCurrentThreadName ("prefetch");
while (1) while (1)

View File

@@ -22,6 +22,7 @@
#include <ripple/resource/impl/Logic.h> #include <ripple/resource/impl/Logic.h>
#include <ripple/basics/chrono.h> #include <ripple/basics/chrono.h>
#include <ripple/basics/Log.h> #include <ripple/basics/Log.h>
#include <ripple/core/ReportUncaughtException.h>
#include <ripple/beast/core/Thread.h> #include <ripple/beast/core/Thread.h>
#include <condition_variable> #include <condition_variable>
#include <memory> #include <memory>
@@ -112,6 +113,12 @@ public:
private: private:
void run () void run ()
{
reportUncaughtException (
this, &ManagerImp::runImpl, "Resource::Manager::run()");
}
void runImpl ()
{ {
beast::Thread::setCurrentThreadName ("Resource::Manager"); beast::Thread::setCurrentThreadName ("Resource::Manager");
for(;;) for(;;)

View File

@@ -35,5 +35,6 @@
#include <ripple/core/tests/Config.test.cpp> #include <ripple/core/tests/Config.test.cpp>
#include <ripple/core/tests/Coroutine.test.cpp> #include <ripple/core/tests/Coroutine.test.cpp>
#include <ripple/core/tests/LoadFeeTrack.test.cpp> #include <ripple/core/tests/LoadFeeTrack.test.cpp>
#include <ripple/core/tests/ReportUncaughtException.test.cpp>
#include <ripple/core/tests/Stoppable.test.cpp> #include <ripple/core/tests/Stoppable.test.cpp>

View File

@@ -21,6 +21,7 @@
#define RIPPLE_WEBSOCKET_SERVER_H_INCLUDED #define RIPPLE_WEBSOCKET_SERVER_H_INCLUDED
#include <ripple/basics/Log.h> #include <ripple/basics/Log.h>
#include <ripple/core/ReportUncaughtException.h>
#include <ripple/websocket/WebSocket.h> #include <ripple/websocket/WebSocket.h>
#include <ripple/beast/core/Thread.h> #include <ripple/beast/core/Thread.h>
#include <condition_variable> #include <condition_variable>
@@ -58,6 +59,12 @@ public:
private: private:
void run () void run ()
{
reportUncaughtException (
this, &Server::runImpl, "Server<WebSocket>::run()");
}
void runImpl ()
{ {
beast::Thread::setCurrentThreadName ("WebSocket"); beast::Thread::setCurrentThreadName ("WebSocket");