mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-25 13:35:54 +00:00
Log uncaught exceptions at the top of threads (RIPD-1166)
This commit is contained in:
committed by
Nik Bougalis
parent
7295d7f4bb
commit
fdd1f2ec36
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void run ();
|
void run ();
|
||||||
|
void runImpl ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Application& app_;
|
Application& app_;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
153
src/ripple/core/ReportUncaughtException.h
Normal file
153
src/ripple/core/ReportUncaughtException.h
Normal 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
|
||||||
@@ -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 ())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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&)>();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 ())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
169
src/ripple/core/tests/ReportUncaughtException.test.cpp
Normal file
169
src/ripple/core/tests/ReportUncaughtException.test.cpp
Normal 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
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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(;;)
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user