office-gobmx/vcl/source/app/watchdog.cxx
Luboš Luňák e0a94e9625 improve debugger/valgrind handling in watchdog
This way it'll avoid incorrect lock-up detection also if the debugger
is attached later when LO is already running.

Change-Id: I9b762ee439a62631036ad2f09f4396cca0b5ba6b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88609
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
2020-02-13 18:21:55 +01:00

165 lines
4.3 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* 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 <watchdog.hxx>
#include <config_features.h>
#include <osl/conditn.hxx>
#include <rtl/ref.hxx>
#include <rtl/string.hxx>
#include <sal/log.hxx>
#include <comphelper/debuggerinfo.hxx>
#include <opengl/zone.hxx>
#include <skia/zone.hxx>
#include <stdlib.h>
#if defined HAVE_VALGRIND_HEADERS
#include <valgrind/memcheck.h>
#endif
namespace
{
static volatile bool gbWatchdogFiring = false;
static osl::Condition* gpWatchdogExit = nullptr;
static rtl::Reference<WatchdogThread> gxWatchdog;
template <typename Zone> struct WatchdogHelper
{
static inline sal_uInt64 nLastEnters = 0;
static inline int nUnchanged = 0; // how many unchanged nEnters
static inline bool bFired = false;
static inline bool bAbortFired = false;
static void setLastEnters() { nLastEnters = Zone::enterCount(); }
static void check()
{
if (Zone::isInZone())
{
const CrashWatchdogTimingsValues& aTimingValues = Zone::getCrashWatchdogTimingsValues();
if (nLastEnters == Zone::enterCount())
nUnchanged++;
else
nUnchanged = 0;
Zone::checkDebug(nUnchanged, aTimingValues);
// Not making progress
if (nUnchanged >= aTimingValues.mnDisableEntries)
{
if (!bFired)
{
gbWatchdogFiring = true;
SAL_WARN("vcl.watchdog",
OStringLiteral("Watchdog triggered: hard disable ") + Zone::name());
Zone::hardDisable();
gbWatchdogFiring = false;
}
bFired = true;
// we can hang using VCL in the abort handling -> be impatient
if (bAbortFired)
{
SAL_WARN("vcl.watchdog",
OStringLiteral("Watchdog gave up: hard exiting ") + Zone::name());
_Exit(1);
}
}
// Not making even more progress
if (nUnchanged >= aTimingValues.mnAbortAfter)
{
if (!bAbortFired)
{
SAL_WARN("vcl.watchdog",
OStringLiteral("Watchdog gave up: aborting ") + Zone::name());
gbWatchdogFiring = true;
std::abort();
}
// coverity[dead_error_line] - we might have caught SIGABRT and failed to exit yet
bAbortFired = true;
}
}
else
{
nUnchanged = 0;
}
}
};
} // namespace
WatchdogThread::WatchdogThread()
: salhelper::Thread("Crash Watchdog")
{
}
void WatchdogThread::execute()
{
TimeValue aQuarterSecond(0, 1000 * 1000 * 1000 * 0.25);
do
{
#if HAVE_FEATURE_OPENGL
WatchdogHelper<OpenGLZone>::setLastEnters();
#endif
#if HAVE_FEATURE_SKIA
WatchdogHelper<SkiaZone>::setLastEnters();
#endif
gpWatchdogExit->wait(&aQuarterSecond);
#if defined HAVE_VALGRIND_HEADERS
if (RUNNING_ON_VALGRIND)
continue;
#endif
#if defined DBG_UTIL
if (comphelper::isDebuggerAttached())
continue;
#endif
#if HAVE_FEATURE_OPENGL
WatchdogHelper<OpenGLZone>::check();
#endif
#if HAVE_FEATURE_SKIA
WatchdogHelper<SkiaZone>::check();
#endif
} while (!gpWatchdogExit->check());
}
void WatchdogThread::start()
{
if (gxWatchdog != nullptr)
return; // already running
if (getenv("SAL_DISABLE_WATCHDOG"))
return;
gpWatchdogExit = new osl::Condition();
gxWatchdog.set(new WatchdogThread());
gxWatchdog->launch();
}
void WatchdogThread::stop()
{
if (gbWatchdogFiring)
return; // in watchdog thread
if (gpWatchdogExit)
gpWatchdogExit->set();
if (gxWatchdog.is())
{
gxWatchdog->join();
gxWatchdog.clear();
}
delete gpWatchdogExit;
gpWatchdogExit = nullptr;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */