wsd: sig: forward USR2 to child processes
We now have USR2 signal that dumps the stack-trace of each process. This is useful for capturing the state of misbehaving instances. COOLWSD forwards USR2 to forkit and the kits so they dump their stacktraces too. This patch does not change the behavior of USR1. Specifically, unlike USR2, USR1 is not forwarded from wsd to frk and the kits. Also unlike USR2, USR1 dumps into stderr. Change-Id: I1d82f678f30f430f627692cc42961b1928f69e11 Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
This commit is contained in:
parent
3109b99d49
commit
b0d6e1b859
4 changed files with 69 additions and 5 deletions
|
@ -23,6 +23,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "Log.hpp"
|
||||
#include <SigUtil.hpp>
|
||||
|
||||
namespace JailUtil
|
||||
{
|
||||
|
@ -122,7 +123,7 @@ static bool safeRemoveDir(const std::string& path)
|
|||
|
||||
void removeJail(const std::string& root)
|
||||
{
|
||||
LOG_INF("Removing jail [" << root << "].");
|
||||
LOG_INF("Removing jail [" << root << ']');
|
||||
|
||||
// Unmount the tmp directory. Don't care if we fail.
|
||||
const std::string tmpPath = Poco::Path(root, "tmp").toString();
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#ifndef IOS
|
||||
static std::atomic<bool> TerminationFlag(false);
|
||||
static std::atomic<bool> DumpGlobalState(false);
|
||||
static std::atomic<bool> ForwardSigUsr2Flag(false); //< Flags to forward SIG_USR2 to children.
|
||||
static std::atomic<bool> ShutdownRequestFlag(false);
|
||||
#endif
|
||||
|
||||
|
@ -93,10 +94,23 @@ namespace SigUtil
|
|||
void checkDumpGlobalState(GlobalDumpStateFn dumpState)
|
||||
{
|
||||
#if !MOBILEAPP
|
||||
assert(dumpState && "Invalid callback for checkDumpGlobalState");
|
||||
if (DumpGlobalState)
|
||||
{
|
||||
dumpState();
|
||||
DumpGlobalState = false;
|
||||
dumpState();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void checkForwardSigUsr2(ForwardSigUsr2Fn forwardSigUsr2)
|
||||
{
|
||||
#if !MOBILEAPP
|
||||
assert(forwardSigUsr2 && "Invalid callback for checkForwardSigUsr2");
|
||||
if (ForwardSigUsr2Flag)
|
||||
{
|
||||
ForwardSigUsr2Flag = false;
|
||||
forwardSigUsr2();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -478,7 +492,6 @@ namespace SigUtil
|
|||
if (signal == SIGUSR1)
|
||||
{
|
||||
DumpGlobalState = true;
|
||||
SocketPoll::wakeupWorld();
|
||||
}
|
||||
else if (signal == SIGUSR2)
|
||||
{
|
||||
|
@ -487,9 +500,12 @@ namespace SigUtil
|
|||
const int numSlots = backtrace(backtraceBuffer, maxSlots);
|
||||
if (numSlots > 0)
|
||||
backtrace_symbols_fd(backtraceBuffer, numSlots, SignalLogFD);
|
||||
|
||||
ForwardSigUsr2Flag = true;
|
||||
}
|
||||
|
||||
signalLogClose();
|
||||
SocketPoll::wakeupWorld();
|
||||
}
|
||||
|
||||
static
|
||||
|
|
|
@ -49,6 +49,10 @@ namespace SigUtil
|
|||
|
||||
void checkDumpGlobalState(GlobalDumpStateFn dumpState);
|
||||
|
||||
extern "C" { typedef void (*ForwardSigUsr2Fn)(void); }
|
||||
|
||||
void checkForwardSigUsr2(ForwardSigUsr2Fn forwardSigUsr2);
|
||||
|
||||
/// Add a message to a round-robin buffer to be dumped on fatal signal
|
||||
void addActivity(const std::string &message);
|
||||
|
||||
|
|
|
@ -213,7 +213,11 @@ static std::map<std::string, std::shared_ptr<DocumentBroker> > DocBrokers;
|
|||
static std::mutex DocBrokersMutex;
|
||||
static Poco::AutoPtr<Poco::Util::XMLConfiguration> KitXmlConfig;
|
||||
|
||||
extern "C" { void dump_state(void); /* easy for gdb */ }
|
||||
extern "C"
|
||||
{
|
||||
void dump_state(void); /* easy for gdb */
|
||||
void forwardSigUsr2();
|
||||
}
|
||||
|
||||
#if ENABLE_DEBUG
|
||||
static std::chrono::milliseconds careerSpanMs(std::chrono::milliseconds::zero());
|
||||
|
@ -367,7 +371,6 @@ void COOLWSD::checkDiskSpaceAndWarnClients(const bool cacheLastCheck)
|
|||
|
||||
/// Remove dead and idle DocBrokers.
|
||||
/// The client of idle document should've greyed-out long ago.
|
||||
/// Returns true if at least one is removed.
|
||||
void cleanupDocBrokers()
|
||||
{
|
||||
Util::assertIsLocked(DocBrokersMutex);
|
||||
|
@ -2838,7 +2841,10 @@ void PrisonPoll::wakeupHook()
|
|||
#endif
|
||||
std::unique_lock<std::mutex> docBrokersLock(DocBrokersMutex, std::defer_lock);
|
||||
if (docBrokersLock.try_lock())
|
||||
{
|
||||
cleanupDocBrokers();
|
||||
SigUtil::checkForwardSigUsr2(forwardSigUsr2);
|
||||
}
|
||||
}
|
||||
|
||||
#if !MOBILEAPP
|
||||
|
@ -5487,6 +5493,43 @@ void dump_state()
|
|||
LOG_TRC(msg);
|
||||
}
|
||||
|
||||
void forwardSigUsr2()
|
||||
{
|
||||
LOG_TRC("forwardSigUsr2");
|
||||
|
||||
Util::assertIsLocked(DocBrokersMutex);
|
||||
std::lock_guard<std::mutex> newChildLock(NewChildrenMutex);
|
||||
|
||||
#if !MOBILEAPP
|
||||
#ifndef KIT_IN_PROCESS
|
||||
if (COOLWSD::ForKitProcId > 0)
|
||||
{
|
||||
LOG_INF("Sending SIGUSR2 to forkit " << COOLWSD::ForKitProcId);
|
||||
::kill(COOLWSD::ForKitProcId, SIGUSR2);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for (const auto& child : NewChildren)
|
||||
{
|
||||
if (child && child->getPid() > 0)
|
||||
{
|
||||
LOG_INF("Sending SIGUSR2 to child " << child->getPid());
|
||||
::kill(child->getPid(), SIGUSR2);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& pair : DocBrokers)
|
||||
{
|
||||
std::shared_ptr<DocumentBroker> docBroker = pair.second;
|
||||
if (docBroker)
|
||||
{
|
||||
LOG_INF("Sending SIGUSR2 to docBroker " << docBroker->getPid());
|
||||
::kill(docBroker->getPid(), SIGUSR2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid this in the Util::isFuzzing() case because libfuzzer defines its own main().
|
||||
#if !MOBILEAPP && !LIBFUZZER
|
||||
|
||||
|
|
Loading…
Reference in a new issue