1//===------------------------- cxa_handlers.cpp ---------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//
9// This file implements the functionality associated with the terminate_handler,
10//   unexpected_handler, and new_handler.
11//===----------------------------------------------------------------------===//
12
13#include <stdexcept>
14#include <new>
15#include <exception>
16#include "abort_message.h"
17#include "cxxabi.h"
18#include "cxa_handlers.hpp"
19#include "cxa_exception.hpp"
20#include "private_typeinfo.h"
21
22namespace std
23{
24
25unexpected_handler
26get_unexpected() _NOEXCEPT
27{
28    return __sync_fetch_and_add(&__cxa_unexpected_handler, (unexpected_handler)0);
29//  The above is safe but overkill on x86
30//  Using of C++11 atomics this should be rewritten
31//  return __cxa_unexpected_handler.load(memory_order_acq);
32}
33
34void
35__unexpected(unexpected_handler func)
36{
37    func();
38    // unexpected handler should not return
39    abort_message("unexpected_handler unexpectedly returned");
40}
41
42__attribute__((noreturn))
43void
44unexpected()
45{
46    __unexpected(get_unexpected());
47}
48
49terminate_handler
50get_terminate() _NOEXCEPT
51{
52    return __sync_fetch_and_add(&__cxa_terminate_handler, (terminate_handler)0);
53//  The above is safe but overkill on x86
54//  Using of C++11 atomics this should be rewritten
55//  return __cxa_terminate_handler.load(memory_order_acq);
56}
57
58void
59__terminate(terminate_handler func) _NOEXCEPT
60{
61#ifndef _LIBCXXABI_NO_EXCEPTIONS
62    try
63    {
64#endif  // _LIBCXXABI_NO_EXCEPTIONS
65        func();
66        // handler should not return
67        abort_message("terminate_handler unexpectedly returned");
68#ifndef _LIBCXXABI_NO_EXCEPTIONS
69    }
70    catch (...)
71    {
72        // handler should not throw exception
73        abort_message("terminate_handler unexpectedly threw an exception");
74    }
75#endif  // _LIBCXXABI_NO_EXCEPTIONS
76}
77
78__attribute__((noreturn))
79void
80terminate() _NOEXCEPT
81{
82    // If there might be an uncaught exception
83    using namespace __cxxabiv1;
84    __cxa_eh_globals* globals = __cxa_get_globals_fast();
85    if (globals)
86    {
87        __cxa_exception* exception_header = globals->caughtExceptions;
88        if (exception_header)
89        {
90            _Unwind_Exception* unwind_exception =
91                reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
92            bool native_exception =
93                (unwind_exception->exception_class & get_vendor_and_language) ==
94                               (kOurExceptionClass & get_vendor_and_language);
95            if (native_exception)
96                __terminate(exception_header->terminateHandler);
97        }
98    }
99    __terminate(get_terminate());
100}
101
102// In the future this will become:
103// std::atomic<std::new_handler>  __cxa_new_handler(0);
104extern "C" {
105new_handler __cxa_new_handler = 0;
106}
107
108new_handler
109set_new_handler(new_handler handler) _NOEXCEPT
110{
111    return __atomic_exchange_n(&__cxa_new_handler, handler, __ATOMIC_ACQ_REL);
112//  Using of C++11 atomics this should be rewritten
113//  return __cxa_new_handler.exchange(handler, memory_order_acq_rel);
114}
115
116new_handler
117get_new_handler() _NOEXCEPT
118{
119    return __sync_fetch_and_add(&__cxa_new_handler, (new_handler)0);
120//  The above is safe but overkill on x86
121//  Using of C++11 atomics this should be rewritten
122//  return __cxa_new_handler.load(memory_order_acq);
123}
124
125}  // std
126