Massive renaming/cleanup of harts->vcores
[akaros.git] / user / parlib / vcore.c
1 #include <stdbool.h>
2 #include <errno.h>
3 #include <vcore.h>
4 #include <mcs.h>
5 #include <sys/param.h>
6 #include <parlib.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <sys/mman.h>
10 #include <rstdio.h>
11
12 // Only need in this file because _dl_allocate and friends are
13 //  internal functions in glibc
14 # ifdef __i386__
15 #  define internal_function   __attribute ((regparm (3), stdcall))
16 # else
17 #  define internal_function
18 # endif
19
20 static size_t _max_vcores_ever_wanted = 0;
21 static mcs_lock_t _vcore_lock = MCS_LOCK_INIT;
22
23 extern void** vcore_thread_control_blocks;
24
25 static void free_transition_tls(int id)
26 {
27         extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
28         if(vcore_thread_control_blocks[id])
29         {
30                 _dl_deallocate_tls(vcore_thread_control_blocks[id],true);
31                 vcore_thread_control_blocks[id] = NULL;
32         }
33 }
34
35 static int allocate_transition_tls(int id)
36 {
37         extern void *_dl_allocate_tls (void *mem) internal_function;
38         // We want to free and then reallocate the tls rather than simply 
39         // reinitializing it because its size may have changed
40         free_transition_tls(id);
41
42         void* tls = _dl_allocate_tls(NULL);
43         if((vcore_thread_control_blocks[id] = tls) == NULL) {
44                 errno = ENOMEM;
45                 return -1;
46         }
47         return 0;
48 }
49
50 #define TRANSITION_STACK_PAGES 2
51 #define TRANSITION_STACK_SIZE (TRANSITION_STACK_PAGES*PGSIZE)
52
53 static void free_transition_stack(int id)
54 {
55         // don't actually free stacks
56 }
57
58 static int allocate_transition_stack(int id)
59 {
60         struct preempt_data *vcpd = &__procdata.vcore_preempt_data[id];
61         if (vcpd->transition_stack)
62                 return 0; // reuse old stack
63
64         void* stackbot = mmap(0, TRANSITION_STACK_SIZE,
65                               PROT_READ|PROT_WRITE|PROT_EXEC,
66                               MAP_POPULATE|MAP_ANONYMOUS, -1, 0);
67
68         if(stackbot == MAP_FAILED)
69                 return -1; // errno set by mmap
70
71         vcpd->transition_stack = (uintptr_t)stackbot + TRANSITION_STACK_SIZE;
72
73         return 0;
74 }
75
76 int vcore_init()
77 {
78         static int initialized = 0;
79         if(initialized)
80                 return 0;
81
82         vcore_thread_control_blocks = (void**)calloc(max_vcores(),sizeof(void*));
83
84         if(!vcore_thread_control_blocks)
85                 goto vcore_init_fail;
86
87         initialized = 1;
88         return 0;
89
90 vcore_init_fail:
91         errno = ENOMEM;
92         return -1;
93 }
94
95 int vcore_request(size_t k)
96 {
97         int ret = -1;
98         size_t i,j;
99
100         if(vcore_init() < 0)
101                 return -1;
102
103         // TODO: could do this function without a lock once we 
104         // have atomic fetch and add in user space
105         mcs_lock_lock(&_vcore_lock);
106
107         size_t vcores_wanted = num_vcores() + k;
108         if(k < 0 || vcores_wanted > max_vcores())
109         {
110                 errno = EAGAIN;
111                 goto fail;
112         }
113
114         for(i = _max_vcores_ever_wanted; i < vcores_wanted; i++)
115         {
116                 if(allocate_transition_stack(i) || allocate_transition_tls(i))
117                         goto fail; // errno set by the call that failed
118                 _max_vcores_ever_wanted++;
119         }
120         ret = sys_resource_req(RES_CORES, vcores_wanted, 1, 0);
121
122 fail:
123         mcs_lock_unlock(&_vcore_lock);
124         return ret;
125 }
126
127 void vcore_yield()
128 {
129         sys_yield(0);
130 }
131
132 size_t max_vcores()
133 {
134         return MIN(__procinfo.max_vcores, MAX_VCORES);
135 }
136
137 size_t num_vcores()
138 {
139         return __procinfo.num_vcores;
140 }
141
142 int vcore_id()
143 {
144         // defined in ros/arch/vcore.h
145         return __vcore_id();
146 }
147