llvm.org GIT mirror llvm / release_40 include / llvm / Support / CrashRecoveryContext.h
release_40

Tree @release_40 (Download .tar.gz)

CrashRecoveryContext.h @release_40

a309dac
 
 
 
 
 
 
 
 
 
 
 
36ecb2e
 
a309dac
a4f9839
36ecb2e
a309dac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4f9839
a309dac
 
34bc6b6
a309dac
36ecb2e
a4f9839
 
a309dac
c0c815e
a309dac
 
c0c815e
a309dac
 
a8fa798
 
 
 
b52fde4
 
 
 
a309dac
 
 
 
 
 
c1303e8
36ecb2e
 
 
6e5887e
a309dac
f8254d6
 
 
 
 
ce6e7c7
 
 
36ecb2e
f8254d6
36ecb2e
 
6e5887e
f8254d6
a309dac
 
 
 
 
a4f9839
afc9e06
 
 
085ee02
e4b461c
a4f9839
1a06d57
d1769e3
a4f9839
 
afc9e06
 
 
 
 
a4f9839
 
 
 
 
afc9e06
 
 
a4f9839
085ee02
 
e4b461c
a4f9839
afc9e06
 
 
 
 
d16725c
a4f9839
 
0597234
 
afc9e06
 
0597234
afc9e06
d1769e3
085ee02
 
afc9e06
0597234
afc9e06
0597234
 
 
a4f9839
afc9e06
 
 
 
 
 
 
a80ff26
a4f9839
 
afc9e06
 
 
 
 
d1769e3
afc9e06
 
 
a4f9839
a80ff26
afc9e06
 
 
a4f9839
 
e4b461c
a4f9839
afc9e06
 
 
 
a4f9839
afc9e06
085ee02
d1769e3
2169ad8
afc9e06
2169ad8
d16725c
a4f9839
 
d16725c
a309dac
d16725c
//===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
#define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H

#include "llvm/ADT/STLExtras.h"

namespace llvm {
class CrashRecoveryContextCleanup;

/// \brief Crash recovery helper object.
///
/// This class implements support for running operations in a safe context so
/// that crashes (memory errors, stack overflow, assertion violations) can be
/// detected and control restored to the crashing thread. Crash detection is
/// purely "best effort", the exact set of failures which can be recovered from
/// is platform dependent.
///
/// Clients make use of this code by first calling
/// CrashRecoveryContext::Enable(), and then executing unsafe operations via a
/// CrashRecoveryContext object. For example:
///
///    void actual_work(void *);
///
///    void foo() {
///      CrashRecoveryContext CRC;
///
///      if (!CRC.RunSafely(actual_work, 0)) {
///         ... a crash was detected, report error to user ...
///      }
///
///      ... no crash was detected ...
///    }
class CrashRecoveryContext {
  void *Impl;
  CrashRecoveryContextCleanup *head;

public:
  CrashRecoveryContext() : Impl(nullptr), head(nullptr) {}
  ~CrashRecoveryContext();

  void registerCleanup(CrashRecoveryContextCleanup *cleanup);
  void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);

  /// \brief Enable crash recovery.
  static void Enable();

  /// \brief Disable crash recovery.
  static void Disable();

  /// \brief Return the active context, if the code is currently executing in a
  /// thread which is in a protected context.
  static CrashRecoveryContext *GetCurrent();

  /// \brief Return true if the current thread is recovering from a
  /// crash.
  static bool isRecoveringFromCrash();

  /// \brief Execute the provide callback function (with the given arguments) in
  /// a protected context.
  ///
  /// \return True if the function completed successfully, and false if the
  /// function crashed (or HandleCrash was called explicitly). Clients should
  /// make as little assumptions as possible about the program state when
  /// RunSafely has returned false.
  bool RunSafely(function_ref<void()> Fn);
  bool RunSafely(void (*Fn)(void*), void *UserData) {
    return RunSafely([&]() { Fn(UserData); });
  }

  /// \brief Execute the provide callback function (with the given arguments) in
  /// a protected context which is run in another thread (optionally with a
  /// requested stack size).
  ///
  /// See RunSafely() and llvm_execute_on_thread().
  ///
  /// On Darwin, if PRIO_DARWIN_BG is set on the calling thread, it will be
  /// propagated to the new thread as well.
  bool RunSafelyOnThread(function_ref<void()>, unsigned RequestedStackSize = 0);
  bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
                         unsigned RequestedStackSize = 0) {
    return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize);
  }

  /// \brief Explicitly trigger a crash recovery in the current process, and
  /// return failure from RunSafely(). This function does not return.
  void HandleCrash();
};

class CrashRecoveryContextCleanup {
protected:
  CrashRecoveryContext *context;
  CrashRecoveryContextCleanup(CrashRecoveryContext *context)
      : context(context), cleanupFired(false) {}

public:
  bool cleanupFired;

  virtual ~CrashRecoveryContextCleanup();
  virtual void recoverResources() = 0;

  CrashRecoveryContext *getContext() const {
    return context;
  }

private:
  friend class CrashRecoveryContext;
  CrashRecoveryContextCleanup *prev, *next;
};

template<typename DERIVED, typename T>
class CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup {
protected:
  T *resource;
  CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T *resource)
      : CrashRecoveryContextCleanup(context), resource(resource) {}

public:
  static DERIVED *create(T *x) {
    if (x) {
      if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent())
        return new DERIVED(context, x);
    }
    return nullptr;
  }
};

template <typename T>
class CrashRecoveryContextDestructorCleanup : public
  CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> {
public:
  CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context,
                                        T *resource)
      : CrashRecoveryContextCleanupBase<
            CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {}

  virtual void recoverResources() {
    this->resource->~T();
  }
};

template <typename T>
class CrashRecoveryContextDeleteCleanup : public
  CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> {
public:
  CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource)
    : CrashRecoveryContextCleanupBase<
        CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {}

  void recoverResources() override { delete this->resource; }
};

template <typename T>
class CrashRecoveryContextReleaseRefCleanup : public
  CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T>
{
public:
  CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context,
                                        T *resource)
    : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>,
          T>(context, resource) {}

  void recoverResources() override { this->resource->Release(); }
};

template <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> >
class CrashRecoveryContextCleanupRegistrar {
  CrashRecoveryContextCleanup *cleanup;

public:
  CrashRecoveryContextCleanupRegistrar(T *x)
    : cleanup(Cleanup::create(x)) {
    if (cleanup)
      cleanup->getContext()->registerCleanup(cleanup);
  }

  ~CrashRecoveryContextCleanupRegistrar() { unregister(); }

  void unregister() {
    if (cleanup && !cleanup->cleanupFired)
      cleanup->getContext()->unregisterCleanup(cleanup);
    cleanup = nullptr;
  }
};
} // end namespace llvm

#endif // LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H