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