cleaned up harts stack allocation
[akaros.git] / user / parlib / src / hart.c
1 #include <hart.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <parlib.h>
7
8 static size_t _current_harts = 1;
9 static hart_lock_t _hart_lock = HART_LOCK_INIT;
10
11 static void _hart_init()
12 {
13         static int initialized = 0;
14         if(initialized)
15                 return;
16
17         initialized = 1;
18
19         extern void **stack_ptr_array, **tls_array;
20         stack_ptr_array = (void**)calloc(hart_max_harts(),sizeof(void*));
21         tls_array = (void**)calloc(hart_max_harts(),sizeof(void*));
22
23         if(stack_ptr_array == NULL || tls_array == NULL)
24         {
25                 fputs("Harts initialization ran out of memory!\n",stderr);
26                 abort();
27         }       
28 }
29
30 error_t hart_request(size_t k)
31 {
32         size_t i,j;
33         const int user_stack_size = 1024*1024, tls_size = 1024*1024;
34
35         extern void** stack_ptr_array;
36         extern void** tls_array;
37
38         _hart_init();
39
40         hart_lock_lock(&_hart_lock);
41
42         if(k < 0 || _current_harts+k > hart_max_harts())
43                 return -1;
44
45         char* stack = (char*)calloc(user_stack_size+tls_size,k);
46         if(stack == NULL)
47         {
48                 hart_lock_unlock(&_hart_lock);
49                 return -ENOMEM;
50         }
51
52         for(i = _current_harts, j = 0; i < _current_harts+k; i++, j++)
53         {
54                 stack_ptr_array[i] = stack + j*(user_stack_size+tls_size);
55                 tls_array[i] = stack_ptr_array[i]+tls_size;
56         }
57
58         error_t ret;
59         if((ret = sys_resource_req(0,_current_harts+k,0)) == 0)
60         {
61                 _current_harts += k;
62                 hart_lock_unlock(&_hart_lock);
63                 return 0;
64         }
65
66         free(stack);
67         for(i = _current_harts; i < _current_harts+k; i++)
68                 stack_ptr_array[i] = tls_array[i] = 0;
69
70         hart_lock_unlock(&_hart_lock);
71         return ret;
72 }
73
74 void hart_yield()
75 {
76         hart_lock_lock(&_hart_lock);
77         _current_harts--;
78         hart_lock_unlock(&_hart_lock);
79         syscall(SYS_yield,0,0,0,0,0);
80 }
81
82 size_t hart_max_harts()
83 {
84         return procinfo.max_harts < HART_MAX_MAX_HARTS ? procinfo.max_harts : HART_MAX_MAX_HARTS;
85 }
86
87 size_t hart_current_harts()
88 {
89         return _current_harts;
90 }
91
92 // MCS locks!!
93 void hart_lock_init(hart_lock_t* lock)
94 {
95         memset(lock,0,sizeof(hart_lock_t));
96 }
97
98 static inline hart_lock_qnode_t* hart_qnode_swap(hart_lock_qnode_t** addr, hart_lock_qnode_t* val)
99 {
100         return (hart_lock_qnode_t*)hart_swap((int*)addr,(int)val);
101 }
102
103 void hart_lock_lock(hart_lock_t* lock)
104 {
105         hart_lock_qnode_t* qnode = &lock->qnode[hart_self()];
106         qnode->next = 0;
107         hart_lock_qnode_t* predecessor = hart_qnode_swap(&lock->lock,qnode);
108         if(predecessor)
109         {
110                 qnode->locked = 1;
111                 predecessor->next = qnode;
112                 while(qnode->locked);
113         }
114 }
115
116 void hart_lock_unlock(hart_lock_t* lock)
117 {
118         hart_lock_qnode_t* qnode = &lock->qnode[hart_self()];
119         if(qnode->next == 0)
120         {
121                 hart_lock_qnode_t* old_tail = hart_qnode_swap(&lock->lock,0);
122                 if(old_tail == qnode)
123                         return;
124
125                 hart_lock_qnode_t* usurper = hart_qnode_swap(&lock->lock,old_tail);
126                 while(qnode->next == 0);
127                 if(usurper)
128                         usurper->next = qnode->next;
129                 else
130                         qnode->next->locked = 0;
131         }
132         else
133                 qnode->next->locked = 0;
134 }
135
136 // MCS dissemination barrier!
137 error_t hart_barrier_init(hart_barrier_t* b, size_t np)
138 {
139         if(np > hart_max_harts())
140                 return -1;
141         b->allnodes = (hart_dissem_flags_t*)malloc(np*sizeof(hart_dissem_flags_t));
142         memset(b->allnodes,0,np*sizeof(hart_dissem_flags_t));
143         b->nprocs = np;
144
145         b->logp = (np & (np-1)) != 0;
146         while(np >>= 1)
147                 b->logp++;
148
149         size_t i,k;
150         for(i = 0; i < b->nprocs; i++)
151         {
152                 b->allnodes[i].parity = 0;
153                 b->allnodes[i].sense = 1;
154
155                 for(k = 0; k < b->logp; k++)
156                 {
157                         size_t j = (i+(1<<k)) % b->nprocs;
158                         b->allnodes[i].partnerflags[0][k] = &b->allnodes[j].myflags[0][k];
159                         b->allnodes[i].partnerflags[1][k] = &b->allnodes[j].myflags[1][k];
160                 } 
161         }
162
163         return 0;
164 }
165
166 void hart_barrier_wait(hart_barrier_t* b, size_t pid)
167 {
168         hart_dissem_flags_t* localflags = &b->allnodes[pid];
169         size_t i;
170         for(i = 0; i < b->logp; i++)
171         {
172                 *localflags->partnerflags[localflags->parity][i] = localflags->sense;
173                 while(localflags->myflags[localflags->parity][i] != localflags->sense);
174         }
175         if(localflags->parity)
176                 localflags->sense = 1-localflags->sense;
177         localflags->parity = 1-localflags->parity;
178 }
179
180 int
181 hart_self()
182 {
183         // defined in ros/arch/hart.h
184         return __hart_self();
185 }
186
187 int
188 hart_swap(int* addr, int val)
189 {
190         return __hart_swap(addr,val);
191 }
192
193 void
194 hart_relax()
195 {
196         __hart_relax();
197 }
198