306d133fa45018b8a43b0d51c5ca03297051c78a
[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 #include "interrupt.h"
12 #ifdef LISP_FEATURE_GENCGC
13 #include "gencgc-alloc-region.h"
14 #else
15 struct alloc_region { };
16 #endif
17 #include "genesis/symbol.h"
18 #include "genesis/static-symbols.h"
19 #include "genesis/thread.h"
20 #include "genesis/fdefn.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 #endif
58
59 extern int kill_safely(os_thread_t os_thread, int signal);
60
61 #define THREAD_SLOT_OFFSET_WORDS(c) \
62  (offsetof(struct thread,c)/(sizeof (struct thread *)))
63
64 union per_thread_data {
65     struct thread thread;
66     lispobj dynamic_values[1];  /* actually more like 4000 or so */
67 };
68
69 extern struct thread *all_threads;
70 extern int dynamic_values_bytes;
71
72 #if defined(LISP_FEATURE_DARWIN)
73 #define CONTROL_STACK_ALIGNMENT_BYTES 8192 /* darwin wants page-aligned stacks */
74 #define THREAD_ALIGNMENT_BYTES CONTROL_STACK_ALIGNMENT_BYTES
75 #else
76 #define THREAD_ALIGNMENT_BYTES BACKEND_PAGE_BYTES
77 #define CONTROL_STACK_ALIGNMENT_BYTES 16
78 #endif
79
80
81 #ifdef LISP_FEATURE_SB_THREAD
82 #define for_each_thread(th) for(th=all_threads;th;th=th->next)
83 #else
84 /* there's some possibility a SSC could notice this never actually
85  * loops  */
86 #define for_each_thread(th) for(th=all_threads;th;th=0)
87 #endif
88
89 static inline lispobj *
90 SymbolValueAddress(u64 tagged_symbol_pointer, void *thread)
91 {
92     struct symbol *sym= (struct symbol *)
93         (pointer_sized_uint_t)(tagged_symbol_pointer-OTHER_POINTER_LOWTAG);
94 #ifdef LISP_FEATURE_SB_THREAD
95     if(thread && sym->tls_index) {
96         lispobj *r = &(((union per_thread_data *)thread)
97                        ->dynamic_values[fixnum_value(sym->tls_index)]);
98         if((*r)!=NO_TLS_VALUE_MARKER_WIDETAG) return r;
99     }
100 #endif
101     return &sym->value;
102 }
103
104 static inline lispobj
105 SymbolValue(u64 tagged_symbol_pointer, void *thread)
106 {
107     struct symbol *sym= (struct symbol *)
108         (pointer_sized_uint_t)(tagged_symbol_pointer-OTHER_POINTER_LOWTAG);
109 #ifdef LISP_FEATURE_SB_THREAD
110     if(thread && sym->tls_index) {
111         lispobj r=
112             ((union per_thread_data *)thread)
113             ->dynamic_values[fixnum_value(sym->tls_index)];
114         if(r!=NO_TLS_VALUE_MARKER_WIDETAG) return r;
115     }
116 #endif
117     return sym->value;
118 }
119
120 static inline lispobj
121 SymbolTlValue(u64 tagged_symbol_pointer, void *thread)
122 {
123     struct symbol *sym= (struct symbol *)
124         (pointer_sized_uint_t)(tagged_symbol_pointer-OTHER_POINTER_LOWTAG);
125 #ifdef LISP_FEATURE_SB_THREAD
126     return ((union per_thread_data *)thread)
127         ->dynamic_values[fixnum_value(sym->tls_index)];
128 #else
129     return sym->value;
130 #endif
131 }
132
133 static inline void
134 SetSymbolValue(u64 tagged_symbol_pointer,lispobj val, void *thread)
135 {
136     struct symbol *sym= (struct symbol *)
137         (pointer_sized_uint_t)(tagged_symbol_pointer-OTHER_POINTER_LOWTAG);
138 #ifdef LISP_FEATURE_SB_THREAD
139     if(thread && sym->tls_index) {
140         lispobj *pr= &(((union per_thread_data *)thread)
141                        ->dynamic_values[fixnum_value(sym->tls_index)]);
142         if(*pr!=NO_TLS_VALUE_MARKER_WIDETAG) {
143             *pr=val;
144             return;
145         }
146     }
147 #endif
148     sym->value = val;
149 }
150
151 static inline void
152 SetTlSymbolValue(u64 tagged_symbol_pointer,lispobj val, void *thread)
153 {
154 #ifdef LISP_FEATURE_SB_THREAD
155     struct symbol *sym= (struct symbol *)
156         (pointer_sized_uint_t)(tagged_symbol_pointer-OTHER_POINTER_LOWTAG);
157     ((union per_thread_data *)thread)
158         ->dynamic_values[fixnum_value(sym->tls_index)]
159         =val;
160 #else
161     SetSymbolValue(tagged_symbol_pointer,val,thread) ;
162 #endif
163 }
164
165 /* This only works for static symbols. */
166 static inline lispobj
167 StaticSymbolFunction(lispobj sym)
168 {
169     return ((struct fdefn *)native_pointer(SymbolValue(sym, 0)))->fun;
170 }
171
172 static inline
173 os_context_t *get_interrupt_context_for_thread(struct thread *th)
174 {
175     return th->interrupt_contexts
176         [fixnum_value(SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX,th)-1)];
177 }
178
179 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_GCC_TLS)
180 extern __thread struct thread *current_thread;
181 #endif
182
183 /* This is clearly per-arch and possibly even per-OS code, but we can't
184  * put it somewhere sensible like x86-linux-os.c because it needs too
185  * much stuff like struct thread and all_threads to be defined, which
186  * usually aren't by that time.  So, it's here instead.  Sorry */
187
188 static inline struct thread *arch_os_get_current_thread(void)
189 {
190 #if defined(LISP_FEATURE_SB_THREAD)
191 #if defined(LISP_FEATURE_X86)
192     register struct thread *me=0;
193     if(all_threads) {
194 #if defined(LISP_FEATURE_DARWIN) && defined(LISP_FEATURE_RESTORE_FS_SEGMENT_REGISTER_FROM_TLS)
195         sel_t sel;
196         struct thread *th = pthread_getspecific(specials);
197         sel.index = th->tls_cookie;
198         sel.rpl = USER_PRIV;
199         sel.ti = SEL_LDT;
200         __asm__ __volatile__ ("movw %w0, %%fs" : : "r"(sel));
201 #elif defined(LISP_FEATURE_FREEBSD)
202 #ifdef LISP_FEATURE_GCC_TLS
203         struct thread *th = current_thread;
204 #else
205         struct thread *th = pthread_getspecific(specials);
206 #endif
207 #ifdef LISP_FEATURE_RESTORE_TLS_SEGMENT_REGISTER_FROM_TLS
208         unsigned int sel = LSEL(th->tls_cookie, SEL_UPL);
209         unsigned int fs = rfs();
210
211         /* Load FS only if it's necessary.  Modifying a selector
212          * causes privilege checking and it takes long time. */
213         if (fs != sel)
214             load_fs(sel);
215 #endif
216         return th;
217 #endif
218         __asm__ __volatile__ ("movl %%fs:%c1,%0" : "=r" (me)
219                  : "i" (offsetof (struct thread,this)));
220     }
221     return me;
222 #else
223 #ifdef LISP_FEATURE_GCC_TLS
224     return current_thread;
225 #else
226     return pthread_getspecific(specials);
227 #endif
228 #endif /* x86 */
229 #else
230      return all_threads;
231 #endif
232 }
233
234 #if defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER)
235 #define THREAD_STRUCT_TO_EXCEPTION_PORT(th) ((mach_port_t) th)
236 #define EXCEPTION_PORT_TO_THREAD_STRUCT(th) ((struct thread *) th)
237 #endif
238
239 extern void create_initial_thread(lispobj);
240
241 #endif /* _INCLUDE_THREAD_H_ */