Pthread join/exit/yield use the uth_yield func ptr
[akaros.git] / user / pthread / pthread.c
1 #include <ros/arch/trapframe.h>
2 #include <pthread.h>
3 #include <vcore.h>
4 #include <mcs.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <assert.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <parlib.h>
11 #include <ros/event.h>
12 #include <arch/atomic.h>
13 #include <arch/arch.h>
14 #include <sys/queue.h>
15 #include <sys/mman.h>
16 #include <assert.h>
17 #include <event.h>
18 #include <ucq.h>
19
20 struct pthread_queue ready_queue = TAILQ_HEAD_INITIALIZER(ready_queue);
21 struct pthread_queue active_queue = TAILQ_HEAD_INITIALIZER(active_queue);
22 struct mcs_pdr_lock queue_lock;
23 pthread_once_t init_once = PTHREAD_ONCE_INIT;
24 int threads_ready = 0;
25 int threads_active = 0;
26
27 /* Array of per-vcore structs to manage waiting on syscalls and handling
28  * overflow.  Init'd in pth_init(). */
29 struct sysc_mgmt *sysc_mgmt = 0;
30
31 /* Helper / local functions */
32 static int get_next_pid(void);
33 static inline void spin_to_sleep(unsigned int spins, unsigned int *spun);
34
35 /* Pthread 2LS operations */
36 void pth_sched_entry(void);
37 void pth_thread_runnable(struct uthread *uthread);
38 void pth_thread_paused(struct uthread *uthread);
39 void pth_thread_blockon_sysc(struct uthread *uthread, void *sysc);
40 void pth_thread_has_blocked(struct uthread *uthread, int flags);
41 void pth_preempt_pending(void);
42 void pth_spawn_thread(uintptr_t pc_start, void *data);
43
44 /* Event Handlers */
45 static void pth_handle_syscall(struct event_msg *ev_msg, unsigned int ev_type);
46
47 struct schedule_ops pthread_sched_ops = {
48         pth_sched_entry,
49         pth_thread_runnable,
50         pth_thread_paused,
51         pth_thread_blockon_sysc,
52         pth_thread_has_blocked,
53         0, /* pth_preempt_pending, */
54         0, /* pth_spawn_thread, */
55 };
56
57 /* Publish our sched_ops, overriding the weak defaults */
58 struct schedule_ops *sched_ops = &pthread_sched_ops;
59
60 /* Static helpers */
61 static void __pthread_free_stack(struct pthread_tcb *pt);
62 static int __pthread_allocate_stack(struct pthread_tcb *pt);
63
64 /* Called from vcore entry.  Options usually include restarting whoever was
65  * running there before or running a new thread.  Events are handled out of
66  * event.c (table of function pointers, stuff like that). */
67 void __attribute__((noreturn)) pth_sched_entry(void)
68 {
69         uint32_t vcoreid = vcore_id();
70         if (current_uthread) {
71                 run_current_uthread();
72                 assert(0);
73         }
74         /* no one currently running, so lets get someone from the ready queue */
75         struct pthread_tcb *new_thread = NULL;
76         /* Try to get a thread.  If we get one, we'll break out and run it.  If not,
77          * we'll try to yield.  vcore_yield() might return, if we lost a race and
78          * had a new event come in, one that may make us able to get a new_thread */
79         do {
80                 handle_events(vcoreid);
81                 __check_preempt_pending(vcoreid);
82                 mcs_pdr_lock(&queue_lock);
83                 new_thread = TAILQ_FIRST(&ready_queue);
84                 if (new_thread) {
85                         TAILQ_REMOVE(&ready_queue, new_thread, next);
86                         TAILQ_INSERT_TAIL(&active_queue, new_thread, next);
87                         threads_active++;
88                         threads_ready--;
89                         mcs_pdr_unlock(&queue_lock);
90                         /* If you see what looks like the same uthread running in multiple
91                          * places, your list might be jacked up.  Turn this on. */
92                         printd("[P] got uthread %08p on vc %d state %08p flags %08p\n",
93                                new_thread, vcoreid,
94                                ((struct uthread*)new_thread)->state,
95                                ((struct uthread*)new_thread)->flags);
96                         break;
97                 }
98                 mcs_pdr_unlock(&queue_lock);
99                 /* no new thread, try to yield */
100                 printd("[P] No threads, vcore %d is yielding\n", vcore_id());
101                 /* TODO: you can imagine having something smarter here, like spin for a
102                  * bit before yielding (or not at all if you want to be greedy). */
103                 vcore_yield(FALSE);
104         } while (1);
105         assert(new_thread->state == PTH_RUNNABLE);
106         run_uthread((struct uthread*)new_thread);
107         assert(0);
108 }
109
110 /* Could move this, along with start_routine and arg, into the 2LSs */
111 static void __pthread_run(void)
112 {
113         struct pthread_tcb *me = pthread_self();
114         pthread_exit(me->start_routine(me->arg));
115 }
116
117 void pth_thread_runnable(struct uthread *uthread)
118 {
119         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
120         /* At this point, the 2LS can see why the thread blocked and was woken up in
121          * the first place (coupling these things together).  On the yield path, the
122          * 2LS was involved and was able to set the state.  Now when we get the
123          * thread back, we can take a look. */
124         printd("pthread %08p runnable, state was %d\n", pthread, pthread->state);
125         switch (pthread->state) {
126                 case (PTH_CREATED):
127                 case (PTH_BLK_YIELDING):
128                 case (PTH_BLK_JOINING):
129                 case (PTH_BLK_SYSC):
130                 case (PTH_BLK_MUTEX):
131                         /* can do whatever for each of these cases */
132                         break;
133                 default:
134                         printf("Odd state %d for pthread %08p\n", pthread->state, pthread);
135         }
136         pthread->state = PTH_RUNNABLE;
137         /* Insert the newly created thread into the ready queue of threads.
138          * It will be removed from this queue later when vcore_entry() comes up */
139         mcs_pdr_lock(&queue_lock);
140         TAILQ_INSERT_TAIL(&ready_queue, pthread, next);
141         threads_ready++;
142         mcs_pdr_unlock(&queue_lock);
143         /* Smarter schedulers should look at the num_vcores() and how much work is
144          * going on to make a decision about how many vcores to request. */
145         vcore_request(threads_ready);
146 }
147
148 /* For some reason not under its control, the uthread stopped running (compared
149  * to yield, which was caused by uthread/2LS code).
150  *
151  * The main case for this is if the vcore was preempted or if the vcore it was
152  * running on needed to stop.  You are given a uthread that looks like it took a
153  * notif, and had its context/silly state copied out to the uthread struct.
154  * (copyout_uthread).  Note that this will be called in the context (TLS) of the
155  * vcore that is losing the uthread.  If that vcore is running, it'll be in a
156  * preempt-event handling loop (not in your 2LS code).  If this is a big
157  * problem, I'll change it. */
158 void pth_thread_paused(struct uthread *uthread)
159 {
160         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
161         /* Remove from the active list.  Note that I don't particularly care about
162          * the active list.  We keep it around because it causes bugs and keeps us
163          * honest.  After all, some 2LS may want an active list */
164         mcs_pdr_lock(&queue_lock);
165         threads_active--;
166         TAILQ_REMOVE(&active_queue, pthread, next);
167         mcs_pdr_unlock(&queue_lock);
168         /* At this point, you could do something clever, like put it at the front of
169          * the runqueue, see if it was holding a lock, do some accounting, or
170          * whatever. */
171         uthread_runnable(uthread);
172 }
173
174 /* Restarts a uthread hanging off a syscall.  For the simple pthread case, we
175  * just make it runnable and let the main scheduler code handle it. */
176 static void restart_thread(struct syscall *sysc)
177 {
178         struct uthread *ut_restartee = (struct uthread*)sysc->u_data;
179         /* uthread stuff here: */
180         assert(ut_restartee);
181         assert(((struct pthread_tcb*)ut_restartee)->state == PTH_BLK_SYSC);
182         assert(ut_restartee->sysc == sysc);     /* set in uthread.c */
183         ut_restartee->sysc = 0; /* so we don't 'reblock' on this later */
184         uthread_runnable(ut_restartee);
185 }
186
187 /* This handler is usually run in vcore context, though I can imagine it being
188  * called by a uthread in some other threading library. */
189 static void pth_handle_syscall(struct event_msg *ev_msg, unsigned int ev_type)
190 {
191         struct syscall *sysc;
192         assert(in_vcore_context());
193         /* if we just got a bit (not a msg), it should be because the process is
194          * still an SCP and hasn't started using the MCP ev_q yet (using the simple
195          * ev_q and glibc's blockon) or because the bit is still set from an old
196          * ev_q (blocking syscalls from before we could enter vcore ctx).  Either
197          * way, just return.  Note that if you screwed up the pth ev_q and made it
198          * NO_MSG, you'll never notice (we used to assert(ev_msg)). */
199         if (!ev_msg)
200                 return;
201         /* It's a bug if we don't have a msg (we're handling a syscall bit-event) */
202         assert(ev_msg);
203         /* Get the sysc from the message and just restart it */
204         sysc = ev_msg->ev_arg3;
205         assert(sysc);
206         restart_thread(sysc);
207 }
208
209 /* This will be called from vcore context, after the current thread has yielded
210  * and is trying to block on sysc.  Need to put it somewhere were we can wake it
211  * up when the sysc is done.  For now, we'll have the kernel send us an event
212  * when the syscall is done. */
213 void pth_thread_blockon_sysc(struct uthread *uthread, void *syscall)
214 {
215         struct syscall *sysc = (struct syscall*)syscall;
216         int old_flags;
217         bool need_to_restart = FALSE;
218         uint32_t vcoreid = vcore_id();
219         /* rip from the active queue */
220         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
221         pthread->state = PTH_BLK_SYSC;
222         mcs_pdr_lock(&queue_lock);
223         threads_active--;
224         TAILQ_REMOVE(&active_queue, pthread, next);
225         mcs_pdr_unlock(&queue_lock);
226         /* Set things up so we can wake this thread up later */
227         sysc->u_data = uthread;
228         /* Register our vcore's syscall ev_q to hear about this syscall. */
229         if (!register_evq(sysc, sysc_mgmt[vcoreid].ev_q)) {
230                 /* Lost the race with the call being done.  The kernel won't send the
231                  * event.  Just restart him. */
232                 restart_thread(sysc);
233         }
234         /* GIANT WARNING: do not touch the thread after this point. */
235 }
236
237 void pth_thread_has_blocked(struct uthread *uthread, int flags)
238 {
239         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
240         /* could imagine doing something with the flags.  For now, we just treat all
241          * externally blocked reasons as 'MUTEX'.  Whatever we do here, we are
242          * mostly communicating to our future selves in pth_thread_runnable(), which
243          * gets called by whoever triggered this callback */
244         pthread->state = PTH_BLK_MUTEX;
245         /* Just for yucks: */
246         if (flags == UTH_EXT_BLK_JUSTICE)
247                 printf("For great justice!\n");
248 }
249
250 void pth_preempt_pending(void)
251 {
252 }
253
254 void pth_spawn_thread(uintptr_t pc_start, void *data)
255 {
256 }
257
258 /* Pthread interface stuff and helpers */
259
260 int pthread_attr_init(pthread_attr_t *a)
261 {
262         a->stacksize = PTHREAD_STACK_SIZE;
263         a->detachstate = PTHREAD_CREATE_JOINABLE;
264         return 0;
265 }
266
267 int pthread_attr_destroy(pthread_attr_t *a)
268 {
269         return 0;
270 }
271
272 static void __pthread_free_stack(struct pthread_tcb *pt)
273 {
274         assert(!munmap(pt->stacktop - pt->stacksize, pt->stacksize));
275 }
276
277 static int __pthread_allocate_stack(struct pthread_tcb *pt)
278 {
279         assert(pt->stacksize);
280         void* stackbot = mmap(0, pt->stacksize,
281                               PROT_READ|PROT_WRITE|PROT_EXEC,
282                               MAP_POPULATE|MAP_ANONYMOUS, -1, 0);
283         if (stackbot == MAP_FAILED)
284                 return -1; // errno set by mmap
285         pt->stacktop = stackbot + pt->stacksize;
286         return 0;
287 }
288
289 // Warning, this will reuse numbers eventually
290 static int get_next_pid(void)
291 {
292         static uint32_t next_pid = 0;
293         return next_pid++;
294 }
295
296 int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
297 {
298         attr->stacksize = stacksize;
299         return 0;
300 }
301 int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
302 {
303         *stacksize = attr->stacksize;
304         return 0;
305 }
306
307 /* Do whatever init you want.  At some point call uthread_lib_init() and pass it
308  * a uthread representing thread0 (int main()) */
309 static int pthread_lib_init(void)
310 {
311         /* Make sure this only runs once */
312         static bool initialized = FALSE;
313         if (initialized)
314                 return -1;
315         initialized = TRUE;
316         uintptr_t mmap_block;
317         mcs_pdr_init(&queue_lock);
318         /* Create a pthread_tcb for the main thread */
319         pthread_t t = (pthread_t)calloc(1, sizeof(struct pthread_tcb));
320         assert(t);
321         t->id = get_next_pid();
322         t->stacksize = USTACK_NUM_PAGES * PGSIZE;
323         t->stacktop = (void*)USTACKTOP;
324         t->detached = TRUE;
325         t->state = PTH_RUNNING;
326         t->joiner = 0;
327         assert(t->id == 0);
328         /* Put the new pthread (thread0) on the active queue */
329         mcs_pdr_lock(&queue_lock);      /* arguably, we don't need these (_S mode) */
330         threads_active++;
331         TAILQ_INSERT_TAIL(&active_queue, t, next);
332         mcs_pdr_unlock(&queue_lock);
333         /* Tell the kernel where and how we want to receive events.  This is just an
334          * example of what to do to have a notification turned on.  We're turning on
335          * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to
336          * send to vcore 0.  Note sys_self_notify will ignore the vcoreid and
337          * private preference.  Also note that enable_kevent() is just an example,
338          * and you probably want to use parts of event.c to do what you want. */
339         enable_kevent(EV_USER_IPI, 0, EVENT_IPI | EVENT_VCORE_PRIVATE);
340
341         /* Handle syscall events. */
342         ev_handlers[EV_SYSCALL] = pth_handle_syscall;
343         /* Set up the per-vcore structs to track outstanding syscalls */
344         sysc_mgmt = malloc(sizeof(struct sysc_mgmt) * max_vcores());
345         assert(sysc_mgmt);
346 #if 1   /* Independent ev_mboxes per vcore */
347         /* Get a block of pages for our per-vcore (but non-VCPD) ev_qs */
348         mmap_block = (uintptr_t)mmap(0, PGSIZE * 2 * max_vcores(),
349                                      PROT_WRITE | PROT_READ,
350                                      MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
351         assert(mmap_block);
352         /* Could be smarter and do this on demand (in case we don't actually want
353          * max_vcores()). */
354         for (int i = 0; i < max_vcores(); i++) {
355                 /* Each vcore needs to point to a non-VCPD ev_q */
356                 sysc_mgmt[i].ev_q = get_big_event_q_raw();
357                 sysc_mgmt[i].ev_q->ev_flags = EVENT_IPI | EVENT_INDIR | EVENT_FALLBACK;
358                 sysc_mgmt[i].ev_q->ev_vcore = i;
359                 ucq_init_raw(&sysc_mgmt[i].ev_q->ev_mbox->ev_msgs, 
360                              mmap_block + (2 * i    ) * PGSIZE, 
361                              mmap_block + (2 * i + 1) * PGSIZE); 
362         }
363         /* Technically, we should munmap and free what we've alloc'd, but the
364          * kernel will clean it up for us when we exit. */
365 #endif 
366 #if 0   /* One global ev_mbox, separate ev_q per vcore */
367         struct event_mbox *sysc_mbox = malloc(sizeof(struct event_mbox));
368         uintptr_t two_pages = (uintptr_t)mmap(0, PGSIZE * 2, PROT_WRITE | PROT_READ,
369                                               MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
370         printd("Global ucq: %08p\n", &sysc_mbox->ev_msgs);
371         assert(sysc_mbox);
372         assert(two_pages);
373         memset(sysc_mbox, 0, sizeof(struct event_mbox));
374         ucq_init_raw(&sysc_mbox->ev_msgs, two_pages, two_pages + PGSIZE);
375         for (int i = 0; i < max_vcores(); i++) {
376                 sysc_mgmt[i].ev_q = get_event_q();
377                 sysc_mgmt[i].ev_q->ev_flags = EVENT_IPI | EVENT_INDIR | EVENT_FALLBACK;
378                 sysc_mgmt[i].ev_q->ev_vcore = i;
379                 sysc_mgmt[i].ev_q->ev_mbox = sysc_mbox;
380         }
381 #endif
382         /* Initialize the uthread code (we're in _M mode after this).  Doing this
383          * last so that all the event stuff is ready when we're in _M mode.  Not a
384          * big deal one way or the other.  Note that vcore_init() hasn't happened
385          * yet, so if a 2LS somehow wants to have its init stuff use things like
386          * vcore stacks or TLSs, we'll need to change this. */
387         assert(!uthread_lib_init((struct uthread*)t));
388         return 0;
389 }
390
391 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
392                    void *(*start_routine)(void *), void *arg)
393 {
394         static bool first = TRUE;
395         if (first) {
396                 assert(!pthread_lib_init());
397                 first = FALSE;
398         }
399         /* Create the actual thread */
400         struct pthread_tcb *pthread;
401         pthread = (pthread_t)calloc(1, sizeof(struct pthread_tcb));
402         assert(pthread);
403         pthread->stacksize = PTHREAD_STACK_SIZE;        /* default */
404         pthread->state = PTH_CREATED;
405         pthread->id = get_next_pid();
406         pthread->detached = FALSE;                              /* default */
407         pthread->joiner = 0;
408         /* Respect the attributes */
409         if (attr) {
410                 if (attr->stacksize)                                    /* don't set a 0 stacksize */
411                         pthread->stacksize = attr->stacksize;
412                 if (attr->detachstate == PTHREAD_CREATE_DETACHED)
413                         pthread->detached = TRUE;
414         }
415         /* allocate a stack */
416         if (__pthread_allocate_stack(pthread))
417                 printf("We're fucked\n");
418         /* Set the u_tf to start up in __pthread_run, which will call the real
419          * start_routine and pass it the arg.  Note those aren't set until later in
420          * pthread_create(). */
421         init_user_tf(&pthread->uthread.utf, (long)&__pthread_run,
422                      (long)(pthread->stacktop));
423         pthread->start_routine = start_routine;
424         pthread->arg = arg;
425         /* Initialize the uthread */
426         uthread_init((struct uthread*)pthread);
427         uthread_runnable((struct uthread*)pthread);
428         *thread = pthread;
429         return 0;
430 }
431
432 /* Helper that all pthread-controlled yield paths call.  Just does some
433  * accounting.  This is another example of how the much-loathed (and loved)
434  * active queue is keeping us honest. */
435 static void __pthread_generic_yield(struct pthread_tcb *pthread)
436 {
437         mcs_pdr_lock(&queue_lock);
438         threads_active--;
439         TAILQ_REMOVE(&active_queue, pthread, next);
440         mcs_pdr_unlock(&queue_lock);
441 }
442
443 /* Callback/bottom half of join, called from __uthread_yield (vcore context).
444  * join_target is who we are trying to join on (and who is calling exit). */
445 static void __pth_join_cb(struct uthread *uthread, void *arg)
446 {
447         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
448         struct pthread_tcb *join_target = (struct pthread_tcb*)arg;
449         struct pthread_tcb *temp_pth = 0;
450         __pthread_generic_yield(pthread);
451         /* We're trying to join, yield til we get woken up */
452         pthread->state = PTH_BLK_JOINING;       /* could do this front-side */
453         /* Put ourselves in the join target's joiner slot.  If we get anything back,
454          * we lost the race and need to wake ourselves.  Syncs with __pth_exit_cb.*/
455         temp_pth = atomic_swap_ptr((void**)&join_target->joiner, pthread);
456         /* After that atomic swap, the pthread might be woken up (if it succeeded),
457          * so don't touch pthread again after that (this following if () is okay).*/
458         if (temp_pth) {         /* temp_pth != 0 means they exited first */
459                 assert(temp_pth == join_target);        /* Sanity */
460                 /* wake ourselves, not the exited one! */
461                 printd("[pth] %08p already exit, rewaking ourselves, joiner %08p\n",
462                        temp_pth, pthread);
463                 uthread_runnable(uthread);      /* wake ourselves */
464         }
465 }
466
467 int pthread_join(struct pthread_tcb *join_target, void **retval)
468 {
469         /* Not sure if this is the right semantics.  There is a race if we deref
470          * join_target and he is already freed (which would have happened if he was
471          * detached. */
472         if (join_target->detached) {
473                 printf("[pthread] trying to join on a detached pthread");
474                 return -1;
475         }
476         /* See if it is already done, to avoid the pain of a uthread_yield() (the
477          * early check is an optimization, pth_thread_yield() handles the race). */
478         if (!join_target->joiner) {
479                 uthread_yield(TRUE, __pth_join_cb, join_target);
480                 /* When we return/restart, the thread will be done */
481         } else {
482                 assert(join_target->joiner == join_target);     /* sanity check */
483         }
484         if (retval)
485                 *retval = join_target->retval;
486         free(join_target);
487         return 0;
488 }
489
490 /* Callback/bottom half of exit.  Syncs with __pth_join_cb.  Here's how it
491  * works: the slot for joiner is initially 0.  Joiners try to swap themselves
492  * into that spot.  Exiters try to put 'themselves' into it.  Whoever gets 0
493  * back won the race.  If the exiter lost the race, it must wake up the joiner
494  * (which was the value from temp_pth).  If the joiner lost the race, it must
495  * wake itself up, and for sanity reasons can ensure the value from temp_pth is
496  * the join target). */
497 static void __pth_exit_cb(struct uthread *uthread, void *junk)
498 {
499         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
500         struct pthread_tcb *temp_pth = 0;
501         __pthread_generic_yield(pthread);
502         /* Catch some bugs */
503         pthread->state = PTH_EXITING;
504         /* Destroy the pthread */
505         uthread_cleanup(uthread);
506         /* Cleanup, mirroring pthread_create() */
507         __pthread_free_stack(pthread);
508         /* TODO: race on detach state (see join) */
509         if (pthread->detached) {
510                 free(pthread);
511         } else {
512                 /* See if someone is joining on us.  If not, we're done (and the
513                  * joiner will wake itself when it saw us there instead of 0). */
514                 temp_pth = atomic_swap_ptr((void**)&pthread->joiner, pthread);
515                 if (temp_pth) {
516                         /* they joined before we exited, we need to wake them */
517                         printd("[pth] %08p exiting, waking joiner %08p\n",
518                                pthread, temp_pth);
519                         uthread_runnable((struct uthread*)temp_pth);
520                 }
521         }
522 }
523
524 void pthread_exit(void *ret)
525 {
526         struct pthread_tcb *pthread = pthread_self();
527         pthread->retval = ret;
528         uthread_yield(FALSE, __pth_exit_cb, 0);
529 }
530
531 /* Callback/bottom half of yield.  For those writing these pth callbacks, the
532  * minimum is call generic, set state (communicate with runnable), then do
533  * something that causes it to be runnable in the future (or right now). */
534 static void __pth_yield_cb(struct uthread *uthread, void *junk)
535 {
536         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
537         __pthread_generic_yield(pthread);
538         pthread->state = PTH_BLK_YIELDING;
539         /* just immediately restart it */
540         uthread_runnable(uthread);
541 }
542
543 /* Cooperative yielding of the processor, to allow other threads to run */
544 int pthread_yield(void)
545 {
546         uthread_yield(TRUE, __pth_yield_cb, 0);
547         return 0;
548 }
549
550 int pthread_mutexattr_init(pthread_mutexattr_t* attr)
551 {
552   attr->type = PTHREAD_MUTEX_DEFAULT;
553   return 0;
554 }
555
556 int pthread_mutexattr_destroy(pthread_mutexattr_t* attr)
557 {
558   return 0;
559 }
560
561 int pthread_attr_setdetachstate(pthread_attr_t *__attr, int __detachstate)
562 {
563         __attr->detachstate = __detachstate;
564         return 0;
565 }
566
567 int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type)
568 {
569   *type = attr ? attr->type : PTHREAD_MUTEX_DEFAULT;
570   return 0;
571 }
572
573 int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type)
574 {
575   if(type != PTHREAD_MUTEX_NORMAL)
576     return EINVAL;
577   attr->type = type;
578   return 0;
579 }
580
581 int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr)
582 {
583   m->attr = attr;
584   atomic_init(&m->lock, 0);
585   return 0;
586 }
587
588 /* Set *spun to 0 when calling this the first time.  It will yield after 'spins'
589  * calls.  Use this for adaptive mutexes and such. */
590 static inline void spin_to_sleep(unsigned int spins, unsigned int *spun)
591 {
592         if ((*spun)++ == spins) {
593                 pthread_yield();
594                 *spun = 0;
595         }
596 }
597
598 int pthread_mutex_lock(pthread_mutex_t* m)
599 {
600         unsigned int spinner = 0;
601         while(pthread_mutex_trylock(m))
602                 while(*(volatile size_t*)&m->lock) {
603                         cpu_relax();
604                         spin_to_sleep(PTHREAD_MUTEX_SPINS, &spinner);
605                 }
606         /* normally we'd need a wmb() and a wrmb() after locking, but the
607          * atomic_swap handles the CPU mb(), so just a cmb() is necessary. */
608         cmb();
609         return 0;
610 }
611
612 int pthread_mutex_trylock(pthread_mutex_t* m)
613 {
614   return atomic_swap(&m->lock, 1) == 0 ? 0 : EBUSY;
615 }
616
617 int pthread_mutex_unlock(pthread_mutex_t* m)
618 {
619   /* keep reads and writes inside the protected region */
620   rwmb();
621   wmb();
622   atomic_set(&m->lock, 0);
623   return 0;
624 }
625
626 int pthread_mutex_destroy(pthread_mutex_t* m)
627 {
628   return 0;
629 }
630
631 int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a)
632 {
633   c->attr = a;
634   memset(c->waiters,0,sizeof(c->waiters));
635   memset(c->in_use,0,sizeof(c->in_use));
636   c->next_waiter = 0;
637   return 0;
638 }
639
640 int pthread_cond_destroy(pthread_cond_t *c)
641 {
642   return 0;
643 }
644
645 int pthread_cond_broadcast(pthread_cond_t *c)
646 {
647   memset(c->waiters,0,sizeof(c->waiters));
648   return 0;
649 }
650
651 int pthread_cond_signal(pthread_cond_t *c)
652 {
653   int i;
654   for(i = 0; i < MAX_PTHREADS; i++)
655   {
656     if(c->waiters[i])
657     {
658       c->waiters[i] = 0;
659       break;
660     }
661   }
662   return 0;
663 }
664
665 int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
666 {
667   uint32_t old_waiter = c->next_waiter;
668   uint32_t my_waiter = c->next_waiter;
669   
670   //allocate a slot
671   while (atomic_swap_u32(& (c->in_use[my_waiter]), SLOT_IN_USE) == SLOT_IN_USE)
672   {
673     my_waiter = (my_waiter + 1) % MAX_PTHREADS;
674     assert (old_waiter != my_waiter);  // do not want to wrap around
675   }
676   c->waiters[my_waiter] = WAITER_WAITING;
677   c->next_waiter = (my_waiter+1) % MAX_PTHREADS;  // race on next_waiter but ok, because it is advisary
678
679   pthread_mutex_unlock(m);
680
681   volatile int* poll = &c->waiters[my_waiter];
682   while(*poll);
683   c->in_use[my_waiter] = SLOT_FREE;
684   pthread_mutex_lock(m);
685
686   return 0;
687 }
688
689 int pthread_condattr_init(pthread_condattr_t *a)
690 {
691   a = PTHREAD_PROCESS_PRIVATE;
692   return 0;
693 }
694
695 int pthread_condattr_destroy(pthread_condattr_t *a)
696 {
697   return 0;
698 }
699
700 int pthread_condattr_setpshared(pthread_condattr_t *a, int s)
701 {
702   a->pshared = s;
703   return 0;
704 }
705
706 int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
707 {
708   *s = a->pshared;
709   return 0;
710 }
711
712 pthread_t pthread_self()
713 {
714   return (struct pthread_tcb*)current_uthread;
715 }
716
717 int pthread_equal(pthread_t t1, pthread_t t2)
718 {
719   return t1 == t2;
720 }
721
722 int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
723 {
724   if (atomic_swap_u32(once_control, 1) == 0)
725     init_routine();
726   return 0;
727 }
728
729 int pthread_barrier_init(pthread_barrier_t* b, const pthread_barrierattr_t* a, int count)
730 {
731   b->nprocs = b->count = count;
732   b->sense = 0;
733   pthread_mutex_init(&b->pmutex, 0);
734   return 0;
735 }
736
737 int pthread_barrier_wait(pthread_barrier_t* b)
738 {
739   unsigned int spinner = 0;
740   int ls = !b->sense;
741
742   pthread_mutex_lock(&b->pmutex);
743   int count = --b->count;
744   pthread_mutex_unlock(&b->pmutex);
745
746   if(count == 0)
747   {
748     printd("Thread %d is last to hit the barrier, resetting...\n", pthread_self()->id);
749     b->count = b->nprocs;
750         wmb();
751     b->sense = ls;
752     return PTHREAD_BARRIER_SERIAL_THREAD;
753   }
754   else
755   {
756     while(b->sense != ls) {
757       cpu_relax();
758       spin_to_sleep(PTHREAD_BARRIER_SPINS, &spinner);
759     }
760     return 0;
761   }
762 }
763
764 int pthread_barrier_destroy(pthread_barrier_t* b)
765 {
766   pthread_mutex_destroy(&b->pmutex);
767   return 0;
768 }
769
770 int pthread_detach(pthread_t thread)
771 {
772         /* TODO: race on this state.  Someone could be trying to join now */
773         thread->detached = TRUE;
774         return 0;
775 }