profiling: simple test
[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) _exit(status)
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 /* Defined in glibc's start.c */
34 extern __thread bool __vcore_context;
35 extern __thread int __vcoreid;
36 /* Defined in vcore.c */
37 extern __thread struct syscall __vcore_one_sysc;        /* see sys_change_vcore */
38
39 /* Vcore API functions */
40 static inline uint32_t max_vcores(void);
41 static inline uint32_t num_vcores(void);
42 static inline int vcore_id(void);
43 static inline bool in_vcore_context(void);
44 static inline bool in_multi_mode(void);
45 static inline void __enable_notifs(uint32_t vcoreid);
46 static inline void __disable_notifs(uint32_t vcoreid);
47 static inline bool notif_is_enabled(uint32_t vcoreid);
48 static inline bool vcore_is_mapped(uint32_t vcoreid);
49 static inline bool vcore_is_preempted(uint32_t vcoreid);
50 static inline struct preempt_data *vcpd_of(uint32_t vcoreid);
51 static inline bool preempt_is_pending(uint32_t vcoreid);
52 static inline bool __preempt_is_pending(uint32_t vcoreid);
53 static inline void *get_vcpd_tls_desc(uint32_t vcoreid);
54 static inline void set_vcpd_tls_desc(uint32_t vcoreid, void *tls_desc);
55 void vcore_init(void);
56 void vcore_event_init(void);
57 void vcore_change_to_m(void);
58 int vcore_request(long nr_new_vcores);
59 void vcore_yield(bool preempt_pending);
60 void vcore_reenter(void (*entry_func)(void));
61 void enable_notifs(uint32_t vcoreid);
62 void disable_notifs(uint32_t vcoreid);
63 void vcore_idle(void);
64 void ensure_vcore_runs(uint32_t vcoreid);
65 void cpu_relax_vc(uint32_t vcoreid);
66 uint32_t get_vcoreid(void);
67 bool check_vcoreid(const char *str, uint32_t vcoreid);
68
69 /* Static inlines */
70 static inline uint32_t max_vcores(void)
71 {
72         return MIN(__procinfo.max_vcores, MAX_VCORES);
73 }
74
75 static inline uint32_t num_vcores(void)
76 {
77         return __procinfo.num_vcores;
78 }
79
80 static inline int vcore_id(void)
81 {
82         return __vcoreid;
83 }
84
85 static inline bool in_vcore_context(void)
86 {
87         return __vcore_context;
88 }
89
90 static inline bool in_multi_mode(void)
91 {
92         return __procinfo.is_mcp;
93 }
94
95 /* Only call this if you know what you are doing. */
96 static inline void __enable_notifs(uint32_t vcoreid)
97 {
98         vcpd_of(vcoreid)->notif_disabled = FALSE;
99 }
100
101 static inline void __disable_notifs(uint32_t vcoreid)
102 {
103         vcpd_of(vcoreid)->notif_disabled = TRUE;
104 }
105
106 static inline bool notif_is_enabled(uint32_t vcoreid)
107 {
108         return !vcpd_of(vcoreid)->notif_disabled;
109 }
110
111 static inline bool vcore_is_mapped(uint32_t vcoreid)
112 {
113         return __procinfo.vcoremap[vcoreid].valid;
114 }
115
116 /* We could also check for VC_K_LOCK, but that's a bit much. */
117 static inline bool vcore_is_preempted(uint32_t vcoreid)
118 {
119         struct preempt_data *vcpd = vcpd_of(vcoreid);
120         return atomic_read(&vcpd->flags) & VC_PREEMPTED;
121 }
122
123 static inline struct preempt_data *vcpd_of(uint32_t vcoreid)
124 {
125         return &__procdata.vcore_preempt_data[vcoreid];
126 }
127
128 /* Uthread's can call this in case they care if a preemption is coming.  If a
129  * preempt is incoming, this will return TRUE, if you are in uthread context.  A
130  * reasonable response for a uthread is to yield, and vcore_entry will deal with
131  * the preempt pending.
132  *
133  * If you call this from vcore context, it will do nothing.  In general, it's
134  * not safe to just yield (or do whatever you plan on doing) from arbitrary
135  * places in vcore context.  So we just lie about PP. */
136 static inline bool preempt_is_pending(uint32_t vcoreid)
137 {
138         if (in_vcore_context())
139                 return FALSE;
140         return __preempt_is_pending(vcoreid);
141 }
142
143 static inline bool __preempt_is_pending(uint32_t vcoreid)
144 {
145         return __procinfo.vcoremap[vcoreid].preempt_pending;
146 }
147
148 /* The kernel interface uses uintptr_t, but we have a lot of older code that
149  * uses void *, hence the casting. */
150 static inline void *get_vcpd_tls_desc(uint32_t vcoreid)
151 {
152         return (void*)__procdata.vcore_preempt_data[vcoreid].vcore_tls_desc;
153 }
154
155 static inline void set_vcpd_tls_desc(uint32_t vcoreid, void *tls_desc)
156 {
157         __procdata.vcore_preempt_data[vcoreid].vcore_tls_desc = (uintptr_t)tls_desc;
158 }
159
160 static inline uint64_t vcore_resume(int vcore)
161 {
162         return __procinfo.vcoremap[vcore].resume;
163 }
164
165 static inline uint64_t vcore_total(int vcore)
166 {
167         return __procinfo.vcoremap[vcore].total;
168 }
169
170 #ifndef __PIC__
171
172 #define begin_safe_access_tls_vars()
173
174 #define end_safe_access_tls_vars()
175
176 #else
177
178 #include <features.h>
179 #if __GNUC_PREREQ(4,4)
180
181 /* These macro acrobatics trick the compiler into not caching the (linear)
182  * address of TLS variables across loads/stores of the TLS descriptor, in lieu
183  * of a "TLS cmb()". */
184 #define begin_safe_access_tls_vars()                                           \
185         void __attribute__((noinline, optimize("O0")))                             \
186         safe_access_tls_var_internal() {                                           \
187                 asm("");                                                               \
188
189 #define end_safe_access_tls_vars()                                             \
190         } safe_access_tls_var_internal();                                          \
191
192 #else
193
194 #define begin_safe_access_tls_vars()                                           \
195         printf("ERROR: For PIC use gcc 4.4 or above for tls support!\n");          \
196         printf("ERROR: As a quick fix, recompile your app with -static...\n");     \
197         exit(2);
198
199 #define end_safe_access_tls_vars()                                             \
200         printf("Will never be called because we abort above!");                    \
201         exit(2);
202
203 #endif //__GNUC_PREREQ
204 #endif // __PIC__
205
206 /* Switches into the TLS 'tls_desc'.  Capable of being called from either
207  * uthread or vcore context.  Pairs with end_access_tls_vars(). */
208 #define begin_access_tls_vars(tls_desc)                                        \
209 {                                                                              \
210         struct uthread *caller;                                                    \
211         uint32_t vcoreid;                                                          \
212         void *temp_tls_desc;                                                       \
213         bool invcore = in_vcore_context();                                         \
214         if (!invcore) {                                                            \
215                 caller = current_uthread;                                              \
216                 /* If you have no current_uthread, you might be called too early in the
217                  * process's lifetime.  Make sure something like uthread_slim_init() has
218                  * been run. */                                                        \
219                 assert(caller);                                                        \
220                 /* We need to disable notifs here (in addition to not migrating), since
221                  * we could get interrupted when we're in the other TLS, and when the
222                  * vcore restarts us, it will put us in our old TLS, not the one we were
223                  * in when we were interrupted.  We need to not migrate, since once we
224                  * know the vcoreid, we depend on being on the same vcore throughout.*/\
225                 caller->flags |= UTHREAD_DONT_MIGRATE;                                 \
226                 /* Not concerned about cross-core memory ordering, so no CPU mbs needed.
227                  * The cmb is to prevent the compiler from issuing the vcore read before
228                  * the DONT_MIGRATE write. */                                          \
229                 cmb();                                                                 \
230                 vcoreid = vcore_id();                                                  \
231                 disable_notifs(vcoreid);                                               \
232         } else { /* vcore context */                                               \
233                 vcoreid = vcore_id();                                                  \
234         }                                                                          \
235         temp_tls_desc = get_tls_desc(vcoreid);                                     \
236         set_tls_desc(tls_desc, vcoreid);                                           \
237         begin_safe_access_tls_vars();
238
239 #define end_access_tls_vars()                                                  \
240         end_safe_access_tls_vars();                                                \
241         set_tls_desc(temp_tls_desc, vcoreid);                                      \
242         if (!invcore) {                                                            \
243                 /* Note we reenable migration before enabling notifs, which is reverse
244                  * from how we disabled notifs.  We must enabling migration before
245                  * enabling notifs.  See 6c7fb12 and 5e4825eb4 for details. */         \
246                 caller->flags &= ~UTHREAD_DONT_MIGRATE;                                \
247                 cmb();  /* turn off DONT_MIGRATE before enabling notifs */             \
248                 if (in_multi_mode())                                                   \
249                         enable_notifs(vcoreid);                                            \
250         }                                                                          \
251 }
252
253 #define safe_set_tls_var(name, val)                                            \
254 ({                                                                             \
255         begin_safe_access_tls_vars();                                              \
256         name = val;                                                                \
257         end_safe_access_tls_vars();                                                \
258 })
259
260 #define safe_get_tls_var(name)                                                 \
261 ({                                                                             \
262         typeof(name) __val;                                                        \
263         begin_safe_access_tls_vars();                                              \
264         __val = name;                                                              \
265         end_safe_access_tls_vars();                                                \
266         __val;                                                                     \
267 })
268
269 #define vcore_set_tls_var(name, val)                                           \
270 ({                                                                             \
271         typeof(val) __val = val;                                                   \
272         begin_access_tls_vars(get_vcpd_tls_desc(vcoreid));                         \
273         name = __val;                                                              \
274         end_access_tls_vars();                                                     \
275 })
276
277 #define vcore_get_tls_var(name)                                                \
278 ({                                                                             \
279         typeof(name) val;                                                          \
280         begin_access_tls_vars(get_vcpd_tls_desc(vcoreid));                         \
281         val = name;                                                                \
282         end_access_tls_vars();                                                     \
283         val;                                                                       \
284 })
285
286 #ifdef __cplusplus
287 }
288 #endif
289
290 #endif