1 // Copyright 2012-2013 Intel Corporation
2 //
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // - Redistributions of source code must retain the above copyright notice, this
9 // list of conditions and the following disclaimer.
10 //
11 // - Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26 #include <assert.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include "threads.h"
32
33 #include "wcore_error.h"
34 #include "wcore_tinfo.h"
35
36 static once_flag wcore_tinfo_once = ONCE_FLAG_INIT;
37 static tss_t wcore_tinfo_key;
38
39 #ifdef WAFFLE_HAS_TLS
40 /// @brief Thread-local storage for all of Waffle.
41 ///
42 /// For documentation on the tls_model, see the GCC manual [1] and
43 /// Drepper [2].
44 ///
45 /// [1] GCC 4.7.0 Manual, 6.59 Thread-Local Storage.
46 /// http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Thread_002dLocal.html
47 ///
48 /// [2] Ulrich Drepper. "Elf Handling For Thread Local Storage".
49 /// http://people.redhat.com/drepper/tls.pdf
50 static __thread struct wcore_tinfo wcore_tinfo
51 #ifdef WAFFLE_HAS_TLS_MODEL_INITIAL_EXEC
52 __attribute__((tls_model("initial-exec")))
53 #endif
54 ;
55 #endif // WAFFLE_HAS_TLS
56
57 #if defined(__GNUC__)
58 #define NORETURN __attribute__((noreturn))
59 #elif defined(_MSC_VER)
60 #define NORETURN __declspec(noreturn)
61 #else
62 #define NORETURN
63 #endif
64
65 static void NORETURN
wcore_tinfo_abort_init(void)66 wcore_tinfo_abort_init(void)
67 {
68 printf("waffle: fatal-error: failed to initialize thread local info\n");
69 abort();
70 }
71
72 static void
wcore_tinfo_key_dtor(void * args)73 wcore_tinfo_key_dtor(void *args)
74 {
75 struct wcore_tinfo *tinfo = args;
76 if (!tinfo)
77 return;
78
79 wcore_error_tinfo_destroy(tinfo->error);
80
81 #ifndef WAFFLE_HAS_TLS
82 free(tinfo);
83 #endif
84 }
85
86 static void
wcore_tinfo_key_create(void)87 wcore_tinfo_key_create(void)
88 {
89 int err;
90
91 err = tss_create(&wcore_tinfo_key, wcore_tinfo_key_dtor);
92 if (err)
93 wcore_tinfo_abort_init();
94 }
95
96 static void
wcore_tinfo_init(struct wcore_tinfo * tinfo)97 wcore_tinfo_init(struct wcore_tinfo *tinfo)
98 {
99 int err;
100
101 if (tinfo->is_init)
102 return;
103
104 tinfo->error = wcore_error_tinfo_create();
105 if (!tinfo->error)
106 wcore_tinfo_abort_init();
107
108 tinfo->current_display = NULL;
109 tinfo->current_window = NULL;
110 tinfo->current_context = NULL;
111
112 tinfo->is_init = true;
113
114 #ifdef WAFFLE_HAS_TLS
115 // Register tinfo with the key's destructor to prevent memory leaks at
116 // thread exit. The destructor must be registered once per process, but
117 // each instance of tinfo must be registered individually. The key's data
118 // is never retrieved because use the key only to register tinfo for
119 // destruction.
120
121 // With C11 threads call_once "can never fail"...
122 // http://open-std.org/twiki/pub/WG14/DefectReports/n1654.htm
123 call_once(&wcore_tinfo_once, wcore_tinfo_key_create);
124 #endif
125
126 err = tss_set(wcore_tinfo_key, tinfo);
127 if (err)
128 wcore_tinfo_abort_init();
129 }
130
131 struct wcore_tinfo*
wcore_tinfo_get(void)132 wcore_tinfo_get(void)
133 {
134 #ifdef WAFFLE_HAS_TLS
135 wcore_tinfo_init(&wcore_tinfo);
136 return &wcore_tinfo;
137 #else
138 struct wcore_tinfo *tinfo;
139
140 // With C11 threads call_once "can never fail"...
141 // http://open-std.org/twiki/pub/WG14/DefectReports/n1654.htm
142 call_once(&wcore_tinfo_once, wcore_tinfo_key_create);
143
144 tinfo = tss_get(wcore_tinfo_key);
145 if (tinfo)
146 return tinfo;
147
148 tinfo = calloc(1, sizeof(*tinfo));
149 if (!tinfo)
150 wcore_tinfo_abort_init();
151
152 wcore_tinfo_init(tinfo);
153 return tinfo;
154 #endif
155 }
156