1 // -*- C++ -*- Implement the members of exception_ptr. 2 // Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. 3 // 4 // This file is part of GCC. 5 // 6 // GCC is free software; you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 // 11 // GCC is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 #include <bits/c++config.h> 26 #include <bits/atomic_lockfree_defines.h> 27 28 #if ATOMIC_INT_LOCK_FREE > 1 29 30 #define _GLIBCXX_EH_PTR_COMPAT 31 32 #include <exception> 33 #include <bits/exception_ptr.h> 34 #include "unwind-cxx.h" 35 36 using namespace __cxxabiv1; 37 38 std::__exception_ptr::exception_ptr::exception_ptr() _GLIBCXX_USE_NOEXCEPT 39 : _M_exception_object(0) { } 40 41 42 std::__exception_ptr::exception_ptr::exception_ptr(void* obj) 43 _GLIBCXX_USE_NOEXCEPT 44 : _M_exception_object(obj) { _M_addref(); } 45 46 47 std::__exception_ptr::exception_ptr::exception_ptr(__safe_bool) 48 _GLIBCXX_USE_NOEXCEPT 49 : _M_exception_object(0) { } 50 51 52 std::__exception_ptr:: 53 exception_ptr::exception_ptr(const exception_ptr& other) _GLIBCXX_USE_NOEXCEPT 54 : _M_exception_object(other._M_exception_object) 55 { _M_addref(); } 56 57 58 std::__exception_ptr::exception_ptr::~exception_ptr() _GLIBCXX_USE_NOEXCEPT 59 { _M_release(); } 60 61 62 std::__exception_ptr::exception_ptr& 63 std::__exception_ptr:: 64 exception_ptr::operator=(const exception_ptr& other) _GLIBCXX_USE_NOEXCEPT 65 { 66 exception_ptr(other).swap(*this); 67 return *this; 68 } 69 70 71 void 72 std::__exception_ptr::exception_ptr::_M_addref() _GLIBCXX_USE_NOEXCEPT 73 { 74 if (_M_exception_object) 75 { 76 __cxa_refcounted_exception *eh = 77 __get_refcounted_exception_header_from_obj (_M_exception_object); 78 __atomic_add_fetch (&eh->referenceCount, 1, __ATOMIC_ACQ_REL); 79 } 80 } 81 82 83 void 84 std::__exception_ptr::exception_ptr::_M_release() _GLIBCXX_USE_NOEXCEPT 85 { 86 if (_M_exception_object) 87 { 88 __cxa_refcounted_exception *eh = 89 __get_refcounted_exception_header_from_obj (_M_exception_object); 90 if (__atomic_sub_fetch (&eh->referenceCount, 1, __ATOMIC_ACQ_REL) == 0) 91 { 92 if (eh->exc.exceptionDestructor) 93 eh->exc.exceptionDestructor (_M_exception_object); 94 95 __cxa_free_exception (_M_exception_object); 96 _M_exception_object = 0; 97 } 98 } 99 } 100 101 102 void* 103 std::__exception_ptr::exception_ptr::_M_get() const _GLIBCXX_USE_NOEXCEPT 104 { return _M_exception_object; } 105 106 107 void 108 std::__exception_ptr::exception_ptr::swap(exception_ptr &other) 109 _GLIBCXX_USE_NOEXCEPT 110 { 111 void *tmp = _M_exception_object; 112 _M_exception_object = other._M_exception_object; 113 other._M_exception_object = tmp; 114 } 115 116 117 // Retained for compatibility with CXXABI_1.3. 118 void 119 std::__exception_ptr::exception_ptr::_M_safe_bool_dummy() 120 _GLIBCXX_USE_NOEXCEPT { } 121 122 123 // Retained for compatibility with CXXABI_1.3. 124 bool 125 std::__exception_ptr::exception_ptr::operator!() const _GLIBCXX_USE_NOEXCEPT 126 { return _M_exception_object == 0; } 127 128 129 // Retained for compatibility with CXXABI_1.3. 130 std::__exception_ptr::exception_ptr::operator __safe_bool() const 131 _GLIBCXX_USE_NOEXCEPT 132 { 133 return _M_exception_object ? &exception_ptr::_M_safe_bool_dummy : 0; 134 } 135 136 137 const std::type_info* 138 std::__exception_ptr::exception_ptr::__cxa_exception_type() const 139 _GLIBCXX_USE_NOEXCEPT 140 { 141 __cxa_exception *eh = __get_exception_header_from_obj (_M_exception_object); 142 return eh->exceptionType; 143 } 144 145 146 bool std::__exception_ptr::operator==(const exception_ptr& lhs, 147 const exception_ptr& rhs) 148 _GLIBCXX_USE_NOEXCEPT 149 { return lhs._M_exception_object == rhs._M_exception_object; } 150 151 152 bool std::__exception_ptr::operator!=(const exception_ptr& lhs, 153 const exception_ptr& rhs) 154 _GLIBCXX_USE_NOEXCEPT 155 { return !(lhs == rhs);} 156 157 158 std::exception_ptr 159 std::current_exception() _GLIBCXX_USE_NOEXCEPT 160 { 161 __cxa_eh_globals *globals = __cxa_get_globals (); 162 __cxa_exception *header = globals->caughtExceptions; 163 164 if (!header) 165 return std::exception_ptr(); 166 167 // Since foreign exceptions can't be counted, we can't return them. 168 if (!__is_gxx_exception_class (header->unwindHeader.exception_class)) 169 return std::exception_ptr(); 170 171 return std::exception_ptr( 172 __get_object_from_ambiguous_exception (header)); 173 } 174 175 176 static void 177 __gxx_dependent_exception_cleanup(_Unwind_Reason_Code code, 178 _Unwind_Exception *exc) 179 { 180 // This cleanup is set only for dependents. 181 __cxa_dependent_exception *dep = __get_dependent_exception_from_ue (exc); 182 __cxa_refcounted_exception *header = 183 __get_refcounted_exception_header_from_obj (dep->primaryException); 184 185 // We only want to be called through _Unwind_DeleteException. 186 // _Unwind_DeleteException in the HP-UX IA64 libunwind library 187 // returns _URC_NO_REASON and not _URC_FOREIGN_EXCEPTION_CAUGHT 188 // like the GCC _Unwind_DeleteException function does. 189 if (code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON) 190 __terminate (header->exc.terminateHandler); 191 192 __cxa_free_dependent_exception (dep); 193 194 if (__atomic_sub_fetch (&header->referenceCount, 1, __ATOMIC_ACQ_REL) == 0) 195 { 196 if (header->exc.exceptionDestructor) 197 header->exc.exceptionDestructor (header + 1); 198 199 __cxa_free_exception (header + 1); 200 } 201 } 202 203 204 void 205 std::rethrow_exception(std::exception_ptr ep) 206 { 207 void *obj = ep._M_get(); 208 __cxa_refcounted_exception *eh 209 = __get_refcounted_exception_header_from_obj (obj); 210 211 __cxa_dependent_exception *dep = __cxa_allocate_dependent_exception (); 212 dep->primaryException = obj; 213 __atomic_add_fetch (&eh->referenceCount, 1, __ATOMIC_ACQ_REL); 214 215 dep->unexpectedHandler = __unexpected_handler; 216 dep->terminateHandler = __terminate_handler; 217 __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(dep->unwindHeader.exception_class); 218 dep->unwindHeader.exception_cleanup = __gxx_dependent_exception_cleanup; 219 220 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS 221 _Unwind_SjLj_RaiseException (&dep->unwindHeader); 222 #else 223 _Unwind_RaiseException (&dep->unwindHeader); 224 #endif 225 226 // Some sort of unwinding error. Note that terminate is a handler. 227 __cxa_begin_catch (&dep->unwindHeader); 228 std::terminate(); 229 } 230 231 #undef _GLIBCXX_EH_PTR_COMPAT 232 233 #endif 234