Related: tdf#163126 fix failure to restart print job
[LibreOffice.git] / vcl / source / app / watchdog.cxx
blobdc2153e639074ac35106ba32226f673eeedc3599
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <watchdog.hxx>
12 #include <config_features.h>
14 #include <osl/conditn.hxx>
15 #include <rtl/ref.hxx>
16 #include <rtl/string.hxx>
17 #include <sal/log.hxx>
18 #include <comphelper/debuggerinfo.hxx>
19 #include <opengl/zone.hxx>
20 #include <skia/zone.hxx>
22 #include <stdlib.h>
24 #if defined HAVE_VALGRIND_HEADERS
25 #include <valgrind/memcheck.h>
26 #endif
28 #include <atomic>
30 namespace
32 std::atomic<bool> gbWatchdogFiring = false;
33 osl::Condition* gpWatchdogExit = nullptr;
34 rtl::Reference<WatchdogThread> gxWatchdog;
36 template <typename Zone> struct WatchdogHelper
38 static inline sal_uInt64 nLastEnters = 0;
39 static inline int nUnchanged = 0; // how many unchanged nEnters
40 static inline bool bFired = false;
41 static inline bool bAbortFired = false;
42 static void setLastEnters() { nLastEnters = Zone::enterCount(); }
43 static void check()
45 if (Zone::isInZone())
47 const CrashWatchdogTimingsValues& aTimingValues = Zone::getCrashWatchdogTimingsValues();
49 if (nLastEnters == Zone::enterCount())
50 nUnchanged++;
51 else
52 nUnchanged = 0;
53 Zone::checkDebug(nUnchanged, aTimingValues);
55 // Not making progress
56 if (nUnchanged >= aTimingValues.mnDisableEntries)
58 if (!bFired)
60 gbWatchdogFiring = true;
61 SAL_WARN("vcl.watchdog", "Watchdog triggered: hard disable " << Zone::name());
62 #ifdef DBG_UTIL
63 std::abort();
64 #else
65 Zone::hardDisable();
66 gbWatchdogFiring = false;
67 #endif
69 bFired = true;
71 // we can hang using VCL in the abort handling -> be impatient
72 if (bAbortFired)
74 SAL_WARN("vcl.watchdog", "Watchdog gave up: hard exiting " << Zone::name());
75 _Exit(1);
79 // Not making even more progress
80 if (nUnchanged >= aTimingValues.mnAbortAfter)
82 if (!bAbortFired)
84 SAL_WARN("vcl.watchdog", "Watchdog gave up: aborting " << Zone::name());
85 gbWatchdogFiring = true;
86 std::abort();
88 // coverity[dead_error_line] - we might have caught SIGABRT and failed to exit yet
89 bAbortFired = true;
92 else
94 nUnchanged = 0;
99 } // namespace
101 WatchdogThread::WatchdogThread()
102 : salhelper::Thread("Crash Watchdog")
106 void WatchdogThread::execute()
108 TimeValue aQuarterSecond(0, 1000 * 1000 * 1000 * 0.25);
111 #if HAVE_FEATURE_OPENGL
112 WatchdogHelper<OpenGLZone>::setLastEnters();
113 #endif
114 #if HAVE_FEATURE_SKIA
115 WatchdogHelper<SkiaZone>::setLastEnters();
116 #endif
118 gpWatchdogExit->wait(&aQuarterSecond);
120 #if defined HAVE_VALGRIND_HEADERS
121 if (RUNNING_ON_VALGRIND)
122 continue;
123 #endif
124 #if defined DBG_UTIL
125 if (comphelper::isDebuggerAttached())
126 continue;
127 #endif
129 #if HAVE_FEATURE_OPENGL
130 WatchdogHelper<OpenGLZone>::check();
131 #endif
132 #if HAVE_FEATURE_SKIA
133 WatchdogHelper<SkiaZone>::check();
134 #endif
136 } while (!gpWatchdogExit->check());
139 void WatchdogThread::start()
141 if (gxWatchdog != nullptr)
142 return; // already running
143 if (getenv("SAL_DISABLE_WATCHDOG"))
144 return;
145 gpWatchdogExit = new osl::Condition();
146 gxWatchdog.set(new WatchdogThread());
147 gxWatchdog->launch();
150 void WatchdogThread::stop()
152 if (gbWatchdogFiring)
153 return; // in watchdog thread
155 if (gpWatchdogExit)
156 gpWatchdogExit->set();
158 if (gxWatchdog.is())
160 gxWatchdog->join();
161 gxWatchdog.clear();
164 delete gpWatchdogExit;
165 gpWatchdogExit = nullptr;
168 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */