Redefine symbol TLS slot indices.
[sbcl.git] / src / runtime / thread.h
1 #if !defined(_INCLUDE_THREAD_H_)
2 #define _INCLUDE_THREAD_H_
3
4 #include <sys/types.h>
5 #include <unistd.h>
6 #include <stddef.h>
7 #include "sbcl.h"
8 #include "globals.h"
9 #include "runtime.h"
10 #include "os.h"
11 #ifdef LISP_FEATURE_GENCGC
12 #include "gencgc-alloc-region.h"
13 #else
14 struct alloc_region { };
15 #endif
16 #include "genesis/symbol.h"
17 #include "genesis/static-symbols.h"
18 #include "genesis/thread.h"
19 #include "genesis/fdefn.h"
20 #include "interrupt.h"
21
22 #define STATE_RUNNING (make_fixnum(1))
23 #define STATE_SUSPENDED (make_fixnum(2))
24 #define STATE_DEAD (make_fixnum(3))
25
26 #ifdef LISP_FEATURE_SB_THREAD
27
28 /* Only access thread state with blockables blocked. */
29 static inline lispobj
30 thread_state(struct thread *thread)
31 {
32     lispobj state;
33     pthread_mutex_lock(thread->state_lock);
34     state = thread->state;
35     pthread_mutex_unlock(thread->state_lock);
36     return state;
37 }
38
39 static inline void
40 set_thread_state(struct thread *thread, lispobj state)
41 {
42     pthread_mutex_lock(thread->state_lock);
43     thread->state = state;
44     pthread_cond_broadcast(thread->state_cond);
45     pthread_mutex_unlock(thread->state_lock);
46 }
47
48 static inline void
49 wait_for_thread_state_change(struct thread *thread, lispobj state)
50 {
51     pthread_mutex_lock(thread->state_lock);
52     while (thread->state == state)
53         pthread_cond_wait(thread->state_cond, thread->state_lock);
54     pthread_mutex_unlock(thread->state_lock);
55 }
56
57 extern pthread_key_t lisp_thread;
58 #endif
59
60 extern int kill_safely(os_thread_t os_thread, int signal);
61
62 #define THREAD_SLOT_OFFSET_WORDS(c) \
63  (offsetof(struct thread,c)/(sizeof (struct thread *)))
64
65 union per_thread_data {
66     struct thread thread;
67     lispobj dynamic_values[1];  /* actually more like 4000 or so */
68 };
69
70 extern struct thread *all_threads;
71 extern int dynamic_values_bytes;
72
73 #if defined(LISP_FEATURE_DARWIN)
74 #define CONTROL_STACK_ALIGNMENT_BYTES 8192 /* darwin wants page-aligned stacks */
75 #define THREAD_ALIGNMENT_BYTES CONTROL_STACK_ALIGNMENT_BYTES
76 #else
77 #define THREAD_ALIGNMENT_BYTES BACKEND_PAGE_BYTES
78 #define CONTROL_STACK_ALIGNMENT_BYTES 16
79 #endif
80
81
82 #ifdef LISP_FEATURE_SB_THREAD
83 #define for_each_thread(th) for(th=all_threads;th;th=th->next)
84 #else
85 /* there's some possibility a SSC could notice this never actually
86  * loops  */
87 #define for_each_thread(th) for(th=all_threads;th;th=0)
88 #endif
89
90 static inline lispobj *
91 SymbolValueAddress(u64 tagged_symbol_pointer, void *thread)
92 {
93     struct symbol *sym= (struct symbol *)
94         (pointer_sized_uint_t)(tagged_symbol_pointer-OTHER_POINTER_LOWTAG);
95 #ifdef LISP_FEATURE_SB_THREAD
96     if(thread && sym->tls_index) {
97         lispobj *r = &(((union per_thread_data *)thread)
98                        ->dynamic_values[(sym->tls_index) >> WORD_SHIFT]);
99         if((*r)!=NO_TLS_VALUE_MARKER_WIDETAG) return r;
100     }
101 #endif
102     return &sym->value;
103 }
104
105 static inline lispobj
106 SymbolValue(u64 tagged_symbol_pointer, void *thread)
107 {
108     struct symbol *sym= (struct symbol *)
109         (pointer_sized_uint_t)(tagged_symbol_pointer-OTHER_POINTER_LOWTAG);
110 #ifdef LISP_FEATURE_SB_THREAD
111     if(thread && sym->tls_index) {
112         lispobj r=
113             ((union per_thread_data *)thread)
114             ->dynamic_values[(sym->tls_index) >> WORD_SHIFT];
115         if(r!=NO_TLS_VALUE_MARKER_WIDETAG) return r;
116     }
117 #endif
118     return sym->value;
119 }
120
121 static inline lispobj
122 SymbolTlValue(u64 tagged_symbol_pointer, void *thread)
123 {
124     struct symbol *sym= (struct symbol *)
125         (pointer_sized_uint_t)(tagged_symbol_pointer-OTHER_POINTER_LOWTAG);
126 #ifdef LISP_FEATURE_SB_THREAD
127     return ((union per_thread_data *)thread)
128         ->dynamic_values[(sym->tls_index) >> WORD_SHIFT];
129 #else
130     return sym->value;
131 #endif
132 }
133
134 static inline void
135 SetSymbolValue(u64 tagged_symbol_pointer,lispobj val, void *thread)
136 {
137     struct symbol *sym= (struct symbol *)
138         (pointer_sized_uint_t)(tagged_symbol_pointer-OTHER_POINTER_LOWTAG);
139 #ifdef LISP_FEATURE_SB_THREAD
140     if(thread && sym->tls_index) {
141         lispobj *pr= &(((union per_thread_data *)thread)
142                        ->dynamic_values[(sym->tls_index) >> WORD_SHIFT]);
143         if(*pr!=NO_TLS_VALUE_MARKER_WIDETAG) {
144             *pr=val;
145             return;
146         }
147     }
148 #endif
149     sym->value = val;
150 }
151
152 static inline void
153 SetTlSymbolValue(u64 tagged_symbol_pointer,lispobj val, void *thread)
154 {
155 #ifdef LISP_FEATURE_SB_THREAD
156     struct symbol *sym= (struct symbol *)
157         (pointer_sized_uint_t)(tagged_symbol_pointer-OTHER_POINTER_LOWTAG);
158     ((union per_thread_data *)thread)
159         ->dynamic_values[(sym->tls_index) >> WORD_SHIFT]
160         =val;
161 #else
162     SetSymbolValue(tagged_symbol_pointer,val,thread) ;
163 #endif
164 }
165
166 /* This only works for static symbols. */
167 static inline lispobj
168 StaticSymbolFunction(lispobj sym)
169 {
170     return ((struct fdefn *)native_pointer(SymbolValue(sym, 0)))->fun;
171 }
172
173 /* These are for use during GC, on the current thread, or on prenatal
174  * threads only. */
175 #if defined(LISP_FEATURE_SB_THREAD)
176 #define get_binding_stack_pointer(thread)       \
177     ((thread)->binding_stack_pointer)
178 #define set_binding_stack_pointer(thread,value) \
179     ((thread)->binding_stack_pointer = (lispobj *)(value))
180 #define access_control_stack_pointer(thread) \
181     ((thread)->control_stack_pointer)
182 #  if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64)
183 #define access_control_frame_pointer(thread) \
184     ((thread)->control_frame_pointer)
185 #  endif
186 #elif defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)
187 #define get_binding_stack_pointer(thread)       \
188     SymbolValue(BINDING_STACK_POINTER, thread)
189 #define set_binding_stack_pointer(thread,value) \
190     SetSymbolValue(BINDING_STACK_POINTER, (lispobj)(value), thread)
191 #define access_control_stack_pointer(thread)    \
192     (current_control_stack_pointer)
193 #else
194 #define get_binding_stack_pointer(thread)       \
195     (current_binding_stack_pointer)
196 #define set_binding_stack_pointer(thread,value) \
197     (current_binding_stack_pointer = (lispobj *)(value))
198 #define access_control_stack_pointer(thread) \
199     (current_control_stack_pointer)
200 #define access_control_frame_pointer(thread) \
201     (current_control_frame_pointer)
202 #endif
203
204 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_GCC_TLS)
205 extern __thread struct thread *current_thread;
206 #endif
207
208 /* This is clearly per-arch and possibly even per-OS code, but we can't
209  * put it somewhere sensible like x86-linux-os.c because it needs too
210  * much stuff like struct thread and all_threads to be defined, which
211  * usually aren't by that time.  So, it's here instead.  Sorry */
212
213 static inline struct thread *arch_os_get_current_thread(void)
214 {
215 #if defined(LISP_FEATURE_SB_THREAD)
216 #if defined(LISP_FEATURE_X86)
217     register struct thread *me=0;
218     if(all_threads) {
219 #if defined(LISP_FEATURE_DARWIN) && defined(LISP_FEATURE_RESTORE_FS_SEGMENT_REGISTER_FROM_TLS)
220         sel_t sel;
221         struct thread *th = pthread_getspecific(specials);
222         sel.index = th->tls_cookie;
223         sel.rpl = USER_PRIV;
224         sel.ti = SEL_LDT;
225         __asm__ __volatile__ ("movw %w0, %%fs" : : "r"(sel));
226 #elif defined(LISP_FEATURE_FREEBSD)
227 #ifdef LISP_FEATURE_GCC_TLS
228         struct thread *th = current_thread;
229 #else
230         struct thread *th = pthread_getspecific(specials);
231 #endif
232 #ifdef LISP_FEATURE_RESTORE_TLS_SEGMENT_REGISTER_FROM_TLS
233         unsigned int sel = LSEL(th->tls_cookie, SEL_UPL);
234         unsigned int fs = rfs();
235
236         /* Load FS only if it's necessary.  Modifying a selector
237          * causes privilege checking and it takes long time. */
238         if (fs != sel)
239             load_fs(sel);
240 #endif
241         return th;
242 #endif
243         __asm__ __volatile__ ("movl %%fs:%c1,%0" : "=r" (me)
244                  : "i" (offsetof (struct thread,this)));
245     }
246     return me;
247 #else
248 #ifdef LISP_FEATURE_GCC_TLS
249     return current_thread;
250 #else
251     return pthread_getspecific(specials);
252 #endif
253 #endif /* x86 */
254 #else
255      return all_threads;
256 #endif
257 }
258
259 #if defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER)
260 #define THREAD_STRUCT_TO_EXCEPTION_PORT(th) ((mach_port_t) th)
261 #define EXCEPTION_PORT_TO_THREAD_STRUCT(th) ((struct thread *) th)
262 #endif
263
264 extern void create_initial_thread(lispobj);
265
266 #endif /* _INCLUDE_THREAD_H_ */