46e67cb84b63ac075d2df46a416b0a697cc4acda
[akaros.git] / user / parlib / src / pthread.c
1 #include <pthread.h>
2 #include <hart.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <assert.h>
6
7 int threads_active = 1;
8 int current_harts = 1;
9 hart_lock_t work_queue_lock = HART_LOCK_INIT;
10 pthread_t work_queue_head = 0;
11 pthread_t work_queue_tail = 0;
12 pthread_once_t init_once = PTHREAD_ONCE_INIT;
13 pthread_t active_threads[HART_MAX_MAX_HARTS] = {0};
14
15 void queue_insert(pthread_t* head, pthread_t* tail, pthread_t node)
16 {
17   node->next = 0;
18   if(*head == 0)
19     *head = node;
20   else
21     (*tail)->next = node;
22   *tail = node;
23 }
24
25 pthread_t queue_remove(pthread_t* head, pthread_t* tail)
26 {
27   pthread_t node = *head;
28   *head = (*head)->next;
29   if(*head == 0)
30     *tail = 0;
31   node->next = 0;
32   return node;
33 }
34
35 void hart_entry()
36 {
37   pthread_t node = NULL;
38   while(1)
39   {
40     hart_lock_lock(&work_queue_lock);
41     if(work_queue_head)
42       node = queue_remove(&work_queue_head,&work_queue_tail);
43     hart_lock_unlock(&work_queue_lock);
44
45     if(node)
46       break;
47     hart_relax();
48   }
49
50   active_threads[hart_self()] = node;
51
52   pthread_exit(node->start_routine(node->arg));
53 }
54
55 void _pthread_init()
56 {
57   // if we allocated active_threads dynamically, we'd do so here
58 }
59
60 int pthread_attr_init(pthread_attr_t *a)
61 {
62   return 0;
63 }
64
65 int pthread_attr_destroy(pthread_attr_t *a)
66 {
67   return 0;
68 }
69
70 int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
71                    void *(*start_routine)(void *), void* arg)
72 {
73   pthread_once(&init_once,&_pthread_init);
74
75   *thread = (pthread_t)malloc(sizeof(work_queue_t));
76   (*thread)->start_routine = start_routine;
77   (*thread)->arg = arg;
78   (*thread)->next = 0;
79   (*thread)->finished = 0;
80   (*thread)->detached = 0;
81
82   int request_hart = 0;
83
84   hart_lock_lock(&work_queue_lock);
85   {
86     threads_active++;
87     if(threads_active > current_harts)
88       request_hart = 1;
89
90     queue_insert(&work_queue_head,&work_queue_tail,*thread);
91   }
92   hart_lock_unlock(&work_queue_lock);
93
94   // don't return until we get a hart
95   while(request_hart && hart_request(1));
96   return 0;
97 }
98
99 int pthread_join(pthread_t t, void** arg)
100 {
101   volatile pthread_t thread = t;
102   while(!thread->finished);
103   if(arg) *arg = thread->arg;
104   free(thread);
105   return 0;
106 }
107
108 int pthread_mutexattr_init(pthread_mutexattr_t* attr)
109 {
110   attr->type = PTHREAD_MUTEX_DEFAULT;
111   return 0;
112 }
113
114 int pthread_mutexattr_destroy(pthread_mutexattr_t* attr)
115 {
116   return 0;
117 }
118
119 int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type)
120 {
121   *type = attr ? attr->type : PTHREAD_MUTEX_DEFAULT;
122   return 0;
123 }
124
125 int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type)
126 {
127   if(type != PTHREAD_MUTEX_NORMAL)
128     return -EINVAL;
129   attr->type = type;
130   return 0;
131 }
132
133 int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr)
134 {
135   m->attr = attr;
136   m->lock = 0;
137   return 0;
138 }
139
140 int pthread_mutex_lock(pthread_mutex_t* m)
141 {
142   while(pthread_mutex_trylock(m))
143     while((volatile size_t*)m->lock);
144   return 0;
145 }
146
147 int pthread_mutex_trylock(pthread_mutex_t* m)
148 {
149   return hart_swap(&m->lock,1) == 0 ? 0 : -EBUSY;
150 }
151
152 int pthread_mutex_unlock(pthread_mutex_t* m)
153 {
154   m->lock = 0;
155   return 0;
156 }
157
158 int pthread_mutex_destroy(pthread_mutex_t* m)
159 {
160   return 0;
161 }
162
163 int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a)
164 {
165   c->attr = a;
166   memset(c->waiters,0,sizeof(c->waiters));
167   return 0;
168 }
169
170 int pthread_cond_destroy(pthread_cond_t *c)
171 {
172   return 0;
173 }
174
175 int pthread_cond_broadcast(pthread_cond_t *c)
176 {
177   memset(c->waiters,0,sizeof(c->waiters));
178   return 0;
179 }
180
181 int pthread_cond_signal(pthread_cond_t *c)
182 {
183   int i;
184   for(i = 0; i < hart_max_harts(); i++)
185   {
186     if(c->waiters[i])
187     {
188       c->waiters[i] = 0;
189       break;
190     }
191   }
192   return 0;
193 }
194
195 int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
196 {
197   c->waiters[hart_self()] = 1;
198   pthread_mutex_unlock(m);
199
200   volatile int* poll = &c->waiters[hart_self()];
201   while(*poll);
202
203   pthread_mutex_lock(m);
204
205   return 0;
206 }
207
208 int pthread_condattr_init(pthread_condattr_t *a)
209 {
210   a = PTHREAD_PROCESS_PRIVATE;
211   return 0;
212 }
213
214 int pthread_condattr_destroy(pthread_condattr_t *a)
215 {
216   return 0;
217 }
218
219 int pthread_condattr_setpshared(pthread_condattr_t *a, int s)
220 {
221   a->pshared = s;
222   return 0;
223 }
224
225 int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
226 {
227   *s = a->pshared;
228   return 0;
229 }
230
231 pthread_t pthread_self()
232 {
233   return active_threads[hart_self()];
234 }
235
236 int pthread_equal(pthread_t t1, pthread_t t2)
237 {
238   return t1 == t2;
239 }
240
241 void pthread_exit(void* ret)
242 {
243   pthread_once(&init_once,&_pthread_init);
244
245   pthread_t t = pthread_self();
246
247   hart_lock_lock(&work_queue_lock);
248   threads_active--;
249   if(threads_active == 0)
250     exit(0);
251   hart_lock_unlock(&work_queue_lock);
252
253   if(t)
254   {
255     t->arg = ret;
256     t->finished = 1;
257     if(t->detached)
258       free(t);
259   }
260
261   hart_entry();
262 }
263
264 int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
265 {
266   if(hart_swap(once_control,1) == 0)
267     init_routine();
268   return 0;
269 }
270
271 int pthread_barrier_init(pthread_barrier_t* b, const pthread_barrierattr_t* a, int count)
272 {
273   b->local_sense = (int*)malloc(32*sizeof(int)*count);
274   memset(b->local_sense,0,32*sizeof(int)*count);
275
276   b->sense = 0;
277   b->nprocs = b->count = count;
278   hart_lock_init(&b->lock);
279   return 0;
280 }
281
282 int pthread_barrier_wait(pthread_barrier_t* b)
283 {
284   int id = hart_self();
285   int ls = b->local_sense[32*id] = 1 - b->local_sense[32*id];
286
287   hart_lock_lock(&b->lock);
288   int count = --b->count;
289   hart_lock_unlock(&b->lock);
290
291   if(count == 0)
292   {
293     b->count = b->nprocs;
294     b->sense = ls;
295     return PTHREAD_BARRIER_SERIAL_THREAD;
296   }
297   else
298   {
299     while(b->sense != ls);
300     return 0;
301   }
302 }
303
304 int pthread_barrier_destroy(pthread_barrier_t* b)
305 {
306   free(b->local_sense);
307   return 0;
308 }