fixed pedantic gcc warning
[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 #pragma weak hart_entry
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   hart_lock_lock(&work_queue_lock);
83   {
84     threads_active++;
85     queue_insert(&work_queue_head,&work_queue_tail,*thread);
86     // don't return until we get a hart
87     while(threads_active > hart_current_harts() && hart_request(1));
88   }
89   hart_lock_unlock(&work_queue_lock);
90
91   return 0;
92 }
93
94 int pthread_join(pthread_t t, void** arg)
95 {
96   volatile pthread_t thread = t;
97   while(!thread->finished);
98   if(arg) *arg = thread->arg;
99   free(thread);
100   return 0;
101 }
102
103 int pthread_mutexattr_init(pthread_mutexattr_t* attr)
104 {
105   attr->type = PTHREAD_MUTEX_DEFAULT;
106   return 0;
107 }
108
109 int pthread_mutexattr_destroy(pthread_mutexattr_t* attr)
110 {
111   return 0;
112 }
113
114 int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type)
115 {
116   *type = attr ? attr->type : PTHREAD_MUTEX_DEFAULT;
117   return 0;
118 }
119
120 int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type)
121 {
122   if(type != PTHREAD_MUTEX_NORMAL)
123     return -EINVAL;
124   attr->type = type;
125   return 0;
126 }
127
128 int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr)
129 {
130   m->attr = attr;
131   m->lock = 0;
132   return 0;
133 }
134
135 int pthread_mutex_lock(pthread_mutex_t* m)
136 {
137   while(pthread_mutex_trylock(m))
138     while(*(volatile size_t*)&m->lock);
139   return 0;
140 }
141
142 int pthread_mutex_trylock(pthread_mutex_t* m)
143 {
144   return hart_swap(&m->lock,1) == 0 ? 0 : -EBUSY;
145 }
146
147 int pthread_mutex_unlock(pthread_mutex_t* m)
148 {
149   m->lock = 0;
150   return 0;
151 }
152
153 int pthread_mutex_destroy(pthread_mutex_t* m)
154 {
155   return 0;
156 }
157
158 int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a)
159 {
160   c->attr = a;
161   memset(c->waiters,0,sizeof(c->waiters));
162   return 0;
163 }
164
165 int pthread_cond_destroy(pthread_cond_t *c)
166 {
167   return 0;
168 }
169
170 int pthread_cond_broadcast(pthread_cond_t *c)
171 {
172   memset(c->waiters,0,sizeof(c->waiters));
173   return 0;
174 }
175
176 int pthread_cond_signal(pthread_cond_t *c)
177 {
178   int i;
179   for(i = 0; i < hart_max_harts(); i++)
180   {
181     if(c->waiters[i])
182     {
183       c->waiters[i] = 0;
184       break;
185     }
186   }
187   return 0;
188 }
189
190 int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
191 {
192   c->waiters[hart_self()] = 1;
193   pthread_mutex_unlock(m);
194
195   volatile int* poll = &c->waiters[hart_self()];
196   while(*poll);
197
198   pthread_mutex_lock(m);
199
200   return 0;
201 }
202
203 int pthread_condattr_init(pthread_condattr_t *a)
204 {
205   a = PTHREAD_PROCESS_PRIVATE;
206   return 0;
207 }
208
209 int pthread_condattr_destroy(pthread_condattr_t *a)
210 {
211   return 0;
212 }
213
214 int pthread_condattr_setpshared(pthread_condattr_t *a, int s)
215 {
216   a->pshared = s;
217   return 0;
218 }
219
220 int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
221 {
222   *s = a->pshared;
223   return 0;
224 }
225
226 pthread_t pthread_self()
227 {
228   return active_threads[hart_self()];
229 }
230
231 int pthread_equal(pthread_t t1, pthread_t t2)
232 {
233   return t1 == t2;
234 }
235
236 void pthread_exit(void* ret)
237 {
238   pthread_once(&init_once,&_pthread_init);
239
240   pthread_t t = pthread_self();
241
242   hart_lock_lock(&work_queue_lock);
243   threads_active--;
244   if(threads_active == 0)
245     exit(0);
246   hart_lock_unlock(&work_queue_lock);
247
248   if(t)
249   {
250     t->arg = ret;
251     t->finished = 1;
252     if(t->detached)
253       free(t);
254   }
255
256   hart_entry();
257 }
258
259 int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
260 {
261   if(hart_swap(once_control,1) == 0)
262     init_routine();
263   return 0;
264 }
265
266 int pthread_barrier_init(pthread_barrier_t* b, const pthread_barrierattr_t* a, int count)
267 {
268   memset(b->local_sense,0,sizeof(b->local_sense));
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   return 0;
301 }