CrashRecoveryContext.h revision 2169ad8c60c9d4fcc3665836be6c5f9302b1c4ec
1a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar//===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===//
2a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar//
3a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar//                     The LLVM Compiler Infrastructure
4a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar//
5a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// This file is distributed under the University of Illinois Open Source
6a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// License. See LICENSE.TXT for details.
7a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar//
8a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar//===----------------------------------------------------------------------===//
9a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
10a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar#ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
11a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar#define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
12a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
13a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar#include <string>
14a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
15a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarnamespace llvm {
16a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarclass StringRef;
17a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
18a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekclass CrashRecoveryContextCleanup;
19a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek
20a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// \brief Crash recovery helper object.
21a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///
22a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// This class implements support for running operations in a safe context so
23a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// that crashes (memory errors, stack overflow, assertion violations) can be
24a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// detected and control restored to the crashing thread. Crash detection is
25a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// purely "best effort", the exact set of failures which can be recovered from
26a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// is platform dependent.
27a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///
28a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// Clients make use of this code by first calling
29a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// CrashRecoveryContext::Enable(), and then executing unsafe operations via a
30a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// CrashRecoveryContext object. For example:
31a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///
32a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///    void actual_work(void *);
33a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///
34a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///    void foo() {
35a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///      CrashRecoveryContext CRC;
36a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///
37a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///      if (!CRC.RunSafely(actual_work, 0)) {
38a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///         ... a crash was detected, report error to user ...
39a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///      }
40a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///
41a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///      ... no crash was detected ...
42a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///    }
43a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar///
44a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar/// Crash recovery contexts may not be nested.
45a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarclass CrashRecoveryContext {
46a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  void *Impl;
47a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  CrashRecoveryContextCleanup *head;
48a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
49a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarpublic:
50a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  CrashRecoveryContext() : Impl(0), head(0) {}
51a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  ~CrashRecoveryContext();
52a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek
53a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  void registerCleanup(CrashRecoveryContextCleanup *cleanup);
54a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);
55a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
56c0c815e887d72414894930b62221acc32488c2d0Daniel Dunbar  /// \brief Enable crash recovery.
57a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  static void Enable();
58a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
59c0c815e887d72414894930b62221acc32488c2d0Daniel Dunbar  /// \brief Disable crash recovery.
60a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  static void Disable();
61a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
62a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar  /// \brief Return the active context, if the code is currently executing in a
63a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar  /// thread which is in a protected context.
64a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar  static CrashRecoveryContext *GetCurrent();
65a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar
66b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek  /// \brief Return true if the current thread is recovering from a
67b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek  /// crash.
68b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek  static bool isRecoveringFromCrash();
69b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek
70a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// \brief Execute the provide callback function (with the given arguments) in
71a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// a protected context.
72a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  ///
73a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// \return True if the function completed successfully, and false if the
74a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// function crashed (or HandleCrash was called explicitly). Clients should
75a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// make as little assumptions as possible about the program state when
76a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// RunSafely has returned false. Clients can use getBacktrace() to retrieve
77a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// the backtrace of the crash on failures.
78a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  bool RunSafely(void (*Fn)(void*), void *UserData);
79a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
80f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar  /// \brief Execute the provide callback function (with the given arguments) in
81f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar  /// a protected context which is run in another thread (optionally with a
82f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar  /// requested stack size).
83f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar  ///
84f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar  /// See RunSafely() and llvm_execute_on_thread().
85f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar  bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
86f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar                         unsigned RequestedStackSize = 0);
87f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar
88a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// \brief Explicitly trigger a crash recovery in the current process, and
89a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// return failure from RunSafely(). This function does not return.
90a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  void HandleCrash();
91a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
92a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// \brief Return a string containing the backtrace where the crash was
93a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// detected; or empty if the backtrace wasn't recovered.
94a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  ///
95a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// This function is only valid when a crash has been detected (i.e.,
96a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  /// RunSafely() has returned false.
97a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar  const std::string &getBacktrace() const;
98a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar};
99a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
100a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekclass CrashRecoveryContextCleanup {
101afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekprotected:
102afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContext *context;
103afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContextCleanup(CrashRecoveryContext *context)
1043311d951e22b133207ed6f8e384d80f0970a7fb3Ted Kremenek    : context(context), cleanupFired(false) {}
105a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekpublic:
1061a06d5721acb9a2b69217fc8872ed5b14a482104Ted Kremenek  bool cleanupFired;
1071a06d5721acb9a2b69217fc8872ed5b14a482104Ted Kremenek
108a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  virtual ~CrashRecoveryContextCleanup();
109a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  virtual void recoverResources() = 0;
110afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek
111afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContext *getContext() const {
112afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    return context;
113afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  }
114afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek
115a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekprivate:
116a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  friend class CrashRecoveryContext;
117a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  CrashRecoveryContextCleanup *prev, *next;
118a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek};
119a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek
120afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenektemplate<typename DERIVED, typename T>
121afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup {
122afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekprotected:
123a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  T *resource;
124afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T* resource)
125afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    : CrashRecoveryContextCleanup(context), resource(resource) {}
126a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekpublic:
127afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  static DERIVED *create(T *x) {
128afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    if (x) {
129afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek      if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent())
130afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek        return new DERIVED(context, x);
131afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    }
132afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    return 0;
133a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  }
134a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek};
1350597234028d14e454673bec8d8196285a9712364Ted Kremenek
1360597234028d14e454673bec8d8196285a9712364Ted Kremenektemplate <typename T>
137afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextDestructorCleanup : public
138afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> {
1390597234028d14e454673bec8d8196285a9712364Ted Kremenekpublic:
140afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context,
141afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek                                        T *resource)
142afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    : CrashRecoveryContextCleanupBase<
143afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek        CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {}
144afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek
1450597234028d14e454673bec8d8196285a9712364Ted Kremenek  virtual void recoverResources() {
146afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    this->resource->~T();
1470597234028d14e454673bec8d8196285a9712364Ted Kremenek  }
1480597234028d14e454673bec8d8196285a9712364Ted Kremenek};
1490597234028d14e454673bec8d8196285a9712364Ted Kremenek
150a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenektemplate <typename T>
151afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextDeleteCleanup : public
152afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> {
153afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekpublic:
154afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource)
155afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    : CrashRecoveryContextCleanupBase<
156afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek        CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {}
157afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek
158afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  virtual void recoverResources() {
159afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    delete this->resource;
160afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  }
161a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek};
162a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek
163afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenektemplate <typename T>
164afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekclass CrashRecoveryContextReleaseRefCleanup : public
165afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T>
166afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek{
167afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenekpublic:
168afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context,
169afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek                                        T *resource)
170afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>,
171afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek          T>(context, resource) {}
172a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek
173afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  virtual void recoverResources() {
174afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    this->resource->Release();
175afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  }
176afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek};
177afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek
178afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenektemplate <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> >
179a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekclass CrashRecoveryContextCleanupRegistrar {
180a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  CrashRecoveryContextCleanup *cleanup;
181a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekpublic:
182afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek  CrashRecoveryContextCleanupRegistrar(T *x)
183afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    : cleanup(Cleanup::create(x)) {
184afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    if (cleanup)
185afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek      cleanup->getContext()->registerCleanup(cleanup);
186a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  }
187afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek
188a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  ~CrashRecoveryContextCleanupRegistrar() {
1892169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek    unregister();
1902169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek  }
1912169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek
1922169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek  void unregister() {
193afc9e06021d4682d0faab2bdad57d6252dfca946Ted Kremenek    if (cleanup && !cleanup->cleanupFired)
1942169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek      cleanup->getContext()->unregisterCleanup(cleanup);
1952169ad8c60c9d4fcc3665836be6c5f9302b1c4ecTed Kremenek    cleanup = 0;
196a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek  }
197a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek};
198a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar}
199a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar
200a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar#endif
201