|
|
|||
File indexing completed on 2026-05-10 08:44:29
0001 //===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 0009 #ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H 0010 #define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H 0011 0012 #include "llvm/ADT/STLFunctionalExtras.h" 0013 0014 namespace llvm { 0015 class CrashRecoveryContextCleanup; 0016 0017 /// Crash recovery helper object. 0018 /// 0019 /// This class implements support for running operations in a safe context so 0020 /// that crashes (memory errors, stack overflow, assertion violations) can be 0021 /// detected and control restored to the crashing thread. Crash detection is 0022 /// purely "best effort", the exact set of failures which can be recovered from 0023 /// is platform dependent. 0024 /// 0025 /// Clients make use of this code by first calling 0026 /// CrashRecoveryContext::Enable(), and then executing unsafe operations via a 0027 /// CrashRecoveryContext object. For example: 0028 /// 0029 /// \code 0030 /// void actual_work(void *); 0031 /// 0032 /// void foo() { 0033 /// CrashRecoveryContext CRC; 0034 /// 0035 /// if (!CRC.RunSafely(actual_work, 0)) { 0036 /// ... a crash was detected, report error to user ... 0037 /// } 0038 /// 0039 /// ... no crash was detected ... 0040 /// } 0041 /// \endcode 0042 /// 0043 /// To assist recovery the class allows specifying set of actions that will be 0044 /// executed in any case, whether crash occurs or not. These actions may be used 0045 /// to reclaim resources in the case of crash. 0046 class CrashRecoveryContext { 0047 void *Impl = nullptr; 0048 CrashRecoveryContextCleanup *head = nullptr; 0049 0050 public: 0051 CrashRecoveryContext(); 0052 ~CrashRecoveryContext(); 0053 0054 /// Register cleanup handler, which is used when the recovery context is 0055 /// finished. 0056 /// The recovery context owns the handler. 0057 void registerCleanup(CrashRecoveryContextCleanup *cleanup); 0058 0059 void unregisterCleanup(CrashRecoveryContextCleanup *cleanup); 0060 0061 /// Enable crash recovery. 0062 static void Enable(); 0063 0064 /// Disable crash recovery. 0065 static void Disable(); 0066 0067 /// Return the active context, if the code is currently executing in a 0068 /// thread which is in a protected context. 0069 static CrashRecoveryContext *GetCurrent(); 0070 0071 /// Return true if the current thread is recovering from a crash. 0072 static bool isRecoveringFromCrash(); 0073 0074 /// Execute the provided callback function (with the given arguments) in 0075 /// a protected context. 0076 /// 0077 /// \return True if the function completed successfully, and false if the 0078 /// function crashed (or HandleCrash was called explicitly). Clients should 0079 /// make as little assumptions as possible about the program state when 0080 /// RunSafely has returned false. 0081 bool RunSafely(function_ref<void()> Fn); 0082 bool RunSafely(void (*Fn)(void*), void *UserData) { 0083 return RunSafely([&]() { Fn(UserData); }); 0084 } 0085 0086 /// Execute the provide callback function (with the given arguments) in 0087 /// a protected context which is run in another thread (optionally with a 0088 /// requested stack size). 0089 /// 0090 /// See RunSafely(). 0091 /// 0092 /// On Darwin, if PRIO_DARWIN_BG is set on the calling thread, it will be 0093 /// propagated to the new thread as well. 0094 bool RunSafelyOnThread(function_ref<void()>, unsigned RequestedStackSize = 0); 0095 bool RunSafelyOnThread(void (*Fn)(void*), void *UserData, 0096 unsigned RequestedStackSize = 0) { 0097 return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize); 0098 } 0099 0100 /// Explicitly trigger a crash recovery in the current process, and 0101 /// return failure from RunSafely(). This function does not return. 0102 [[noreturn]] void HandleExit(int RetCode); 0103 0104 /// Return true if RetCode indicates that a signal or an exception occurred. 0105 static bool isCrash(int RetCode); 0106 0107 /// Throw again a signal or an exception, after it was catched once by a 0108 /// CrashRecoveryContext. 0109 static bool throwIfCrash(int RetCode); 0110 0111 /// In case of a crash, this is the crash identifier. 0112 int RetCode = 0; 0113 0114 /// Selects whether handling of failures should be done in the same way as 0115 /// for regular crashes. When this is active, a crash would print the 0116 /// callstack, clean-up any temporary files and create a coredump/minidump. 0117 bool DumpStackAndCleanupOnFailure = false; 0118 }; 0119 0120 /// Abstract base class of cleanup handlers. 0121 /// 0122 /// Derived classes override method recoverResources, which makes actual work on 0123 /// resource recovery. 0124 /// 0125 /// Cleanup handlers are stored in a double list, which is owned and managed by 0126 /// a crash recovery context. 0127 class CrashRecoveryContextCleanup { 0128 protected: 0129 CrashRecoveryContext *context = nullptr; 0130 CrashRecoveryContextCleanup(CrashRecoveryContext *context) 0131 : context(context) {} 0132 0133 public: 0134 bool cleanupFired = false; 0135 0136 virtual ~CrashRecoveryContextCleanup(); 0137 virtual void recoverResources() = 0; 0138 0139 CrashRecoveryContext *getContext() const { 0140 return context; 0141 } 0142 0143 private: 0144 friend class CrashRecoveryContext; 0145 CrashRecoveryContextCleanup *prev = nullptr, *next = nullptr; 0146 }; 0147 0148 /// Base class of cleanup handler that controls recovery of resources of the 0149 /// given type. 0150 /// 0151 /// \tparam Derived Class that uses this class as a base. 0152 /// \tparam T Type of controlled resource. 0153 /// 0154 /// This class serves as a base for its template parameter as implied by 0155 /// Curiously Recurring Template Pattern. 0156 /// 0157 /// This class factors out creation of a cleanup handler. The latter requires 0158 /// knowledge of the current recovery context, which is provided by this class. 0159 template<typename Derived, typename T> 0160 class CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup { 0161 protected: 0162 T *resource; 0163 CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T *resource) 0164 : CrashRecoveryContextCleanup(context), resource(resource) {} 0165 0166 public: 0167 /// Creates cleanup handler. 0168 /// \param x Pointer to the resource recovered by this handler. 0169 /// \return New handler or null if the method was called outside a recovery 0170 /// context. 0171 static Derived *create(T *x) { 0172 if (x) { 0173 if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent()) 0174 return new Derived(context, x); 0175 } 0176 return nullptr; 0177 } 0178 }; 0179 0180 /// Cleanup handler that reclaims resource by calling destructor on it. 0181 template <typename T> 0182 class CrashRecoveryContextDestructorCleanup : public 0183 CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> { 0184 public: 0185 CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context, 0186 T *resource) 0187 : CrashRecoveryContextCleanupBase< 0188 CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {} 0189 0190 void recoverResources() override { 0191 this->resource->~T(); 0192 } 0193 }; 0194 0195 /// Cleanup handler that reclaims resource by calling 'delete' on it. 0196 template <typename T> 0197 class CrashRecoveryContextDeleteCleanup : public 0198 CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> { 0199 public: 0200 CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource) 0201 : CrashRecoveryContextCleanupBase< 0202 CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {} 0203 0204 void recoverResources() override { delete this->resource; } 0205 }; 0206 0207 /// Cleanup handler that reclaims resource by calling its method 'Release'. 0208 template <typename T> 0209 class CrashRecoveryContextReleaseRefCleanup : public 0210 CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T> { 0211 public: 0212 CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context, 0213 T *resource) 0214 : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, 0215 T>(context, resource) {} 0216 0217 void recoverResources() override { this->resource->Release(); } 0218 }; 0219 0220 /// Helper class for managing resource cleanups. 0221 /// 0222 /// \tparam T Type of resource been reclaimed. 0223 /// \tparam Cleanup Class that defines how the resource is reclaimed. 0224 /// 0225 /// Clients create objects of this type in the code executed in a crash recovery 0226 /// context to ensure that the resource will be reclaimed even in the case of 0227 /// crash. For example: 0228 /// 0229 /// \code 0230 /// void actual_work(void *) { 0231 /// ... 0232 /// std::unique_ptr<Resource> R(new Resource()); 0233 /// CrashRecoveryContextCleanupRegistrar D(R.get()); 0234 /// ... 0235 /// } 0236 /// 0237 /// void foo() { 0238 /// CrashRecoveryContext CRC; 0239 /// 0240 /// if (!CRC.RunSafely(actual_work, 0)) { 0241 /// ... a crash was detected, report error to user ... 0242 /// } 0243 /// \endcode 0244 /// 0245 /// If the code of `actual_work` in the example above does not crash, the 0246 /// destructor of CrashRecoveryContextCleanupRegistrar removes cleanup code from 0247 /// the current CrashRecoveryContext and the resource is reclaimed by the 0248 /// destructor of std::unique_ptr. If crash happens, destructors are not called 0249 /// and the resource is reclaimed by cleanup object registered in the recovery 0250 /// context by the constructor of CrashRecoveryContextCleanupRegistrar. 0251 template <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> > 0252 class CrashRecoveryContextCleanupRegistrar { 0253 CrashRecoveryContextCleanup *cleanup; 0254 0255 public: 0256 CrashRecoveryContextCleanupRegistrar(T *x) 0257 : cleanup(Cleanup::create(x)) { 0258 if (cleanup) 0259 cleanup->getContext()->registerCleanup(cleanup); 0260 } 0261 0262 ~CrashRecoveryContextCleanupRegistrar() { unregister(); } 0263 0264 void unregister() { 0265 if (cleanup && !cleanup->cleanupFired) 0266 cleanup->getContext()->unregisterCleanup(cleanup); 0267 cleanup = nullptr; 0268 } 0269 }; 0270 } // end namespace llvm 0271 0272 #endif // LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|