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 "config.h"
18#include "cxxabi.h"
19#include "cxa_handlers.hpp"
20#include "cxa_exception.hpp"
21#include "private_typeinfo.h"
22
23namespace std
24{
25
26unexpected_handler
27get_unexpected() _NOEXCEPT
28{
29    return __sync_fetch_and_add(&__cxa_unexpected_handler, (unexpected_handler)0);
30//  The above is safe but overkill on x86
31//  Using of C++11 atomics this should be rewritten
32//  return __cxa_unexpected_handler.load(memory_order_acq);
33}
34
35__attribute__((visibility("hidden"), noreturn))
36void
37__unexpected(unexpected_handler func)
38{
39    func();
40    // unexpected handler should not return
41    abort_message("unexpected_handler unexpectedly returned");
42}
43
44__attribute__((noreturn))
45void
46unexpected()
47{
48    __unexpected(get_unexpected());
49}
50
51terminate_handler
52get_terminate() _NOEXCEPT
53{
54    return __sync_fetch_and_add(&__cxa_terminate_handler, (terminate_handler)0);
55//  The above is safe but overkill on x86
56//  Using of C++11 atomics this should be rewritten
57//  return __cxa_terminate_handler.load(memory_order_acq);
58}
59
60__attribute__((visibility("hidden"), noreturn))
61void
62__terminate(terminate_handler func) _NOEXCEPT
63{
64#if __has_feature(cxx_exceptions)
65    try
66    {
67#endif  // __has_feature(cxx_exceptions)
68        func();
69        // handler should not return
70        abort_message("terminate_handler unexpectedly returned");
71#if __has_feature(cxx_exceptions)
72    }
73    catch (...)
74    {
75        // handler should not throw exception
76        abort_message("terminate_handler unexpectedly threw an exception");
77    }
78#endif  // #if __has_feature(cxx_exceptions)
79}
80
81__attribute__((noreturn))
82void
83terminate() _NOEXCEPT
84{
85    // If there might be an uncaught exception
86    using namespace __cxxabiv1;
87    __cxa_eh_globals* globals = __cxa_get_globals_fast();
88    if (globals)
89    {
90        __cxa_exception* exception_header = globals->caughtExceptions;
91        if (exception_header)
92        {
93            _Unwind_Exception* unwind_exception =
94                reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
95            bool native_exception =
96                (unwind_exception->exception_class & get_vendor_and_language) ==
97                               (kOurExceptionClass & get_vendor_and_language);
98            if (native_exception)
99                __terminate(exception_header->terminateHandler);
100        }
101    }
102    __terminate(get_terminate());
103}
104
105extern "C" new_handler __cxa_new_handler = 0;
106// In the future these will become:
107// std::atomic<std::new_handler>  __cxa_new_handler(0);
108
109new_handler
110set_new_handler(new_handler handler) _NOEXCEPT
111{
112    return __sync_swap(&__cxa_new_handler, handler);
113//  Using of C++11 atomics this should be rewritten
114//  return __cxa_new_handler.exchange(handler, memory_order_acq_rel);
115}
116
117new_handler
118get_new_handler() _NOEXCEPT
119{
120    return __sync_fetch_and_add(&__cxa_new_handler, (new_handler)0);
121//  The above is safe but overkill on x86
122//  Using of C++11 atomics this should be rewritten
123//  return __cxa_new_handler.load(memory_order_acq);
124}
125
126}  // std
127