handle TLS mostly in glibc, not parlib
[akaros.git] / user / parlib / include / vcore.h
1 #ifndef _VCORE_H
2 #define _VCORE_H
3
4 #ifdef __cplusplus
5 extern "C" {
6 #endif
7
8 #include <arch/vcore.h>
9 #include <arch/atomic.h>
10 #include <sys/param.h>
11 #include <string.h>
12
13 /*****************************************************************************/
14 /* TODO: This is a complete hack, but necessary for vcore stuff to work for now
15  * The issue is that exit sometimes calls sys_yield(), and we can't recover from
16  * that properly under our vcore model (we shouldn't though).  We really need to
17  * rethink what sys_yield 'should' do when in multicore mode, or else come up 
18  * with a different syscall entirely. */
19 #include <stdlib.h>
20 #include <unistd.h>
21 #undef exit
22 #define exit(status) ros_syscall(SYS_proc_destroy, getpid(), status, 0, 0, 0, 0)
23 /*****************************************************************************/
24
25 #define LOG2_MAX_VCORES 6
26 #define MAX_VCORES (1 << LOG2_MAX_VCORES)
27
28 #define TRANSITION_STACK_PAGES 2
29 #define TRANSITION_STACK_SIZE (TRANSITION_STACK_PAGES*PGSIZE)
30
31 /* Defined by glibc; Must be implemented by a user level threading library */
32 extern void vcore_entry();
33 /* Declared in glibc's start.c */
34 extern __thread bool __vcore_context;
35 extern __thread int __vcoreid;
36
37 /* Vcore API functions */
38 static inline size_t max_vcores(void);
39 static inline size_t num_vcores(void);
40 static inline int vcore_id(void);
41 static inline bool in_vcore_context(void);
42 static inline bool in_multi_mode(void);
43 static inline void __enable_notifs(uint32_t vcoreid);
44 static inline void __disable_notifs(uint32_t vcoreid);
45 static inline bool notif_is_enabled(uint32_t vcoreid);
46 static inline bool vcore_is_mapped(uint32_t vcoreid);
47 static inline bool vcore_is_preempted(uint32_t vcoreid);
48 static inline struct preempt_data *vcpd_of(uint32_t vcoreid);
49 static inline bool preempt_is_pending(uint32_t vcoreid);
50 static inline bool __preempt_is_pending(uint32_t vcoreid);
51 int vcore_init(void);
52 void vcore_event_init(void);
53 void vcore_change_to_m(void);
54 int vcore_request(long nr_new_vcores);
55 void vcore_yield(bool preempt_pending);
56 bool clear_notif_pending(uint32_t vcoreid);
57 void enable_notifs(uint32_t vcoreid);
58 void disable_notifs(uint32_t vcoreid);
59 void vcore_idle(void);
60 void ensure_vcore_runs(uint32_t vcoreid);
61 void cpu_relax_vc(uint32_t vcoreid);
62
63 /* Static inlines */
64 static inline size_t max_vcores(void)
65 {
66         return MIN(__procinfo.max_vcores, MAX_VCORES);
67 }
68
69 static inline size_t num_vcores(void)
70 {
71         return __procinfo.num_vcores;
72 }
73
74 static inline int vcore_id(void)
75 {
76         return __vcoreid;
77 }
78
79 static inline bool in_vcore_context(void)
80 {
81         return __vcore_context;
82 }
83
84 static inline bool in_multi_mode(void)
85 {
86         return __procinfo.is_mcp;
87 }
88
89 /* Only call this if you know what you are doing. */
90 static inline void __enable_notifs(uint32_t vcoreid)
91 {
92         vcpd_of(vcoreid)->notif_disabled = FALSE;
93 }
94
95 static inline void __disable_notifs(uint32_t vcoreid)
96 {
97         vcpd_of(vcoreid)->notif_disabled = TRUE;
98 }
99
100 static inline bool notif_is_enabled(uint32_t vcoreid)
101 {
102         return !vcpd_of(vcoreid)->notif_disabled;
103 }
104
105 static inline bool vcore_is_mapped(uint32_t vcoreid)
106 {
107         return __procinfo.vcoremap[vcoreid].valid;
108 }
109
110 /* We could also check for VC_K_LOCK, but that's a bit much. */
111 static inline bool vcore_is_preempted(uint32_t vcoreid)
112 {
113         struct preempt_data *vcpd = vcpd_of(vcoreid);
114         return atomic_read(&vcpd->flags) & VC_PREEMPTED;
115 }
116
117 static inline struct preempt_data *vcpd_of(uint32_t vcoreid)
118 {
119         return &__procdata.vcore_preempt_data[vcoreid];
120 }
121
122 /* Uthread's can call this in case they care if a preemption is coming.  If a
123  * preempt is incoming, this will return TRUE, if you are in uthread context.  A
124  * reasonable response for a uthread is to yield, and vcore_entry will deal with
125  * the preempt pending.
126  *
127  * If you call this from vcore context, it will do nothing.  In general, it's
128  * not safe to just yield (or do whatever you plan on doing) from arbitrary
129  * places in vcore context.  So we just lie about PP. */
130 static inline bool preempt_is_pending(uint32_t vcoreid)
131 {
132         if (in_vcore_context())
133                 return FALSE;
134         return __preempt_is_pending(vcoreid);
135 }
136
137 static inline bool __preempt_is_pending(uint32_t vcoreid)
138 {
139         return __procinfo.vcoremap[vcoreid].preempt_pending;
140 }
141
142
143 #ifndef __PIC__
144
145 #define begin_safe_access_tls_vars()
146
147 #define end_safe_access_tls_vars()
148
149 #else
150
151 #include <features.h>
152 #if __GNUC_PREREQ(4,4)
153
154 #define begin_safe_access_tls_vars()                                    \
155   void __attribute__((noinline, optimize("O0")))                        \
156   safe_access_tls_var_internal() {                                      \
157     asm("");                                                            \
158
159 #define end_safe_access_tls_vars()                                      \
160   } safe_access_tls_var_internal();                                     \
161
162 #else
163
164 #define begin_safe_access_tls_vars()                                                   \
165   printf("ERROR: For PIC you must be using gcc 4.4 or above for tls support!\n");      \
166   printf("ERROR: As a quick fix, try recompiling your application with -static...\n"); \
167   exit(2);
168
169 #define end_safe_access_tls_vars()                                         \
170   printf("Will never be called because we abort above!");                  \
171   exit(2);
172
173 #endif //__GNUC_PREREQ
174 #endif // __PIC__
175
176 #define begin_access_tls_vars(tls_desc)                               \
177 {                                                                     \
178         uthread_t *caller;                                            \
179         int invcore = in_vcore_context();                             \
180         if(!invcore) {                                                \
181           caller = current_uthread;                                   \
182           assert(caller);                                             \
183           caller->flags |= UTHREAD_DONT_MIGRATE;                      \
184         }                                                             \
185                                                                       \
186         cmb();                                                        \
187         int vcoreid = vcore_id();                                     \
188         void *temp_tls_desc = get_tls_desc(vcoreid);                  \
189                                                                       \
190         if(!invcore)                                                  \
191           disable_notifs(vcoreid);                                    \
192                                                                       \
193         set_tls_desc(tls_desc, vcoreid);                              \
194         begin_safe_access_tls_vars();
195
196 #define end_access_tls_vars()                                         \
197         end_safe_access_tls_vars();                                   \
198         set_tls_desc(temp_tls_desc, vcoreid);                         \
199                                                                       \
200         if(!invcore) {                                                \
201           caller->flags &= ~UTHREAD_DONT_MIGRATE;                     \
202           cmb();                                                      \
203           if(in_multi_mode())                                         \
204             enable_notifs(vcoreid);                                   \
205         }                                                             \
206         cmb();                                                        \
207 }
208
209 #define safe_set_tls_var(name, val)                                   \
210 ({                                                                    \
211         begin_safe_access_tls_vars();                                 \
212         name = val;                                                   \
213         end_safe_access_tls_vars();                                   \
214 })
215
216 #define safe_get_tls_var(name)                                        \
217 ({                                                                    \
218         typeof(name) __val;                                           \
219         begin_safe_access_tls_vars();                                 \
220         __val = name;                                                 \
221         end_safe_access_tls_vars();                                   \
222         __val;                                                        \
223 })
224
225 #define vcore_set_tls_var(name, val)                                     \
226 {                                                                        \
227       extern void** vcore_thread_control_blocks;                         \
228       typeof(val) __val = val;                                           \
229       begin_access_tls_vars(vcore_thread_control_blocks[vcoreid]);       \
230       name = __val;                                                      \
231       end_access_tls_vars();                                             \
232 }
233
234 #define vcore_get_tls_var(name)                                 \
235 ({                                                              \
236       typeof(name) val;                                         \
237       begin_access_tls_vars(vcore_tls_descs[vcoreid]);          \
238       val = name;                                               \
239       end_access_tls_vars();                                    \
240       val;                                                      \
241 })
242
243 #ifdef __cplusplus
244 }
245 #endif
246
247 #endif