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 () throw () {
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      () throw() { return __globals (); }
29     __cxa_eh_globals * __cxa_get_globals_fast () throw() { 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_once_t flag_ = PTHREAD_ONCE_INIT;
46     pthread_key_t  key_;
47 
48     void destruct_ (void *p) throw () {
49         std::free ( p );
50         if ( 0 != ::pthread_setspecific ( key_, NULL ) )
51             abort_message("cannot zero out thread value for __cxa_get_globals()");
52         }
53 
54     void construct_ () throw () {
55         if ( 0 != pthread_key_create ( &key_, destruct_ ) )
56             abort_message("cannot create pthread key for __cxa_get_globals()");
57         }
58 }
59 
60 extern "C" {
61     __cxa_eh_globals * __cxa_get_globals () throw () {
62     //  First time through, create the key.
63         if ( 0 != pthread_once ( &flag_, construct_ ) )
64             abort_message("cannot run pthread_once for __cxa_get_globals()");
65 
66     //  Try to get the globals for this thread
67         __cxa_eh_globals* retVal = __cxa_get_globals_fast ();
68 
69     //  If this is the first time we've been asked for these globals, create them
70         if ( NULL == retVal ) {
71             retVal = static_cast<__cxa_eh_globals*>
72                         (std::calloc (1, sizeof (__cxa_eh_globals)));
73             if ( NULL == retVal )
74                 abort_message("cannot allocate __cxa_eh_globals");
75             if ( 0 != pthread_setspecific ( key_, retVal ) )
76                abort_message("pthread_setspecific failure in __cxa_get_globals()");
77            }
78         return retVal;
79         }
80 
81     __cxa_eh_globals * __cxa_get_globals_fast () throw () {
82         return static_cast<__cxa_eh_globals*>(::pthread_getspecific(key_));
83         }
84 
85 }
86 }
87 #endif
88