Glibc syscalls now block properly (XCC)
[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
36 /* Utility Functions */
37 void *allocate_tls(void);
38 void free_tls(void *tcb);
39 void *reinit_tls(void *tcb);
40
41 /* Vcore API functions */
42 static inline size_t max_vcores(void);
43 static inline size_t num_vcores(void);
44 static inline int vcore_id(void);
45 static inline bool in_vcore_context(void);
46 static inline bool in_multi_mode(void);
47 static inline void __enable_notifs(uint32_t vcoreid);
48 static inline void __disable_notifs(uint32_t vcoreid);
49 static inline bool notif_is_enabled(uint32_t vcoreid);
50 static inline bool vcore_is_mapped(uint32_t vcoreid);
51 static inline bool vcore_is_preempted(uint32_t vcoreid);
52 static inline struct preempt_data *vcpd_of(uint32_t vcoreid);
53 static inline bool preempt_is_pending(uint32_t vcoreid);
54 static inline bool __preempt_is_pending(uint32_t vcoreid);
55 int 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 bool clear_notif_pending(uint32_t vcoreid);
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
67 /* Static inlines */
68 static inline size_t max_vcores(void)
69 {
70         return MIN(__procinfo.max_vcores, MAX_VCORES);
71 }
72
73 static inline size_t num_vcores(void)
74 {
75         return __procinfo.num_vcores;
76 }
77
78 static inline int vcore_id(void)
79 {
80         return __vcoreid;
81 }
82
83 static inline bool in_vcore_context(void)
84 {
85         return __vcore_context;
86 }
87
88 static inline bool in_multi_mode(void)
89 {
90         return __procinfo.is_mcp;
91 }
92
93 /* Only call this if you know what you are doing. */
94 static inline void __enable_notifs(uint32_t vcoreid)
95 {
96         vcpd_of(vcoreid)->notif_disabled = FALSE;
97 }
98
99 static inline void __disable_notifs(uint32_t vcoreid)
100 {
101         vcpd_of(vcoreid)->notif_disabled = TRUE;
102 }
103
104 static inline bool notif_is_enabled(uint32_t vcoreid)
105 {
106         return !vcpd_of(vcoreid)->notif_disabled;
107 }
108
109 static inline bool vcore_is_mapped(uint32_t vcoreid)
110 {
111         return __procinfo.vcoremap[vcoreid].valid;
112 }
113
114 /* We could also check for VC_K_LOCK, but that's a bit much. */
115 static inline bool vcore_is_preempted(uint32_t vcoreid)
116 {
117         struct preempt_data *vcpd = vcpd_of(vcoreid);
118         return atomic_read(&vcpd->flags) & VC_PREEMPTED;
119 }
120
121 static inline struct preempt_data *vcpd_of(uint32_t vcoreid)
122 {
123         return &__procdata.vcore_preempt_data[vcoreid];
124 }
125
126 /* Uthread's can call this in case they care if a preemption is coming.  If a
127  * preempt is incoming, this will return TRUE, if you are in uthread context.  A
128  * reasonable response for a uthread is to yield, and vcore_entry will deal with
129  * the preempt pending.
130  *
131  * If you call this from vcore context, it will do nothing.  In general, it's
132  * not safe to just yield (or do whatever you plan on doing) from arbitrary
133  * places in vcore context.  So we just lie about PP. */
134 static inline bool preempt_is_pending(uint32_t vcoreid)
135 {
136         if (in_vcore_context())
137                 return FALSE;
138         return __preempt_is_pending(vcoreid);
139 }
140
141 static inline bool __preempt_is_pending(uint32_t vcoreid)
142 {
143         return __procinfo.vcoremap[vcoreid].preempt_pending;
144 }
145
146 #ifdef __cplusplus
147 }
148 #endif
149
150 #endif