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