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