[Libreoffice-commits] online.git: loolwsd/Admin.cpp loolwsd/common loolwsd/DocumentBroker.hpp loolwsd/LOOLForKit.cpp loolwsd/LOOLKit.cpp loolwsd/LOOLSession.cpp loolwsd/LOOLWSD.cpp loolwsd/Makefile.am loolwsd/test loolwsd/Unit.cpp loolwsd/Util.cpp loolwsd/Util.hpp
Ashod Nakashian
ashod.nakashian at collabora.co.uk
Mon Nov 14 21:20:43 UTC 2016
loolwsd/Admin.cpp | 4
loolwsd/DocumentBroker.hpp | 4
loolwsd/LOOLForKit.cpp | 12 +
loolwsd/LOOLKit.cpp | 8 -
loolwsd/LOOLSession.cpp | 4
loolwsd/LOOLWSD.cpp | 14 +-
loolwsd/Makefile.am | 2
loolwsd/Unit.cpp | 2
loolwsd/Util.cpp | 232 ------------------------------------
loolwsd/Util.hpp | 26 ----
loolwsd/common/SigUtil.cpp | 288 +++++++++++++++++++++++++++++++++++++++++++++
loolwsd/common/SigUtil.hpp | 51 +++++++
loolwsd/test/Makefile.am | 1
13 files changed, 372 insertions(+), 276 deletions(-)
New commits:
commit 8072576424351b5e164a049357f6f081d1ffa3ca
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date: Mon Nov 14 08:58:04 2016 -0500
loolwsd: move signal and process code to SigUtil files
Change-Id: I91c001ef54858d942f8e3fe56d8a6b02cb2bf37e
Reviewed-on: https://gerrit.libreoffice.org/30846
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
diff --git a/loolwsd/Admin.cpp b/loolwsd/Admin.cpp
index dc2aa9d..445fa1e 100644
--- a/loolwsd/Admin.cpp
+++ b/loolwsd/Admin.cpp
@@ -40,6 +40,8 @@
#include "Unit.hpp"
#include "Util.hpp"
+#include "common/SigUtil.hpp"
+
using namespace LOOLProtocol;
using Poco::StringTokenizer;
@@ -124,7 +126,7 @@ bool AdminRequestHandler::adminCommandHandler(const std::vector<char>& payload)
{
const auto pid = std::stoi(tokens[1]);
LOG_INF("Admin request to kill PID: " << pid);
- Util::killChild(pid);
+ SigUtil::killChild(pid);
}
catch (std::invalid_argument& exc)
{
diff --git a/loolwsd/DocumentBroker.hpp b/loolwsd/DocumentBroker.hpp
index 2184925..7e94fa2 100644
--- a/loolwsd/DocumentBroker.hpp
+++ b/loolwsd/DocumentBroker.hpp
@@ -30,6 +30,8 @@
#include "TileCache.hpp"
#include "Util.hpp"
+#include "common/SigUtil.hpp"
+
// Forwards.
class DocumentBroker;
@@ -99,7 +101,7 @@ public:
if (_pid != -1 && rude && kill(_pid, 0) != 0 && errno != ESRCH)
{
LOG_INF("Killing child [" << _pid << "].");
- if (Util::killChild(_pid))
+ if (SigUtil::killChild(_pid))
{
LOG_ERR("Cannot terminate lokit [" << _pid << "]. Abandoning.");
}
diff --git a/loolwsd/LOOLForKit.cpp b/loolwsd/LOOLForKit.cpp
index 75156a0..6763225 100644
--- a/loolwsd/LOOLForKit.cpp
+++ b/loolwsd/LOOLForKit.cpp
@@ -32,12 +32,14 @@
#include <Poco/Util/Application.h>
#include "Common.hpp"
-#include "common/FileUtil.hpp"
#include "IoUtil.hpp"
#include "LOOLKit.hpp"
#include "Log.hpp"
#include "Unit.hpp"
#include "Util.hpp"
+
+#include "common/FileUtil.hpp"
+#include "common/SigUtil.hpp"
#include "security.h"
using Poco::Process;
@@ -259,7 +261,9 @@ static void printArgumentHelp()
int main(int argc, char** argv)
{
if (!hasCorrectUID("loolforkit"))
+ {
return Application::EXIT_SOFTWARE;
+ }
if (std::getenv("SLEEPFORDEBUGGER"))
{
@@ -273,6 +277,9 @@ int main(int argc, char** argv)
}
}
+ SigUtil::setFatalSignals();
+ SigUtil::setTerminationSignals();
+
// Initialization
const bool logToFile = std::getenv("LOOL_LOGFILE");
const char* logFilename = std::getenv("LOOL_LOGFILENAME");
@@ -286,9 +293,6 @@ int main(int argc, char** argv)
Log::initialize("frk", logLevel ? logLevel : "", logColor != nullptr, logToFile, logProperties);
- Util::setTerminationSignals();
- Util::setFatalSignals();
-
std::string childRoot;
std::string loSubPath;
std::string sysTemplate;
diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp
index 435b8a7..48902cb 100644
--- a/loolwsd/LOOLKit.cpp
+++ b/loolwsd/LOOLKit.cpp
@@ -54,7 +54,7 @@
#include "LOKitHelper.hpp"
#include "LOOLKit.hpp"
#include "LOOLProtocol.hpp"
-#include <LOOLWebSocket.hpp>
+#include "LOOLWebSocket.hpp"
#include "LibreOfficeKit.hpp"
#include "Log.hpp"
#include "Png.hpp"
@@ -64,6 +64,8 @@
#include "UserMessages.hpp"
#include "Util.hpp"
+#include "common/SigUtil.hpp"
+
#define LIB_SOFFICEAPP "lib" "sofficeapp" ".so"
#define LIB_MERGED "lib" "mergedlo" ".so"
@@ -1279,8 +1281,8 @@ void lokit_main(const std::string& childRoot,
bool queryVersion,
bool displayVersion)
{
- Util::setFatalSignals();
- Util::setTerminationSignals();
+ SigUtil::setFatalSignals();
+ SigUtil::setTerminationSignals();
Util::setThreadName("loolkit");
diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index 97ae19e..c503af7 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -227,10 +227,6 @@ bool LOOLSession::handleInput(const char *buffer, int length)
try
{
LOG_TRC(getName() << ": Recv: " << summary);
- if (TerminationFlag)
- {
- LOG_WRN("Input while terminating: [" << summary << "].");
- }
return _handleInput(buffer, length);
}
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 1ee548c..e6a5f27 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -114,6 +114,8 @@
#include "UserMessages.hpp"
#include "Util.hpp"
+#include "common/SigUtil.hpp"
+
using namespace LOOLProtocol;
using Poco::Environment;
@@ -1846,8 +1848,8 @@ Process::PID LOOLWSD::createForKit()
int LOOLWSD::main(const std::vector<std::string>& /*args*/)
{
- Util::setFatalSignals();
- Util::setTerminationSignals();
+ SigUtil::setFatalSignals();
+ SigUtil::setTerminationSignals();
// down-pay all the forkit linking cost once & early.
Environment::set("LD_BIND_NOW", "1");
@@ -1863,7 +1865,9 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
char* locale = setlocale(LC_ALL, nullptr);
if (locale == nullptr || std::strcmp(locale, "C") == 0)
+ {
setlocale(LC_ALL, "en_US.utf8");
+ }
if (access(Cache.c_str(), R_OK | W_OK | X_OK) != 0)
{
@@ -1989,7 +1993,7 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
{
LOG_ERR("Child process [" << pid << "] " <<
(WCOREDUMP(status) ? "core-dumped" : "died") <<
- " with " << Util::signalName(WTERMSIG(status)));
+ " with " << SigUtil::signalName(WTERMSIG(status)));
}
// Spawn a new forkit and try to dust it off and resume.
@@ -2003,7 +2007,7 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
else if (WIFSTOPPED(status) == true)
{
LOG_INF("Child process [" << pid << "] stopped with " <<
- Util::signalName(WSTOPSIG(status)));
+ SigUtil::signalName(WSTOPSIG(status)));
}
else if (WIFCONTINUED(status) == true)
{
@@ -2082,7 +2086,7 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
// Terminate child processes
LOG_INF("Requesting forkit process " << forKitPid << " to terminate.");
- Util::requestTermination(forKitPid);
+ SigUtil::requestTermination(forKitPid);
for (auto& child : NewChildren)
{
child->close(true);
diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index e7e69ff..a87599d 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -32,6 +32,7 @@ AM_CTAGSFLAGS = $(AM_ETAGSFLAGS)
shared_sources = ChildSession.cpp \
common/FileUtil.cpp \
+ common/SigUtil.cpp \
IoUtil.cpp \
Log.cpp \
LOOLProtocol.cpp \
@@ -95,6 +96,7 @@ noinst_HEADERS = Admin.hpp \
Exceptions.hpp \
FileServer.hpp \
common/FileUtil.hpp \
+ common/SigUtil.hpp \
IoUtil.hpp \
LibreOfficeKit.hpp \
Log.hpp \
diff --git a/loolwsd/Unit.cpp b/loolwsd/Unit.cpp
index f269fc7..ca83f4e 100644
--- a/loolwsd/Unit.cpp
+++ b/loolwsd/Unit.cpp
@@ -22,6 +22,8 @@
#include "Log.hpp"
#include "Util.hpp"
+#include "common/SigUtil.hpp"
+
UnitBase *UnitBase::Global = nullptr;
static Poco::Thread TimeoutThread("unit timeout");
diff --git a/loolwsd/Util.cpp b/loolwsd/Util.cpp
index 85ccd1e..b4aa969 100644
--- a/loolwsd/Util.cpp
+++ b/loolwsd/Util.cpp
@@ -50,10 +50,6 @@
#include "Log.hpp"
#include "Util.hpp"
-std::atomic<bool> TerminationFlag(false);
-std::atomic<bool> ShutdownFlag(false);
-std::mutex SigHandlerTrap;
-
namespace Util
{
namespace rng
@@ -136,206 +132,6 @@ namespace Util
namespace Util
{
- const char *signalName(const int signo)
- {
- switch (signo)
- {
-#define CASE(x) case SIG##x: return "SIG" #x
- CASE(HUP);
- CASE(INT);
- CASE(QUIT);
- CASE(ILL);
- CASE(ABRT);
- CASE(FPE);
- CASE(KILL);
- CASE(SEGV);
- CASE(PIPE);
- CASE(ALRM);
- CASE(TERM);
- CASE(USR1);
- CASE(USR2);
- CASE(CHLD);
- CASE(CONT);
- CASE(STOP);
- CASE(TSTP);
- CASE(TTIN);
- CASE(TTOU);
- CASE(BUS);
-#ifdef SIGPOLL
- CASE(POLL);
-#endif
- CASE(PROF);
- CASE(SYS);
- CASE(TRAP);
- CASE(URG);
- CASE(VTALRM);
- CASE(XCPU);
- CASE(XFSZ);
-#ifdef SIGEMT
- CASE(EMT);
-#endif
-#ifdef SIGSTKFLT
- CASE(STKFLT);
-#endif
-#if defined(SIGIO) && SIGIO != SIGPOLL
- CASE(IO);
-#endif
-#ifdef SIGPWR
- CASE(PWR);
-#endif
-#ifdef SIGLOST
- CASE(LOST);
-#endif
- CASE(WINCH);
-#if defined(SIGINFO) && SIGINFO != SIGPWR
- CASE(INFO);
-#endif
-#undef CASE
- default:
- return "unknown";
- }
- }
-
- static
- void handleTerminationSignal(const int signal)
- {
- if (!ShutdownFlag)
- {
- Log::signalLogPrefix();
- Log::signalLog(" Shutdown signal received: ");
- Log::signalLog(signalName(signal));
- Log::signalLog("\n");
- ShutdownFlag = true;
- return;
- }
-
- if (!TerminationFlag)
- {
- Log::signalLogPrefix();
- Log::signalLog(" Forced-Termination signal received: ");
- Log::signalLog(signalName(signal));
- Log::signalLog("\n");
- TerminationFlag = true;
- }
- }
-
- void setTerminationSignals()
- {
- struct sigaction action;
-
- sigemptyset(&action.sa_mask);
- action.sa_flags = 0;
- action.sa_handler = handleTerminationSignal;
-
- sigaction(SIGINT, &action, nullptr);
- sigaction(SIGTERM, &action, nullptr);
- sigaction(SIGQUIT, &action, nullptr);
- sigaction(SIGHUP, &action, nullptr);
- }
-
- static char FatalGdbString[256] = { '\0' };
-
- static
- void handleFatalSignal(const int signal)
- {
- std::unique_lock<std::mutex> lock(SigHandlerTrap);
-
- Log::signalLogPrefix();
- Log::signalLog(" Fatal signal received: ");
- Log::signalLog(signalName(signal));
- Log::signalLog("\n");
-
- if (std::getenv("LOOL_DEBUG"))
- {
- Log::signalLog(FatalGdbString);
- LOG_ERR("Sleeping 30s to allow debugging.");
- sleep(30);
- }
-
- struct sigaction action;
-
- sigemptyset(&action.sa_mask);
- action.sa_flags = 0;
- action.sa_handler = SIG_DFL;
-
- sigaction(signal, &action, NULL);
-
- char header[32];
- sprintf(header, "Backtrace %d:\n", getpid());
-
- const int maxSlots = 50;
- void *backtraceBuffer[maxSlots];
- int numSlots = backtrace(backtraceBuffer, maxSlots);
- if (numSlots > 0)
- {
- char **symbols = backtrace_symbols(backtraceBuffer, numSlots);
- if (symbols != NULL)
- {
- struct iovec ioVector[maxSlots*2+1];
- ioVector[0].iov_base = (void*)header;
- ioVector[0].iov_len = std::strlen((const char*)ioVector[0].iov_base);
- for (int i = 0; i < numSlots; i++)
- {
- ioVector[1+i*2+0].iov_base = symbols[i];
- ioVector[1+i*2+0].iov_len = std::strlen((const char *)ioVector[1+i*2+0].iov_base);
- ioVector[1+i*2+1].iov_base = (void*)"\n";
- ioVector[1+i*2+1].iov_len = 1;
- }
-
- if (writev(STDERR_FILENO, ioVector, numSlots*2+1) == -1)
- {
- LOG_SYS("Failed to dump backtrace to stderr.");
- }
- }
- }
-
- if (std::getenv("LOOL_DEBUG"))
- {
- LOG_ERR("Sleeping 30s to allow debugging.");
- sleep(30);
- }
-
- // let default handler process the signal
- kill(Poco::Process::id(), signal);
- }
-
- void setFatalSignals()
- {
- struct sigaction action;
-
- sigemptyset(&action.sa_mask);
- action.sa_flags = 0;
- action.sa_handler = handleFatalSignal;
-
- sigaction(SIGSEGV, &action, NULL);
- sigaction(SIGBUS, &action, NULL);
- sigaction(SIGABRT, &action, NULL);
- sigaction(SIGILL, &action, NULL);
- sigaction(SIGFPE, &action, NULL);
-
- // prepare this in advance just in case.
- std::ostringstream stream;
- stream << "\nFatal signal! Attach debugger with:\n"
- << "sudo gdb --pid=" << Poco::Process::id() << "\n or \n"
- << "sudo gdb --q --n --ex 'thread apply all backtrace full' --batch --pid="
- << Poco::Process::id() << "\n";
- std::string streamStr = stream.str();
- assert (sizeof (FatalGdbString) > strlen(streamStr.c_str()) + 1);
- strncpy(FatalGdbString, streamStr.c_str(), sizeof(FatalGdbString));
- }
-
- void requestTermination(const Poco::Process::PID& pid)
- {
- try
- {
- Poco::Process::requestTermination(pid);
- }
- catch(const Poco::Exception& exc)
- {
- Log::warn("Util::requestTermination: Exception: " + exc.message());
- }
- }
-
int getMemoryUsage(const Poco::Process::PID nPid)
{
try
@@ -408,34 +204,6 @@ namespace Util
static std::atomic_int counter(0);
return std::to_string(Poco::Process::id()) + "/" + std::to_string(counter++);
}
-
- bool killChild(const int pid)
- {
- LOG_DBG("Killing PID: " << pid);
- if (kill(pid, SIGTERM) == 0 || errno == ESRCH)
- {
- // Killed or doesn't exist.
- return true;
- }
-
- LOG_SYS("Error when trying to kill PID: " << pid << ". Will wait for termination.");
-
- const auto sleepMs = 50;
- const auto count = std::max(CHILD_REBALANCE_INTERVAL_MS / sleepMs, 2);
- for (int i = 0; i < count; ++i)
- {
- if (kill(pid, 0) == 0 || errno == ESRCH)
- {
- // Doesn't exist.
- return true;
- }
-
- std::this_thread::sleep_for(std::chrono::milliseconds(sleepMs));
- }
-
- LOG_WRN("Cannot terminate PID: " << pid);
- return false;
- }
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/Util.hpp b/loolwsd/Util.hpp
index 3abc53e..40bcc30 100644
--- a/loolwsd/Util.hpp
+++ b/loolwsd/Util.hpp
@@ -27,16 +27,6 @@
#define LOK_USE_UNSTABLE_API
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
-/// Flag to stop pump loops.
-extern std::atomic<bool> TerminationFlag;
-
-/// Flag to shutdown the server.
-extern std::atomic<bool> ShutdownFlag;
-
-/// Mutex to trap signal handler, if any,
-/// and prevent _Exit while collecting backtrace.
-extern std::mutex SigHandlerTrap;
-
namespace Util
{
namespace rng
@@ -82,22 +72,6 @@ namespace Util
assert(!mtx.try_lock());
}
- /// Returns the name of the signal.
- const char* signalName(int signo);
-
- /// Trap signals to cleanup and exit the process gracefully.
- void setTerminationSignals();
-
- /// Trap all fatal signals to assist debugging.
- void setFatalSignals();
-
- void requestTermination(const Poco::Process::PID& pid);
-
- /// Kills a child process and returns true when
- /// child pid is removed from the process table
- /// after a certain (short) timeout.
- bool killChild(const int pid);
-
int getMemoryUsage(const Poco::Process::PID nPid);
std::string replace(const std::string& s, const std::string& a, const std::string& b);
diff --git a/loolwsd/common/SigUtil.cpp b/loolwsd/common/SigUtil.cpp
new file mode 100644
index 0000000..f3e7f03
--- /dev/null
+++ b/loolwsd/common/SigUtil.cpp
@@ -0,0 +1,288 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "SigUtil.hpp"
+#include "config.h"
+
+#include <execinfo.h>
+#include <csignal>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <cassert>
+#include <chrono>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <mutex>
+#include <random>
+#include <sstream>
+#include <string>
+#include <thread>
+
+#include <Poco/Base64Encoder.h>
+#include <Poco/ConsoleChannel.h>
+#include <Poco/Exception.h>
+#include <Poco/Format.h>
+#include <Poco/Net/WebSocket.h>
+#include <Poco/Process.h>
+#include <Poco/RandomStream.h>
+#include <Poco/TemporaryFile.h>
+#include <Poco/Thread.h>
+#include <Poco/Timestamp.h>
+#include <Poco/Util/Application.h>
+
+#include "Common.hpp"
+#include "Log.hpp"
+#include "Util.hpp"
+
+std::atomic<bool> TerminationFlag(false);
+std::atomic<bool> ShutdownFlag(false);
+std::mutex SigHandlerTrap;
+
+namespace SigUtil
+{
+ const char *signalName(const int signo)
+ {
+ switch (signo)
+ {
+#define CASE(x) case SIG##x: return "SIG" #x
+ CASE(HUP);
+ CASE(INT);
+ CASE(QUIT);
+ CASE(ILL);
+ CASE(ABRT);
+ CASE(FPE);
+ CASE(KILL);
+ CASE(SEGV);
+ CASE(PIPE);
+ CASE(ALRM);
+ CASE(TERM);
+ CASE(USR1);
+ CASE(USR2);
+ CASE(CHLD);
+ CASE(CONT);
+ CASE(STOP);
+ CASE(TSTP);
+ CASE(TTIN);
+ CASE(TTOU);
+ CASE(BUS);
+#ifdef SIGPOLL
+ CASE(POLL);
+#endif
+ CASE(PROF);
+ CASE(SYS);
+ CASE(TRAP);
+ CASE(URG);
+ CASE(VTALRM);
+ CASE(XCPU);
+ CASE(XFSZ);
+#ifdef SIGEMT
+ CASE(EMT);
+#endif
+#ifdef SIGSTKFLT
+ CASE(STKFLT);
+#endif
+#if defined(SIGIO) && SIGIO != SIGPOLL
+ CASE(IO);
+#endif
+#ifdef SIGPWR
+ CASE(PWR);
+#endif
+#ifdef SIGLOST
+ CASE(LOST);
+#endif
+ CASE(WINCH);
+#if defined(SIGINFO) && SIGINFO != SIGPWR
+ CASE(INFO);
+#endif
+#undef CASE
+ default:
+ return "unknown";
+ }
+ }
+
+ static
+ void handleTerminationSignal(const int signal)
+ {
+ if (!ShutdownFlag)
+ {
+ Log::signalLogPrefix();
+ Log::signalLog(" Shutdown signal received: ");
+ Log::signalLog(signalName(signal));
+ Log::signalLog("\n");
+ ShutdownFlag = true;
+ return;
+ }
+
+ if (!TerminationFlag)
+ {
+ Log::signalLogPrefix();
+ Log::signalLog(" Forced-Termination signal received: ");
+ Log::signalLog(signalName(signal));
+ Log::signalLog("\n");
+ TerminationFlag = true;
+ }
+ }
+
+ void setTerminationSignals()
+ {
+ struct sigaction action;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_handler = handleTerminationSignal;
+
+ sigaction(SIGINT, &action, nullptr);
+ sigaction(SIGTERM, &action, nullptr);
+ sigaction(SIGQUIT, &action, nullptr);
+ sigaction(SIGHUP, &action, nullptr);
+ }
+
+ static char FatalGdbString[256] = { '\0' };
+
+ static
+ void handleFatalSignal(const int signal)
+ {
+ std::unique_lock<std::mutex> lock(SigHandlerTrap);
+
+ Log::signalLogPrefix();
+ Log::signalLog(" Fatal signal received: ");
+ Log::signalLog(signalName(signal));
+ Log::signalLog("\n");
+
+ if (std::getenv("LOOL_DEBUG"))
+ {
+ Log::signalLog(FatalGdbString);
+ LOG_ERR("Sleeping 30s to allow debugging.");
+ sleep(30);
+ }
+
+ struct sigaction action;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_handler = SIG_DFL;
+
+ sigaction(signal, &action, NULL);
+
+ char header[32];
+ sprintf(header, "Backtrace %d:\n", getpid());
+
+ const int maxSlots = 50;
+ void *backtraceBuffer[maxSlots];
+ int numSlots = backtrace(backtraceBuffer, maxSlots);
+ if (numSlots > 0)
+ {
+ char **symbols = backtrace_symbols(backtraceBuffer, numSlots);
+ if (symbols != NULL)
+ {
+ struct iovec ioVector[maxSlots*2+1];
+ ioVector[0].iov_base = (void*)header;
+ ioVector[0].iov_len = std::strlen((const char*)ioVector[0].iov_base);
+ for (int i = 0; i < numSlots; i++)
+ {
+ ioVector[1+i*2+0].iov_base = symbols[i];
+ ioVector[1+i*2+0].iov_len = std::strlen((const char *)ioVector[1+i*2+0].iov_base);
+ ioVector[1+i*2+1].iov_base = (void*)"\n";
+ ioVector[1+i*2+1].iov_len = 1;
+ }
+
+ if (writev(STDERR_FILENO, ioVector, numSlots*2+1) == -1)
+ {
+ LOG_SYS("Failed to dump backtrace to stderr.");
+ }
+ }
+ }
+
+ if (std::getenv("LOOL_DEBUG"))
+ {
+ LOG_ERR("Sleeping 30s to allow debugging.");
+ sleep(30);
+ }
+
+ // let default handler process the signal
+ kill(Poco::Process::id(), signal);
+ }
+
+ void setFatalSignals()
+ {
+ struct sigaction action;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_handler = handleFatalSignal;
+
+ sigaction(SIGSEGV, &action, NULL);
+ sigaction(SIGBUS, &action, NULL);
+ sigaction(SIGABRT, &action, NULL);
+ sigaction(SIGILL, &action, NULL);
+ sigaction(SIGFPE, &action, NULL);
+
+ // prepare this in advance just in case.
+ std::ostringstream stream;
+ stream << "\nFatal signal! Attach debugger with:\n"
+ << "sudo gdb --pid=" << Poco::Process::id() << "\n or \n"
+ << "sudo gdb --q --n --ex 'thread apply all backtrace full' --batch --pid="
+ << Poco::Process::id() << "\n";
+ std::string streamStr = stream.str();
+ assert (sizeof (FatalGdbString) > strlen(streamStr.c_str()) + 1);
+ strncpy(FatalGdbString, streamStr.c_str(), sizeof(FatalGdbString));
+ }
+
+ void requestTermination(const Poco::Process::PID& pid)
+ {
+ try
+ {
+ Poco::Process::requestTermination(pid);
+ }
+ catch(const Poco::Exception& exc)
+ {
+ Log::warn("Util::requestTermination: Exception: " + exc.message());
+ }
+ }
+
+ bool killChild(const int pid)
+ {
+ LOG_DBG("Killing PID: " << pid);
+ if (kill(pid, SIGTERM) == 0 || errno == ESRCH)
+ {
+ // Killed or doesn't exist.
+ return true;
+ }
+
+ LOG_SYS("Error when trying to kill PID: " << pid << ". Will wait for termination.");
+
+ const auto sleepMs = 50;
+ const auto count = std::max(CHILD_REBALANCE_INTERVAL_MS / sleepMs, 2);
+ for (int i = 0; i < count; ++i)
+ {
+ if (kill(pid, 0) == 0 || errno == ESRCH)
+ {
+ // Doesn't exist.
+ return true;
+ }
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleepMs));
+ }
+
+ LOG_WRN("Cannot terminate PID: " << pid);
+ return false;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/common/SigUtil.hpp b/loolwsd/common/SigUtil.hpp
new file mode 100644
index 0000000..13082cf
--- /dev/null
+++ b/loolwsd/common/SigUtil.hpp
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SIGNALUTIL_HPP
+#define INCLUDED_SIGNALUTIL_HPP
+
+#include <atomic>
+#include <mutex>
+#include <string>
+
+#include <Poco/Process.h>
+
+/// Flag to stop pump loops.
+extern std::atomic<bool> TerminationFlag;
+
+/// Flag to shutdown the server.
+extern std::atomic<bool> ShutdownFlag;
+
+/// Mutex to trap signal handler, if any,
+/// and prevent _Exit while collecting backtrace.
+extern std::mutex SigHandlerTrap;
+
+namespace SigUtil
+{
+ /// Returns the name of the signal.
+ const char* signalName(int signo);
+
+ /// Trap signals to cleanup and exit the process gracefully.
+ void setTerminationSignals();
+
+ /// Trap all fatal signals to assist debugging.
+ void setFatalSignals();
+
+ void requestTermination(const Poco::Process::PID& pid);
+
+ /// Kills a child process and returns true when
+ /// child pid is removed from the process table
+ /// after a certain (short) timeout.
+ bool killChild(const int pid);
+
+} // end namespace SigUtil
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/test/Makefile.am b/loolwsd/test/Makefile.am
index 9de6443..7600797 100644
--- a/loolwsd/test/Makefile.am
+++ b/loolwsd/test/Makefile.am
@@ -28,6 +28,7 @@ AM_CPPFLAGS = -pthread -I$(top_srcdir) -DBUILDING_TESTS
wsd_sources = \
../common/FileUtil.cpp \
+ ../common/SigUtil.cpp \
../IoUtil.cpp \
../Log.cpp \
../LOOLKit.cpp \
More information about the Libreoffice-commits
mailing list