1 #include <NTL/config.h>
2 #include <NTL/new.h>
3 #include <atomic>
4 #include <thread>
5 #include <utility>
6 #include <cstdlib>
7 
8 #include <iostream>
9 
TerminalError(const char * s)10 void TerminalError(const char *s)
11 {
12    std::cerr << s << "\n";
13    std::abort();
14 }
15 
MemoryError()16 void MemoryError() { TerminalError("out of memory"); }
ResourceError(const char * msg)17 void ResourceError(const char *msg) { TerminalError(msg); }
18 
19 
20 #if (defined(NTL_THREADS) && defined(NTL_TLS_HACK))
21 #include <pthread.h>
22 #endif
23 
24 #define NTL_THREAD_LOCAL thread_local
25 
26 #ifdef __GNUC__
27 #define NTL_CHEAP_THREAD_LOCAL __thread
28 #else
29 #define NTL_CHEAP_THREAD_LOCAL thread_local
30 #endif
31 
32 
33 #define NTL_DETAILS_PTHREAD details_pthread
34 
35 
36 #if (defined(NTL_THREADS) && defined(NTL_TLS_HACK))
37 
38 namespace details_pthread {
39 
40 
41 struct Node {
42    Node *next;
43 
Nodedetails_pthread::Node44    Node() : next(0) { }
~Nodedetails_pthread::Node45    virtual ~Node() { }
46 };
47 
48 template<class T>
49 struct DerivedNode : Node {
50    T t;
51 
52    template<class... Args>
DerivedNodedetails_pthread::DerivedNode53    DerivedNode(Args&&... args) : t(std::forward<Args>(args)...) { }
54 };
55 
56 inline void
delete_node(Node * p)57 delete_node(Node *p) noexcept { delete p;  }
58 // an exception here would likely lead to a complete mess...
59 // the noexcept specification should force an immediate termination
60 
61 inline void
delete_list(void * vp)62 delete_list(void *vp)
63 {
64    Node *p = (Node *) vp;
65    while (p) {
66       Node *tmp = p;
67       p = p->next;
68       delete_node(tmp);
69    }
70 }
71 
72 
73 using namespace std;
74 // I'm not sure if pthread stuff might be placed in namespace std
75 
76 struct key_wrapper {
77    pthread_key_t key;
78 
key_wrapperdetails_pthread::key_wrapper79    key_wrapper(void (*destructor)(void*))
80    {
81       if (pthread_key_create(&key, destructor))
82          ResourceError("pthread_key_create failed");
83    }
84 };
85 
86 
87 inline void
push_node(Node * p)88 push_node(Node *p)
89 // this pushes a new node to the front to the list
90 // of objects that need to be deleted
91 {
92    if (!p) MemoryError();
93 
94    static key_wrapper wkey(delete_list);
95    // This relies on C++11 thread-safe static initialization.
96    // It also relies on the guarantee that there is just one
97    // global key (this requirement is only needed to
98    // limit the number of keys, not for correctness).
99 
100    p->next = (Node *) pthread_getspecific(wkey.key);
101 
102    if (pthread_setspecific(wkey.key, p)) {
103       delete_node(p);
104       ResourceError("pthread_setspecific failed");
105    }
106 }
107 
108 }
109 
110 
111 #define NTL_TLS_LOCAL_INIT(type, var, init)  \
112    static NTL_CHEAP_THREAD_LOCAL NTL_DETAILS_PTHREAD::DerivedNode<type> *_ntl_hidden_variable_tls_local_ptr_ ## var = 0;  \
113    NTL_DETAILS_PTHREAD::DerivedNode<type> *_ntl_hidden_variable_tls_local_ptr1_ ## var = _ntl_hidden_variable_tls_local_ptr_ ## var;  \
114    if (!_ntl_hidden_variable_tls_local_ptr1_ ## var) {  \
115       NTL_DETAILS_PTHREAD::DerivedNode<type> *_ntl_hidden_variable_tls_local_ptr2_ ## var = NTL_NEW_OP NTL_DETAILS_PTHREAD::DerivedNode<type> init;  \
116       NTL_DETAILS_PTHREAD::push_node(_ntl_hidden_variable_tls_local_ptr2_ ## var); \
117       _ntl_hidden_variable_tls_local_ptr1_ ## var = _ntl_hidden_variable_tls_local_ptr2_ ## var;  \
118       _ntl_hidden_variable_tls_local_ptr_ ## var = _ntl_hidden_variable_tls_local_ptr1_ ## var;  \
119    }  \
120    type &var = _ntl_hidden_variable_tls_local_ptr1_ ## var->t  \
121 
122 
123 
124 #else
125 
126 
127 // NOTE: this definition of NTL_TLS_LOCAL_INIT ensures that var names
128 // a local reference, regardless of the implementation
129 #define NTL_TLS_LOCAL_INIT(type,var,init) \
130     static NTL_THREAD_LOCAL type _ntl_hidden_variable_tls_local ## var init; \
131     type &var = _ntl_hidden_variable_tls_local ## var
132 
133 
134 
135 
136 #endif
137 
138 #define NTL_EMPTY_ARG
139 #define NTL_TLS_LOCAL(type,var) NTL_TLS_LOCAL_INIT(type,var,NTL_EMPTY_ARG)
140 
141 #define NTL_TLS_GLOBAL_DECL_INIT(type,var,init)  \
142    typedef type _ntl_hidden_typedef_tls_access_ ## var;  \
143    static inline  \
144    type& _ntl_hidden_function_tls_access_ ## var() {  \
145       NTL_TLS_LOCAL_INIT(type,var,init);  \
146       return var;  \
147    }  \
148 
149 
150 #define NTL_TLS_GLOBAL_DECL(type,var) NTL_TLS_GLOBAL_DECL_INIT(type,var,NTL_EMPTY_ARG)
151 
152 #define NTL_TLS_GLOBAL_ACCESS(var) \
153 _ntl_hidden_typedef_tls_access_ ## var & var = _ntl_hidden_function_tls_access_ ## var()
154 
155 
156 //=======================
157 
158 std::atomic_long count_con(0);
159 std::atomic_long count_des(0);
160 std::atomic_long count1(0);
161 
162 struct X {
163    long d;
164 
XX165    X() { d = count1++; count_con++; }
~XX166    ~X() { count_des++; }
167 };
168 
NTL_TLS_GLOBAL_DECL(X,x)169 NTL_TLS_GLOBAL_DECL(X,x)
170 
171 void task(long *v)
172 {
173    NTL_TLS_GLOBAL_ACCESS(x);
174    *v = x.d;
175 }
176 
177 
178 #define MIN(a,b) ((a)<(b)?(a):(b))
179 #define MAX(a,b) ((a)>(b)?(a):(b))
180 
main()181 int main()
182 {
183    long v1, v2, v3;
184    std::thread t1(task, &v1);
185    std::thread t2(task, &v2);
186    std::thread t3(task, &v3);
187 
188    t1.join();
189    t2.join();
190    t3.join();
191 
192    //std::cout << count_con << "\n";
193    //std::cout << count_des << "\n";
194    //std::cout << v1 << " " << v2 << " " << v3 << "\n";
195 
196    long s1, s2, s3;
197    s1 = MIN(MIN(v1,v2),v3);
198    s3 = MAX(MAX(v1,v2),v3);
199    s2 = v1+v2+v3-s1-s3;
200 
201    if (count_con != 3 || count_des != 3 || s1 != 0 || s2 != 1 || s3 != 2) {
202       return -1;
203    }
204    return 0;
205 }
206