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