97da92001f3b911993ce528a7bdb745da9d95c40
[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 <sys/param.h>
10 #include <string.h>
11
12 /*****************************************************************************/
13 /* TODO: This is a complete hack, but necessary for vcore stuff to work for now
14  * The issue is that exit sometimes calls sys_yield(), and we can't recover from
15  * that properly under our vcore model (we shouldn't though).  We really need to
16  * rethink what sys_yield 'should' do when in multicore mode, or else come up 
17  * with a different syscall entirely. */
18 #include <stdlib.h>
19 #include <unistd.h>
20 #undef exit
21 #define exit(status) ros_syscall(SYS_proc_destroy, getpid(), status, 0, 0, 0, 0)
22 /*****************************************************************************/
23
24 #define LOG2_MAX_VCORES 6
25 #define MAX_VCORES (1 << LOG2_MAX_VCORES)
26
27 #define TRANSITION_STACK_PAGES 2
28 #define TRANSITION_STACK_SIZE (TRANSITION_STACK_PAGES*PGSIZE)
29
30 /* Defined by glibc; Must be implemented by a user level threading library */
31 extern void vcore_entry();
32 /* Declared in glibc's start.c */
33 extern __thread bool __vcore_context;
34
35 /* Utility Functions */
36 void *allocate_tls(void);
37
38 /* Vcore API functions */
39 static inline size_t max_vcores(void);
40 static inline size_t num_vcores(void);
41 static inline int vcore_id(void);
42 static inline bool in_vcore_context(void);
43 static inline void enable_notifs(uint32_t vcoreid);
44 static inline void disable_notifs(uint32_t vcoreid);
45 int vcore_init(void);
46 int vcore_request(size_t k);
47 void vcore_yield(void);
48 bool check_preempt_pending(uint32_t vcoreid);
49 void clear_notif_pending(uint32_t vcoreid);
50
51 /* Bare necessities of a user thread.  2LSs should allocate a bigger struct and
52  * cast their threads to uthreads when talking with vcore code.  Vcore/default
53  * 2LS code won't touch udata or beyond. */
54 struct uthread {
55         struct user_trapframe utf;
56         struct ancillary_state as;
57         void *tls_desc;
58         /* these four could be put in the 2LSs, but since their main use is by
59          * init_user_tf, which mucks with utf, we'll keep it in vcore code for now*/
60         void *(*start_routine)(void*);
61         void *arg;
62         void *stacktop;
63         void *retval;   /* tied to join, which isn't as clean as i'd like */
64         /* whether or not the scheduler can migrate you from your vcore */
65         bool dont_migrate;
66 };
67 extern __thread struct uthread *current_thread;
68
69 /* 2L-Scheduler operations.  Can be 0.  Examples in pthread.c. */
70 struct schedule_ops {
71         /* Functions supporting thread ops */
72         struct uthread *(*sched_init)(void);
73         void (*sched_entry)(void);
74         struct uthread *(*thread_create)(void *);
75         void (*thread_runnable)(struct uthread *);
76         void (*thread_yield)(struct uthread *);
77         void (*thread_exit)(struct uthread *);
78         /* Functions event handling wants */
79         void (*preempt_pending)(void);
80         void (*spawn_thread)(uintptr_t pc_start, void *data);   /* don't run yet */
81 };
82 extern struct schedule_ops *sched_ops;
83
84 /* Functions to make/manage uthreads.  Can be called by functions such as
85  * pthread_create(), which can wrap these with their own stuff (like attrs,
86  * retvals, etc). */
87
88 /* Creates a uthread.  Will pass udata to sched_ops's thread_create.  For now,
89  * the vcore/default 2ls code handles start routines and args.  Mostly because
90  * this is used when initing a utf, which is vcore specific for now. */
91 struct uthread *uthread_create(void *(*start_routine)(void *), void *arg,
92                                void *udata);
93 void uthread_yield(void);
94 void uthread_exit(void *retval);
95
96 /* Helpers, which sched_entry() can call */
97 void run_current_uthread(void);
98 void run_uthread(struct uthread *uthread);
99
100 /* Static inlines */
101 static inline size_t max_vcores(void)
102 {
103         return MIN(__procinfo.max_vcores, MAX_VCORES);
104 }
105
106 static inline size_t num_vcores(void)
107 {
108         return __procinfo.num_vcores;
109 }
110
111 static inline int vcore_id(void)
112 {
113         return __vcoreid;
114 }
115
116 static inline bool in_vcore_context(void)
117 {
118         return __vcore_context;
119 }
120
121 static inline void enable_notifs(uint32_t vcoreid)
122 {
123         __procdata.vcore_preempt_data[vcoreid].notif_enabled = TRUE;
124 }
125
126 static inline void disable_notifs(uint32_t vcoreid)
127 {
128         __procdata.vcore_preempt_data[vcoreid].notif_enabled = FALSE;
129 }
130
131 #ifdef __cplusplus
132 }
133 #endif
134
135 #endif