ebc9870e0346b76f4b0f841688ad46172b010a11
[akaros.git] / user / c3po / threads / ucontext.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdarg.h>
4 #include <threadlib_internal.h>
5 #include <vcore.h>
6 #include <ucontext.h>
7
8
9 /* Maintain a static reference to the main threads tls region */
10 static void *__main_tls_desc;
11
12 struct u_context* create_context(thread_t *t, void *entry_pt, void *stack_top)
13 {
14         uint32_t vcoreid = vcore_id();
15
16         /* Allocate a new context struct */
17         struct u_context *uc = malloc(sizeof(struct u_context));
18         if(!uc) return NULL;
19
20         /* If we are the main thread, then current_thread has not been set yet, so
21          * we set the tls descriptor to the tls on the currently running core */
22         if(current_thread == NULL) {
23                 /* Make sure this only executes once! */
24                 static int done = FALSE;
25                 assert(!done); done = TRUE;
26
27                 /* Set up the tls regions for the main thred */
28                 uc->tls_desc = get_tls_desc(vcoreid);
29                 __main_tls_desc = uc->tls_desc;
30
31                 /* And set the current thread in this tls region */
32                 current_thread = t;
33         }
34     /* Otherwise, allocate a new tls region for this context */
35         else {
36                 /* Allocate the tls, freeing the whole uc if it fails */
37         uc->tls_desc = allocate_tls();
38                 if(!uc->tls_desc) {
39                         free(uc);
40                         return NULL;
41                 }
42                 /* Temporarily switch into the new the context's tls region to set the
43                  * current_thread variable in that tls region */
44                 void *temp_tls = get_tls_desc(vcoreid);
45                 set_tls_desc(uc->tls_desc, vcoreid);
46                 current_thread = t;
47                 /* Then switch back to the origin one */
48                 set_tls_desc(temp_tls, vcoreid);
49         }
50
51         /* For good measure, also save the thread associated with this context in
52          * the ucontext struct */
53         uc->thread = t;
54
55         /* Initialize the trapframe for this context */
56         init_user_ctx(&uc->u_ctx, (uint32_t)entry_pt, (uint32_t)stack_top);
57         return uc;
58 }
59
60 void save_context(struct u_context *uc)
61 {
62         /* Save the trapframe for this context */
63         save_user_ctx(&uc->u_ctx);
64 }
65
66 void restore_context(struct u_context *uc)
67 {
68         uint32_t vcoreid = vcore_id();
69
70         /* Save the thread we are about to restore into current_thread
71          * in this vcores tls region */
72         current_thread = uc->thread;
73         /* Set the proper tls descriptor for the context we are restoring */
74     set_tls_desc(uc->tls_desc, vcoreid);
75         /* Tell the uthread which vcore it is on */
76         __vcoreid = vcoreid;
77         /* Pop the trapframe */
78         pop_user_ctx(&uc->u_ctx, vcoreid);
79 }
80
81 void destroy_context(struct u_context *uc)
82 {
83     extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
84
85         /* Make sure we have passed in Non-Null pointers for our ucontext / tls */
86     assert(uc);
87     assert(uc->tls_desc);
88
89         /* Dont' deallocate the main tls descriptor, glibc will do that */
90         if(uc->tls_desc != __main_tls_desc)
91         _dl_deallocate_tls(uc->tls_desc, TRUE);
92         free(uc);
93 }
94
95 void print_context(struct u_context *uc)
96 {
97         printf("GIANT WARNING: this assumes a HW ctx\n");
98         /* Just print the trapframe */
99         print_trapframe(&uc->u_ctx.tf.hw_tf);
100 }
101