Remove dependence on std::function.
[oota-llvm.git] / include / llvm / Support / CrashRecoveryContext.h
1 //===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
11 #define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
12
13 #include <string>
14
15 namespace llvm {
16 class StringRef;
17
18 class CrashRecoveryContextCleanup;
19   
20 /// \brief Crash recovery helper object.
21 ///
22 /// This class implements support for running operations in a safe context so
23 /// that crashes (memory errors, stack overflow, assertion violations) can be
24 /// detected and control restored to the crashing thread. Crash detection is
25 /// purely "best effort", the exact set of failures which can be recovered from
26 /// is platform dependent.
27 ///
28 /// Clients make use of this code by first calling
29 /// CrashRecoveryContext::Enable(), and then executing unsafe operations via a
30 /// CrashRecoveryContext object. For example:
31 ///
32 ///    void actual_work(void *);
33 ///
34 ///    void foo() {
35 ///      CrashRecoveryContext CRC;
36 ///
37 ///      if (!CRC.RunSafely(actual_work, 0)) {
38 ///         ... a crash was detected, report error to user ...
39 ///      }
40 ///
41 ///      ... no crash was detected ...
42 ///    }
43 ///
44 /// Crash recovery contexts may not be nested.
45 class CrashRecoveryContext {
46   void *Impl;
47   CrashRecoveryContextCleanup *head;
48
49   /// An adaptor to convert an arbitrary functor into a void(void*), void* pair.
50   template<typename T> struct FunctorAdaptor {
51     T Fn;
52     static void invoke(void *Data) {
53       return static_cast<FunctorAdaptor<T>*>(Data)->Fn();
54     }
55     typedef void Callback(void*);
56     Callback *fn() { return &invoke; }
57     void *arg() { return this; }
58   };
59
60 public:
61   CrashRecoveryContext() : Impl(0), head(0) {}
62   ~CrashRecoveryContext();
63   
64   void registerCleanup(CrashRecoveryContextCleanup *cleanup);
65   void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);
66
67   /// \brief Enable crash recovery.
68   static void Enable();
69
70   /// \brief Disable crash recovery.
71   static void Disable();
72
73   /// \brief Return the active context, if the code is currently executing in a
74   /// thread which is in a protected context.
75   static CrashRecoveryContext *GetCurrent();
76
77   /// \brief Return true if the current thread is recovering from a
78   /// crash.
79   static bool isRecoveringFromCrash();
80
81   /// \brief Execute the provide callback function (with the given arguments) in
82   /// a protected context.
83   ///
84   /// \return True if the function completed successfully, and false if the
85   /// function crashed (or HandleCrash was called explicitly). Clients should
86   /// make as little assumptions as possible about the program state when
87   /// RunSafely has returned false. Clients can use getBacktrace() to retrieve
88   /// the backtrace of the crash on failures.
89   bool RunSafely(void (*Fn)(void*), void *UserData);
90   template<typename Functor>
91   bool RunSafely(Functor Fn) {
92     FunctorAdaptor<Functor> Adaptor = { Fn };
93     return RunSafely(Adaptor.fn(), Adaptor.arg());
94   }
95
96   /// \brief Execute the provide callback function (with the given arguments) in
97   /// a protected context which is run in another thread (optionally with a
98   /// requested stack size).
99   ///
100   /// See RunSafely() and llvm_execute_on_thread().
101   bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
102                          unsigned RequestedStackSize = 0);
103   template<typename Functor>
104   bool RunSafelyOnThread(Functor Fn, unsigned RequestedStackSize = 0) {
105     FunctorAdaptor<Functor> Adaptor = { Fn };
106     return RunSafelyOnThread(Adaptor.fn(), Adaptor.arg(), RequestedStackSize);
107   }
108
109   /// \brief Explicitly trigger a crash recovery in the current process, and
110   /// return failure from RunSafely(). This function does not return.
111   void HandleCrash();
112
113   /// \brief Return a string containing the backtrace where the crash was
114   /// detected; or empty if the backtrace wasn't recovered.
115   ///
116   /// This function is only valid when a crash has been detected (i.e.,
117   /// RunSafely() has returned false.
118   const std::string &getBacktrace() const;
119 };
120
121 class CrashRecoveryContextCleanup {
122 protected:
123   CrashRecoveryContext *context;
124   CrashRecoveryContextCleanup(CrashRecoveryContext *context)
125     : context(context), cleanupFired(false) {}
126 public:
127   bool cleanupFired;
128   
129   virtual ~CrashRecoveryContextCleanup();
130   virtual void recoverResources() = 0;
131
132   CrashRecoveryContext *getContext() const {
133     return context;
134   }
135
136 private:
137   friend class CrashRecoveryContext;
138   CrashRecoveryContextCleanup *prev, *next;
139 };
140
141 template<typename DERIVED, typename T>
142 class CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup {
143 protected:
144   T *resource;
145   CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T* resource)
146     : CrashRecoveryContextCleanup(context), resource(resource) {}
147 public:
148   static DERIVED *create(T *x) {
149     if (x) {
150       if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent())
151         return new DERIVED(context, x);
152     }
153     return 0;
154   }
155 };
156
157 template <typename T>
158 class CrashRecoveryContextDestructorCleanup : public
159   CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> {
160 public:
161   CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context,
162                                         T *resource) 
163     : CrashRecoveryContextCleanupBase<
164         CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {}
165
166   virtual void recoverResources() {
167     this->resource->~T();
168   }
169 };
170
171 template <typename T>
172 class CrashRecoveryContextDeleteCleanup : public
173   CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> {
174 public:
175   CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource)
176     : CrashRecoveryContextCleanupBase<
177         CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {}
178
179   virtual void recoverResources() {
180     delete this->resource;
181   }  
182 };
183
184 template <typename T>
185 class CrashRecoveryContextReleaseRefCleanup : public
186   CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T>
187 {
188 public:
189   CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context, 
190                                         T *resource)
191     : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>,
192           T>(context, resource) {}
193
194   virtual void recoverResources() {
195     this->resource->Release();
196   }
197 };
198
199 template <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> >
200 class CrashRecoveryContextCleanupRegistrar {
201   CrashRecoveryContextCleanup *cleanup;
202 public:
203   CrashRecoveryContextCleanupRegistrar(T *x)
204     : cleanup(Cleanup::create(x)) {
205     if (cleanup)
206       cleanup->getContext()->registerCleanup(cleanup);
207   }
208
209   ~CrashRecoveryContextCleanupRegistrar() {
210     unregister();
211   }
212   
213   void unregister() {
214     if (cleanup && !cleanup->cleanupFired)
215       cleanup->getContext()->unregisterCleanup(cleanup);
216     cleanup = 0;
217   }
218 };
219 }
220
221 #endif