1 //===--------------------- cxa_exception_storage.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 storage for the "Caught Exception Stack"
10 //  http://www.codesourcery.com/public/cxx-abi/abi-eh.html (section 2.2.2)
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "cxa_exception.hpp"
15 
16 #ifdef HAS_THREAD_LOCAL
17 
18 namespace __cxxabiv1 {
19 
20 namespace {
21     __cxa_eh_globals * __globals () noexcept {
22         static thread_local __cxa_eh_globals eh_globals;
23         return &eh_globals;
24         }
25     }
26 
27 extern "C" {
28     __cxa_eh_globals * __cxa_get_globals      () noexcept { return __globals (); }
29     __cxa_eh_globals * __cxa_get_globals_fast () noexcept { return __globals (); }
30     }
31 }
32 
33 #else
34 
35 #include <pthread.h>
36 #include <cstdlib>          // for calloc, free
37 #include "abort_message.h"
38 
39 //  In general, we treat all pthread errors as fatal.
40 //  We cannot call std::terminate() because that will in turn
41 //  call __cxa_get_globals() and cause infinite recursion.
42 
43 namespace __cxxabiv1 {
44 namespace {
45     pthread_key_t  key_;
46 
47     void destruct_ (void *p) noexcept {
48         std::free ( p );
49         if ( 0 != ::pthread_setspecific ( key_, NULL ) )
50             abort_message("cannot zero out thread value for __cxa_get_globals()");
51         }
52 
53     int construct_ () noexcept {
54         if ( 0 != pthread_key_create ( &key_, destruct_ ) )
55             abort_message("cannot create pthread key for __cxa_get_globals()");
56         return 0;
57         }
58 }
59 
60 extern "C" {
61     __cxa_eh_globals * __cxa_get_globals () noexcept {
62 
63     //  Try to get the globals for this thread
64         __cxa_eh_globals* retVal = __cxa_get_globals_fast ();
65 
66     //  If this is the first time we've been asked for these globals, create them
67         if ( NULL == retVal ) {
68             retVal = static_cast<__cxa_eh_globals*>
69                         (std::calloc (1, sizeof (__cxa_eh_globals)));
70             if ( NULL == retVal )
71                 abort_message("cannot allocate __cxa_eh_globals");
72             if ( 0 != pthread_setspecific ( key_, retVal ) )
73                abort_message("pthread_setspecific failure in __cxa_get_globals()");
74            }
75         return retVal;
76         }
77 
78     // Note that this implementation will reliably return NULL if not
79     // preceeded by a call to __cxa_get_globals().  This is an extension
80     // to the Itanium ABI and is taken advantage of in several places in
81     // libc++abi.
82     __cxa_eh_globals * __cxa_get_globals_fast () noexcept {
83     //  First time through, create the key.
84         static int init = construct_();
85         return static_cast<__cxa_eh_globals*>(::pthread_getspecific(key_));
86         }
87 
88 }
89 }
90 #endif
91