pthread: Make pthread barriers 2LS-independent
[akaros.git] / user / pthread / pthread.c
1 #include <ros/trapframe.h>
2 #include "pthread.h"
3 #include <parlib/vcore.h>
4 #include <parlib/mcs.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <parlib/assert.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <parlib/parlib.h>
11 #include <ros/event.h>
12 #include <parlib/arch/atomic.h>
13 #include <parlib/arch/arch.h>
14 #include <sys/queue.h>
15 #include <sys/mman.h>
16 #include <parlib/event.h>
17 #include <parlib/ucq.h>
18 #include <parlib/signal.h>
19 #include <parlib/arch/trap.h>
20 #include <parlib/ros_debug.h>
21 #include <parlib/stdio.h>
22
23 struct pthread_queue ready_queue = TAILQ_HEAD_INITIALIZER(ready_queue);
24 struct pthread_queue active_queue = TAILQ_HEAD_INITIALIZER(active_queue);
25 struct mcs_pdr_lock queue_lock;
26 int threads_ready = 0;
27 int threads_active = 0;
28 atomic_t threads_total;
29 bool need_tls = TRUE;
30
31 /* Array of per-vcore structs to manage waiting on syscalls and handling
32  * overflow.  Init'd in pth_init(). */
33 struct sysc_mgmt *sysc_mgmt = 0;
34
35 /* Helper / local functions */
36 static int get_next_pid(void);
37 static inline void pthread_exit_no_cleanup(void *ret);
38
39 /* Pthread 2LS operations */
40 static void pth_sched_init(void);
41 static void pth_sched_entry(void);
42 static void pth_thread_runnable(struct uthread *uthread);
43 static void pth_thread_paused(struct uthread *uthread);
44 static void pth_thread_blockon_sysc(struct uthread *uthread, void *sysc);
45 static void pth_thread_has_blocked(struct uthread *uthread, int flags);
46 static void pth_thread_refl_fault(struct uthread *uth,
47                                   struct user_context *ctx);
48 static void pth_thread_exited(struct uthread *uth);
49 static struct uthread *pth_thread_create(void *(*func)(void *), void *arg);
50 static void pth_thread_bulk_runnable(uth_sync_t *wakees);
51
52 /* Event Handlers */
53 static void pth_handle_syscall(struct event_msg *ev_msg, unsigned int ev_type,
54                                void *data);
55
56 struct schedule_ops pthread_sched_ops = {
57         .sched_init = pth_sched_init,
58         .sched_entry = pth_sched_entry,
59         .thread_runnable = pth_thread_runnable,
60         .thread_paused = pth_thread_paused,
61         .thread_blockon_sysc = pth_thread_blockon_sysc,
62         .thread_has_blocked = pth_thread_has_blocked,
63         .thread_refl_fault = pth_thread_refl_fault,
64         .thread_exited = pth_thread_exited,
65         .thread_create = pth_thread_create,
66         .thread_bulk_runnable = pth_thread_bulk_runnable,
67 };
68
69 struct schedule_ops *sched_ops = &pthread_sched_ops;
70
71 /* Static helpers */
72 static void __pthread_free_stack(struct pthread_tcb *pt);
73 static int __pthread_allocate_stack(struct pthread_tcb *pt);
74 static void __pth_yield_cb(struct uthread *uthread, void *junk);
75
76 /* Called from vcore entry.  Options usually include restarting whoever was
77  * running there before or running a new thread.  Events are handled out of
78  * event.c (table of function pointers, stuff like that). */
79 static void __attribute__((noreturn)) pth_sched_entry(void)
80 {
81         uint32_t vcoreid = vcore_id();
82         if (current_uthread) {
83                 /* Prep the pthread to run any pending posix signal handlers registered
84          * via pthread_kill once it is restored. */
85                 uthread_prep_pending_signals(current_uthread);
86                 /* Run the thread itself */
87                 run_current_uthread();
88                 assert(0);
89         }
90         /* no one currently running, so lets get someone from the ready queue */
91         struct pthread_tcb *new_thread = NULL;
92         /* Try to get a thread.  If we get one, we'll break out and run it.  If not,
93          * we'll try to yield.  vcore_yield() might return, if we lost a race and
94          * had a new event come in, one that may make us able to get a new_thread */
95         do {
96                 handle_events(vcoreid);
97                 __check_preempt_pending(vcoreid);
98                 mcs_pdr_lock(&queue_lock);
99                 new_thread = TAILQ_FIRST(&ready_queue);
100                 if (new_thread) {
101                         TAILQ_REMOVE(&ready_queue, new_thread, tq_next);
102                         assert(new_thread->state == PTH_RUNNABLE);
103                         new_thread->state = PTH_RUNNING;
104                         TAILQ_INSERT_TAIL(&active_queue, new_thread, tq_next);
105                         threads_active++;
106                         threads_ready--;
107                         mcs_pdr_unlock(&queue_lock);
108                         /* If you see what looks like the same uthread running in multiple
109                          * places, your list might be jacked up.  Turn this on. */
110                         printd("[P] got uthread %08p on vc %d state %08p flags %08p\n",
111                                new_thread, vcoreid,
112                                ((struct uthread*)new_thread)->state,
113                                ((struct uthread*)new_thread)->flags);
114                         break;
115                 }
116                 mcs_pdr_unlock(&queue_lock);
117                 /* no new thread, try to yield */
118                 printd("[P] No threads, vcore %d is yielding\n", vcore_id());
119                 /* TODO: you can imagine having something smarter here, like spin for a
120                  * bit before yielding. */
121                 vcore_yield(FALSE);
122         } while (1);
123         /* Prep the pthread to run any pending posix signal handlers registered
124      * via pthread_kill once it is restored. */
125         uthread_prep_pending_signals((struct uthread*)new_thread);
126         /* Run the thread itself */
127         run_uthread((struct uthread*)new_thread);
128         assert(0);
129 }
130
131 /* Could move this, along with start_routine and arg, into the 2LSs */
132 static void __pthread_run(void)
133 {
134         struct pthread_tcb *me = pthread_self();
135         pthread_exit_no_cleanup(me->start_routine(me->arg));
136 }
137
138 /* GIANT WARNING: if you make any changes to this, also change the broadcast
139  * wakeups (cond var, barrier, etc) */
140 static void pth_thread_runnable(struct uthread *uthread)
141 {
142         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
143         /* At this point, the 2LS can see why the thread blocked and was woken up in
144          * the first place (coupling these things together).  On the yield path, the
145          * 2LS was involved and was able to set the state.  Now when we get the
146          * thread back, we can take a look. */
147         printd("pthread %08p runnable, state was %d\n", pthread, pthread->state);
148         switch (pthread->state) {
149                 case (PTH_CREATED):
150                 case (PTH_BLK_YIELDING):
151                 case (PTH_BLK_SYSC):
152                 case (PTH_BLK_PAUSED):
153                 case (PTH_BLK_MUTEX):
154                 case (PTH_BLK_MISC):
155                         /* can do whatever for each of these cases */
156                         break;
157                 default:
158                         panic("Odd state %d for pthread %08p\n", pthread->state, pthread);
159         }
160         pthread->state = PTH_RUNNABLE;
161         /* Insert the newly created thread into the ready queue of threads.
162          * It will be removed from this queue later when vcore_entry() comes up */
163         mcs_pdr_lock(&queue_lock);
164         /* Again, GIANT WARNING: if you change this, change batch wakeup code */
165         TAILQ_INSERT_TAIL(&ready_queue, pthread, tq_next);
166         threads_ready++;
167         mcs_pdr_unlock(&queue_lock);
168         /* Smarter schedulers should look at the num_vcores() and how much work is
169          * going on to make a decision about how many vcores to request. */
170         vcore_request_more(threads_ready);
171 }
172
173 /* For some reason not under its control, the uthread stopped running (compared
174  * to yield, which was caused by uthread/2LS code).
175  *
176  * The main case for this is if the vcore was preempted or if the vcore it was
177  * running on needed to stop.  You are given a uthread that looks like it took a
178  * notif, and had its context/silly state copied out to the uthread struct.
179  * (copyout_uthread).  Note that this will be called in the context (TLS) of the
180  * vcore that is losing the uthread.  If that vcore is running, it'll be in a
181  * preempt-event handling loop (not in your 2LS code).  If this is a big
182  * problem, I'll change it. */
183 static void pth_thread_paused(struct uthread *uthread)
184 {
185         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
186
187         __pthread_generic_yield(pthread);
188         /* communicate to pth_thread_runnable */
189         pthread->state = PTH_BLK_PAUSED;
190         /* At this point, you could do something clever, like put it at the front of
191          * the runqueue, see if it was holding a lock, do some accounting, or
192          * whatever. */
193         pth_thread_runnable(uthread);
194 }
195
196 /* Restarts a uthread hanging off a syscall.  For the simple pthread case, we
197  * just make it runnable and let the main scheduler code handle it. */
198 static void restart_thread(struct syscall *sysc)
199 {
200         struct uthread *ut_restartee = (struct uthread*)sysc->u_data;
201         /* uthread stuff here: */
202         assert(ut_restartee);
203         assert(((struct pthread_tcb*)ut_restartee)->state == PTH_BLK_SYSC);
204         assert(ut_restartee->sysc == sysc);     /* set in uthread.c */
205         ut_restartee->sysc = 0; /* so we don't 'reblock' on this later */
206         pth_thread_runnable(ut_restartee);
207 }
208
209 /* This handler is usually run in vcore context, though I can imagine it being
210  * called by a uthread in some other threading library. */
211 static void pth_handle_syscall(struct event_msg *ev_msg, unsigned int ev_type,
212                                void *data)
213 {
214         struct syscall *sysc;
215         assert(in_vcore_context());
216         /* if we just got a bit (not a msg), it should be because the process is
217          * still an SCP and hasn't started using the MCP ev_q yet (using the simple
218          * ev_q and glibc's blockon) or because the bit is still set from an old
219          * ev_q (blocking syscalls from before we could enter vcore ctx).  Either
220          * way, just return.  Note that if you screwed up the pth ev_q and made it
221          * NO_MSG, you'll never notice (we used to assert(ev_msg)). */
222         if (!ev_msg)
223                 return;
224         /* It's a bug if we don't have a msg (we're handling a syscall bit-event) */
225         assert(ev_msg);
226         /* Get the sysc from the message and just restart it */
227         sysc = ev_msg->ev_arg3;
228         assert(sysc);
229         restart_thread(sysc);
230 }
231
232 /* This will be called from vcore context, after the current thread has yielded
233  * and is trying to block on sysc.  Need to put it somewhere were we can wake it
234  * up when the sysc is done.  For now, we'll have the kernel send us an event
235  * when the syscall is done. */
236 static void pth_thread_blockon_sysc(struct uthread *uthread, void *syscall)
237 {
238         struct syscall *sysc = (struct syscall*)syscall;
239         int old_flags;
240         uint32_t vcoreid = vcore_id();
241         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
242
243         __pthread_generic_yield(pthread);
244         pthread->state = PTH_BLK_SYSC;
245         /* Set things up so we can wake this thread up later */
246         sysc->u_data = uthread;
247         /* Register our vcore's syscall ev_q to hear about this syscall. */
248         if (!register_evq(sysc, sysc_mgmt[vcoreid].ev_q)) {
249                 /* Lost the race with the call being done.  The kernel won't send the
250                  * event.  Just restart him. */
251                 restart_thread(sysc);
252         }
253         /* GIANT WARNING: do not touch the thread after this point. */
254 }
255
256 static void pth_thread_has_blocked(struct uthread *uthread, int flags)
257 {
258         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
259
260         __pthread_generic_yield(pthread);
261         /* Whatever we do here, we are mostly communicating to our future selves in
262          * pth_thread_runnable(), which gets called by whoever triggered this
263          * callback */
264         switch (flags) {
265         case UTH_EXT_BLK_YIELD:
266                 pthread->state = PTH_BLK_YIELDING;
267                 break;
268         case UTH_EXT_BLK_MUTEX:
269                 pthread->state = PTH_BLK_MUTEX;
270                 break;
271         default:
272                 pthread->state = PTH_BLK_MISC;
273         };
274 }
275
276 static void __signal_and_restart(struct uthread *uthread,
277                                  int signo, int code, void *addr)
278 {
279         uthread_prep_signal_from_fault(uthread, signo, code, addr);
280         pth_thread_runnable(uthread);
281 }
282
283 static void handle_div_by_zero(struct uthread *uthread, unsigned int err,
284                                unsigned long aux)
285 {
286         __signal_and_restart(uthread, SIGFPE, FPE_INTDIV, (void*)aux);
287 }
288
289 static void handle_gp_fault(struct uthread *uthread, unsigned int err,
290                             unsigned long aux)
291 {
292         __signal_and_restart(uthread, SIGSEGV, SEGV_ACCERR, (void*)aux);
293 }
294
295 static void handle_page_fault(struct uthread *uthread, unsigned int err,
296                               unsigned long aux)
297 {
298         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
299         if (!(err & PF_VMR_BACKED)) {
300                 __signal_and_restart(uthread, SIGSEGV, SEGV_MAPERR, (void*)aux);
301         } else {
302                 syscall_async(&uthread->local_sysc, SYS_populate_va, aux, 1);
303                 __block_uthread_on_async_sysc(uthread);
304         }
305 }
306
307 static void pth_thread_refl_hw_fault(struct uthread *uthread,
308                                      unsigned int trap_nr,
309                                      unsigned int err, unsigned long aux)
310 {
311         struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
312
313         __pthread_generic_yield(pthread);
314         pthread->state = PTH_BLK_SYSC;
315
316         switch (trap_nr) {
317         case HW_TRAP_DIV_ZERO:
318                 handle_div_by_zero(uthread, err, aux);
319                 break;
320         case HW_TRAP_GP_FAULT:
321                 handle_gp_fault(uthread, err, aux);
322                 break;
323         case HW_TRAP_PAGE_FAULT:
324                 handle_page_fault(uthread, err, aux);
325                 break;
326         default:
327                 printf("Pthread has unhandled fault: %d, err: %d, aux: %p\n",
328                        trap_nr, err, aux);
329                 /* Note that uthread.c already copied out our ctx into the uth
330                  * struct */
331                 print_user_context(&uthread->u_ctx);
332                 printf("Turn on printx to spew unhandled, malignant trap info\n");
333                 exit(-1);
334         }
335 }
336
337 static void pth_thread_refl_fault(struct uthread *uth,
338                                   struct user_context *ctx)
339 {
340         switch (ctx->type) {
341         case ROS_HW_CTX:
342                 pth_thread_refl_hw_fault(uth, __arch_refl_get_nr(ctx),
343                                          __arch_refl_get_err(ctx),
344                                          __arch_refl_get_aux(ctx));
345                 break;
346         default:
347                 assert(0);
348         }
349 }
350
351 static void pth_thread_exited(struct uthread *uth)
352 {
353         struct pthread_tcb *pthread = (struct pthread_tcb*)uth;
354
355         __pthread_generic_yield(pthread);
356         /* Catch some bugs */
357         pthread->state = PTH_EXITING;
358         /* Destroy the pthread */
359         uthread_cleanup(uth);
360         /* Cleanup, mirroring pthread_create() */
361         __pthread_free_stack(pthread);
362         /* If we were the last pthread, we exit for the whole process.  Keep in mind
363          * that thread0 is counted in this, so this will only happen if that thread
364          * calls pthread_exit(). */
365         if ((atomic_fetch_and_add(&threads_total, -1) == 1))
366                 exit(0);
367 }
368
369 /* Careful, if someone used the pthread_need_tls() hack to turn off TLS, it will
370  * also be turned off for these threads. */
371 static struct uthread *pth_thread_create(void *(*func)(void *), void *arg)
372 {
373         struct pthread_tcb *pth;
374         int ret;
375
376         ret = pthread_create(&pth, NULL, func, arg);
377         return ret == 0 ? (struct uthread*)pth : NULL;
378 }
379
380 static void pth_thread_bulk_runnable(uth_sync_t *wakees)
381 {
382         struct uthread *uth_i;
383         struct pthread_tcb *pth_i;
384
385         /* Amortize the lock grabbing over all restartees */
386         mcs_pdr_lock(&queue_lock);
387         while ((uth_i = __uth_sync_get_next(wakees))) {
388                 pth_i = (struct pthread_tcb*)uth_i;
389                 pth_i->state = PTH_RUNNABLE;
390                 TAILQ_INSERT_TAIL(&ready_queue, pth_i, tq_next);
391                 threads_ready++;
392         }
393         mcs_pdr_unlock(&queue_lock);
394         vcore_request_more(threads_ready);
395 }
396
397 /* Akaros pthread extensions / hacks */
398
399 /* Careful using this - glibc and gcc are likely to use TLS without you knowing
400  * it. */
401 void pthread_need_tls(bool need)
402 {
403         need_tls = need;
404 }
405
406 /* Pthread interface stuff and helpers */
407
408 int pthread_attr_init(pthread_attr_t *a)
409 {
410         a->stackaddr = 0;
411         a->stacksize = PTHREAD_STACK_SIZE;
412         a->detachstate = PTHREAD_CREATE_JOINABLE;
413         /* priority and policy should be set by anyone changing inherit. */
414         a->sched_priority = 0;
415         a->sched_policy = 0;
416         a->sched_inherit = PTHREAD_INHERIT_SCHED;
417         return 0;
418 }
419
420 int pthread_attr_destroy(pthread_attr_t *a)
421 {
422         return 0;
423 }
424
425 static void __pthread_free_stack(struct pthread_tcb *pt)
426 {
427         int ret = munmap(pt->stacktop - pt->stacksize, pt->stacksize);
428         assert(!ret);
429 }
430
431 static int __pthread_allocate_stack(struct pthread_tcb *pt)
432 {
433         int force_a_page_fault;
434         assert(pt->stacksize);
435         void* stackbot = mmap(0, pt->stacksize,
436                               PROT_READ|PROT_WRITE|PROT_EXEC,
437                               MAP_ANONYMOUS, -1, 0);
438         if (stackbot == MAP_FAILED)
439                 return -1; // errno set by mmap
440         pt->stacktop = stackbot + pt->stacksize;
441         /* Want the top of the stack populated, but not the rest of the stack;
442          * that'll grow on demand (up to pt->stacksize) */
443         force_a_page_fault = ACCESS_ONCE(*(int*)(pt->stacktop - sizeof(int)));
444         return 0;
445 }
446
447 // Warning, this will reuse numbers eventually
448 static int get_next_pid(void)
449 {
450         static uint32_t next_pid = 0;
451         return next_pid++;
452 }
453
454 int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
455 {
456         attr->stacksize = stacksize;
457         return 0;
458 }
459
460 int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
461 {
462         *stacksize = attr->stacksize;
463         return 0;
464 }
465
466 int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
467 {
468         attr->guardsize = guardsize;
469         return 0;
470 }
471
472 int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize)
473 {
474         *guardsize = attr->guardsize;
475         return 0;
476 }
477
478 int pthread_attr_getstack(const pthread_attr_t *__restrict __attr,
479                                                    void **__stackaddr, size_t *__stacksize)
480 {
481         *__stackaddr = __attr->stackaddr;
482         *__stacksize = __attr->stacksize;
483         return 0;
484 }
485
486 int pthread_getattr_np(pthread_t __th, pthread_attr_t *__attr)
487 {
488         struct uthread *uth = (struct uthread*)__th;
489
490         __attr->stackaddr = __th->stacktop - __th->stacksize;
491         __attr->stacksize = __th->stacksize;
492         if (atomic_read(&uth->join_ctl.state) == UTH_JOIN_DETACHED)
493                 __attr->detachstate = PTHREAD_CREATE_DETACHED;
494         else
495                 __attr->detachstate = PTHREAD_CREATE_JOINABLE;
496         return 0;
497 }
498
499 /* Do whatever init you want.  At some point call uthread_2ls_init() and pass it
500  * a uthread representing thread0 (int main()) */
501 void pth_sched_init(void)
502 {
503         uintptr_t mmap_block;
504         struct pthread_tcb *t;
505         int ret;
506
507         mcs_pdr_init(&queue_lock);
508         /* Create a pthread_tcb for the main thread */
509         ret = posix_memalign((void**)&t, __alignof__(struct pthread_tcb),
510                              sizeof(struct pthread_tcb));
511         assert(!ret);
512         memset(t, 0, sizeof(struct pthread_tcb));       /* aggressively 0 for bugs */
513         t->id = get_next_pid();
514         t->stacksize = USTACK_NUM_PAGES * PGSIZE;
515         t->stacktop = (void*)USTACKTOP;
516         t->state = PTH_RUNNING;
517         /* implies that sigmasks are longs, which they are. */
518         assert(t->id == 0);
519         t->sched_policy = SCHED_FIFO;
520         t->sched_priority = 0;
521         SLIST_INIT(&t->cr_stack);
522         /* Put the new pthread (thread0) on the active queue */
523         mcs_pdr_lock(&queue_lock);
524         threads_active++;
525         TAILQ_INSERT_TAIL(&active_queue, t, tq_next);
526         mcs_pdr_unlock(&queue_lock);
527         /* Tell the kernel where and how we want to receive events.  This is just an
528          * example of what to do to have a notification turned on.  We're turning on
529          * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to
530          * send to vcore 0.  Note sys_self_notify will ignore the vcoreid and
531          * private preference.  Also note that enable_kevent() is just an example,
532          * and you probably want to use parts of event.c to do what you want. */
533         enable_kevent(EV_USER_IPI, 0, EVENT_IPI | EVENT_VCORE_PRIVATE);
534         /* Set up the per-vcore structs to track outstanding syscalls */
535         sysc_mgmt = malloc(sizeof(struct sysc_mgmt) * max_vcores());
536         assert(sysc_mgmt);
537 #if 1   /* Independent ev_mboxes per vcore */
538         /* Get a block of pages for our per-vcore (but non-VCPD) ev_qs */
539         mmap_block = (uintptr_t)mmap(0, PGSIZE * 2 * max_vcores(),
540                                      PROT_WRITE | PROT_READ,
541                                      MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
542         assert(mmap_block);
543         /* Could be smarter and do this on demand (in case we don't actually want
544          * max_vcores()). */
545         for (int i = 0; i < max_vcores(); i++) {
546                 /* Each vcore needs to point to a non-VCPD ev_q */
547                 sysc_mgmt[i].ev_q = get_eventq_raw();
548                 sysc_mgmt[i].ev_q->ev_flags = EVENT_IPI | EVENT_INDIR |
549                                               EVENT_SPAM_INDIR | EVENT_WAKEUP;
550                 sysc_mgmt[i].ev_q->ev_vcore = i;
551                 sysc_mgmt[i].ev_q->ev_mbox->type = EV_MBOX_UCQ;
552                 ucq_init_raw(&sysc_mgmt[i].ev_q->ev_mbox->ucq,
553                              mmap_block + (2 * i    ) * PGSIZE, 
554                              mmap_block + (2 * i + 1) * PGSIZE); 
555         }
556         /* Technically, we should munmap and free what we've alloc'd, but the
557          * kernel will clean it up for us when we exit. */
558 #endif 
559 #if 0   /* One global ev_mbox, separate ev_q per vcore */
560         struct event_mbox *sysc_mbox = malloc(sizeof(struct event_mbox));
561         uintptr_t two_pages = (uintptr_t)mmap(0, PGSIZE * 2, PROT_WRITE | PROT_READ,
562                                               MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
563         printd("Global ucq: %08p\n", &sysc_mbox->ev_msgs);
564         assert(sysc_mbox);
565         assert(two_pages);
566         memset(sysc_mbox, 0, sizeof(struct event_mbox));
567         sysc_mbox->type = EV_MBOX_UCQ;
568         ucq_init_raw(&sysc_mbox->ucq, two_pages, two_pages + PGSIZE);
569         for (int i = 0; i < max_vcores(); i++) {
570                 sysc_mgmt[i].ev_q = get_eventq_slim();
571                 sysc_mgmt[i].ev_q->ev_flags = EVENT_IPI | EVENT_INDIR |
572                                               EVENT_SPAM_INDIR | EVENT_WAKEUP;
573                 sysc_mgmt[i].ev_q->ev_vcore = i;
574                 sysc_mgmt[i].ev_q->ev_mbox = sysc_mbox;
575         }
576 #endif
577         uthread_2ls_init((struct uthread*)t, pth_handle_syscall, NULL);
578         atomic_init(&threads_total, 1);                 /* one for thread0 */
579 }
580
581 /* Make sure our scheduler runs inside an MCP rather than an SCP. */
582 void pthread_mcp_init()
583 {
584         /* Prevent this from happening more than once. */
585         parlib_init_once_racy(return);
586
587         uthread_mcp_init();
588         /* From here forward we are an MCP running on vcore 0. Could consider doing
589          * other pthread specific initialization based on knowing we are an mcp
590          * after this point. */
591 }
592
593 int __pthread_create(pthread_t *thread, const pthread_attr_t *attr,
594                      void *(*start_routine)(void *), void *arg)
595 {
596         struct uth_thread_attr uth_attr = {0};
597         struct pthread_tcb *parent;
598         struct pthread_tcb *pthread;
599         int ret;
600
601         /* For now, unconditionally become an mcp when creating a pthread (if not
602          * one already). This may change in the future once we support 2LSs in an
603          * SCP. */
604         pthread_mcp_init();
605
606         parent = (struct pthread_tcb*)current_uthread;
607         ret = posix_memalign((void**)&pthread, __alignof__(struct pthread_tcb),
608                              sizeof(struct pthread_tcb));
609         assert(!ret);
610         memset(pthread, 0, sizeof(struct pthread_tcb)); /* aggressively 0 for bugs*/
611         pthread->stacksize = PTHREAD_STACK_SIZE;        /* default */
612         pthread->state = PTH_CREATED;
613         pthread->id = get_next_pid();
614         /* Might override these later, based on attr && EXPLICIT_SCHED */
615         pthread->sched_policy = parent->sched_policy;
616         pthread->sched_priority = parent->sched_priority;
617         SLIST_INIT(&pthread->cr_stack);
618         /* Respect the attributes */
619         if (attr) {
620                 if (attr->stacksize)                                    /* don't set a 0 stacksize */
621                         pthread->stacksize = attr->stacksize;
622                 if (attr->detachstate == PTHREAD_CREATE_DETACHED)
623                         uth_attr.detached = TRUE;
624                 if (attr->sched_inherit == PTHREAD_EXPLICIT_SCHED) {
625                         pthread->sched_policy = attr->sched_policy;
626                         pthread->sched_priority = attr->sched_priority;
627                 }
628         }
629         /* allocate a stack */
630         if (__pthread_allocate_stack(pthread))
631                 printf("We're fucked\n");
632         /* Set the u_tf to start up in __pthread_run, which will call the real
633          * start_routine and pass it the arg.  Note those aren't set until later in
634          * pthread_create(). */
635         init_user_ctx(&pthread->uthread.u_ctx, (uintptr_t)&__pthread_run,
636                       (uintptr_t)(pthread->stacktop));
637         pthread->start_routine = start_routine;
638         pthread->arg = arg;
639         /* Initialize the uthread */
640         if (need_tls)
641                 uth_attr.want_tls = TRUE;
642         uthread_init((struct uthread*)pthread, &uth_attr);
643         *thread = pthread;
644         atomic_inc(&threads_total);
645         return 0;
646 }
647
648 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
649                    void *(*start_routine)(void *), void *arg)
650 {
651         if (!__pthread_create(thread, attr, start_routine, arg))
652                 pth_thread_runnable((struct uthread*)*thread);
653         return 0;
654 }
655
656 /* Helper that all pthread-controlled yield paths call.  Just does some
657  * accounting.  This is another example of how the much-loathed (and loved)
658  * active queue is keeping us honest.  Need to export for sem and friends. */
659 void __pthread_generic_yield(struct pthread_tcb *pthread)
660 {
661         mcs_pdr_lock(&queue_lock);
662         threads_active--;
663         TAILQ_REMOVE(&active_queue, pthread, tq_next);
664         mcs_pdr_unlock(&queue_lock);
665 }
666
667 int pthread_join(struct pthread_tcb *join_target, void **retval)
668 {
669         uthread_join((struct uthread*)join_target, retval);
670         return 0;
671 }
672
673 static inline void pthread_exit_no_cleanup(void *ret)
674 {
675         struct pthread_tcb *pthread = pthread_self();
676
677         while (SLIST_FIRST(&pthread->cr_stack))
678                 pthread_cleanup_pop(FALSE);
679         destroy_dtls();
680         uth_2ls_thread_exit(ret);
681 }
682
683 void pthread_exit(void *ret)
684 {
685         struct pthread_tcb *pthread = pthread_self();
686         while (SLIST_FIRST(&pthread->cr_stack))
687                 pthread_cleanup_pop(TRUE);
688         pthread_exit_no_cleanup(ret);
689 }
690
691 /* Cooperative yielding of the processor, to allow other threads to run */
692 int pthread_yield(void)
693 {
694         uthread_sched_yield();
695         return 0;
696 }
697
698 int pthread_cancel(pthread_t __th)
699 {
700         fprintf(stderr, "Unsupported %s!", __FUNCTION__);
701         abort();
702         return -1;
703 }
704
705 void pthread_cleanup_push(void (*routine)(void *), void *arg)
706 {
707         struct pthread_tcb *p = pthread_self();
708         struct pthread_cleanup_routine *r = malloc(sizeof(*r));
709         r->routine = routine;
710         r->arg = arg;
711         SLIST_INSERT_HEAD(&p->cr_stack, r, cr_next);
712 }
713
714 void pthread_cleanup_pop(int execute)
715 {
716         struct pthread_tcb *p = pthread_self();
717         struct pthread_cleanup_routine *r = SLIST_FIRST(&p->cr_stack);
718         if (r) {
719                 SLIST_REMOVE_HEAD(&p->cr_stack, cr_next);
720                 if (execute)
721                         r->routine(r->arg);
722                 free(r);
723         }
724 }
725
726 int pthread_mutexattr_init(pthread_mutexattr_t *attr)
727 {
728         attr->type = PTHREAD_MUTEX_DEFAULT;
729         return 0;
730 }
731
732 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
733 {
734         return 0;
735 }
736
737 int pthread_attr_setdetachstate(pthread_attr_t *__attr, int __detachstate)
738 {
739         __attr->detachstate = __detachstate;
740         return 0;
741 }
742
743 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
744 {
745         *type = attr ? attr->type : PTHREAD_MUTEX_DEFAULT;
746         return 0;
747 }
748
749 static bool __pthread_mutex_type_ok(int type)
750 {
751         switch (type) {
752         case PTHREAD_MUTEX_NORMAL:
753         case PTHREAD_MUTEX_RECURSIVE:
754                 return TRUE;
755         }
756         return FALSE;
757 }
758
759 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
760 {
761         if (!__pthread_mutex_type_ok(type))
762                 return EINVAL;
763         attr->type = type;
764         return 0;
765 }
766
767 int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *attr)
768 {
769         if (!__pthread_mutex_type_ok(attr->type))
770                 return EINVAL;
771         m->type = attr->type;
772         switch (m->type) {
773         case PTHREAD_MUTEX_NORMAL:
774                 uth_mutex_init(&m->mtx);
775                 break;
776         case PTHREAD_MUTEX_RECURSIVE:
777                 uth_recurse_mutex_init(&m->r_mtx);
778                 break;
779         }
780         return 0;
781 }
782
783 int pthread_mutex_lock(pthread_mutex_t *m)
784 {
785         switch (m->type) {
786         case PTHREAD_MUTEX_NORMAL:
787                 uth_mutex_lock(&m->mtx);
788                 break;
789         case PTHREAD_MUTEX_RECURSIVE:
790                 uth_recurse_mutex_lock(&m->r_mtx);
791                 break;
792         default:
793                 panic("Bad pth mutex type %d!", m->type);
794         }
795         return 0;
796 }
797
798 int pthread_mutex_trylock(pthread_mutex_t *m)
799 {
800         bool got_it;
801
802         switch (m->type) {
803         case PTHREAD_MUTEX_NORMAL:
804                 got_it = uth_mutex_trylock(&m->mtx);
805                 break;
806         case PTHREAD_MUTEX_RECURSIVE:
807                 got_it = uth_recurse_mutex_trylock(&m->r_mtx);
808                 break;
809         default:
810                 panic("Bad pth mutex type %d!", m->type);
811         }
812         return got_it ? 0 : EBUSY;
813 }
814
815 int pthread_mutex_unlock(pthread_mutex_t *m)
816 {
817         switch (m->type) {
818         case PTHREAD_MUTEX_NORMAL:
819                 uth_mutex_unlock(&m->mtx);
820                 break;
821         case PTHREAD_MUTEX_RECURSIVE:
822                 uth_recurse_mutex_unlock(&m->r_mtx);
823                 break;
824         default:
825                 panic("Bad pth mutex type %d!", m->type);
826         }
827         return 0;
828 }
829
830 int pthread_mutex_destroy(pthread_mutex_t *m)
831 {
832         switch (m->type) {
833         case PTHREAD_MUTEX_NORMAL:
834                 uth_mutex_destroy(&m->mtx);
835                 break;
836         case PTHREAD_MUTEX_RECURSIVE:
837                 uth_recurse_mutex_destroy(&m->r_mtx);
838                 break;
839         default:
840                 panic("Bad pth mutex type %d!", m->type);
841         }
842         return 0;
843 }
844
845 int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime)
846 {
847         bool got_it;
848
849         switch (m->type) {
850         case PTHREAD_MUTEX_NORMAL:
851                 got_it = uth_mutex_timed_lock(&m->mtx, abstime);
852                 break;
853         case PTHREAD_MUTEX_RECURSIVE:
854                 got_it = uth_recurse_mutex_timed_lock(&m->r_mtx, abstime);
855                 break;
856         default:
857                 panic("Bad pth mutex type %d!", m->type);
858         }
859         return got_it ? 0 : ETIMEDOUT;
860 }
861
862 int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a)
863 {
864         if (a) {
865                 if (a->pshared != PTHREAD_PROCESS_PRIVATE)
866                         fprintf(stderr, "pthreads only supports private condvars");
867                 /* We also ignore clock_id */
868         }
869         uth_cond_var_init(c);
870         return 0;
871 }
872
873 int pthread_cond_destroy(pthread_cond_t *c)
874 {
875         uth_cond_var_destroy(c);
876         return 0;
877 }
878
879 int pthread_cond_broadcast(pthread_cond_t *c)
880 {
881         uth_cond_var_broadcast(c);
882         return 0;
883 }
884
885 /* spec says this needs to work regardless of whether or not it holds the mutex
886  * already. */
887 int pthread_cond_signal(pthread_cond_t *c)
888 {
889         uth_cond_var_signal(c);
890         return 0;
891 }
892
893 int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
894 {
895         switch (m->type) {
896         case PTHREAD_MUTEX_NORMAL:
897                 uth_cond_var_wait(c, &m->mtx);
898                 break;
899         case PTHREAD_MUTEX_RECURSIVE:
900                 uth_cond_var_wait_recurse(c, &m->r_mtx);
901                 break;
902         default:
903                 panic("Bad pth mutex type %d!", m->type);
904         }
905         return 0;
906 }
907
908 int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m,
909                            const struct timespec *abstime)
910 {
911         bool got_it;
912
913         switch (m->type) {
914         case PTHREAD_MUTEX_NORMAL:
915                 got_it = uth_cond_var_timed_wait(c, &m->mtx, abstime);
916                 break;
917         case PTHREAD_MUTEX_RECURSIVE:
918                 got_it = uth_cond_var_timed_wait_recurse(c, &m->r_mtx, abstime);
919                 break;
920         default:
921                 panic("Bad pth mutex type %d!", m->type);
922         }
923         return got_it ? 0 : ETIMEDOUT;
924 }
925
926 int pthread_condattr_init(pthread_condattr_t *a)
927 {
928         a->pshared = PTHREAD_PROCESS_PRIVATE;
929         a->clock = 0;
930         return 0;
931 }
932
933 int pthread_condattr_destroy(pthread_condattr_t *a)
934 {
935         return 0;
936 }
937
938 int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
939 {
940         *s = a->pshared;
941         return 0;
942 }
943
944 int pthread_condattr_setpshared(pthread_condattr_t *a, int s)
945 {
946         a->pshared = s;
947         if (s == PTHREAD_PROCESS_SHARED) {
948                 printf("Warning: we don't do shared pthread condvars btw diff MCPs\n");
949                 return -1;
950         }
951         return 0;
952 }
953
954 int pthread_condattr_getclock(const pthread_condattr_t *attr,
955                               clockid_t *clock_id)
956 {
957         *clock_id = attr->clock;
958         return 0;
959 }
960
961 int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id)
962 {
963         printf("Warning: we don't do pthread condvar clock stuff\n");
964         attr->clock = clock_id;
965         return 0;
966 }
967
968 int pthread_rwlock_init(pthread_rwlock_t *rwl, const pthread_rwlockattr_t *a)
969 {
970         uth_rwlock_init(rwl);
971         return 0;
972 }
973
974 int pthread_rwlock_destroy(pthread_rwlock_t *rwl)
975 {
976         uth_rwlock_destroy(rwl);
977         return 0;
978 }
979
980 int pthread_rwlock_rdlock(pthread_rwlock_t *rwl)
981 {
982         uth_rwlock_rdlock(rwl);
983         return 0;
984 }
985
986 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwl)
987 {
988         return uth_rwlock_try_rdlock(rwl) ? 0 : EBUSY;
989 }
990
991 int pthread_rwlock_wrlock(pthread_rwlock_t *rwl)
992 {
993         uth_rwlock_wrlock(rwl);
994         return 0;
995 }
996
997 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwl)
998 {
999         return uth_rwlock_try_wrlock(rwl) ? 0 : EBUSY;
1000 }
1001
1002 int pthread_rwlock_unlock(pthread_rwlock_t *rwl)
1003 {
1004         uth_rwlock_unlock(rwl);
1005         return 0;
1006 }
1007
1008 pthread_t pthread_self(void)
1009 {
1010         return (struct pthread_tcb*)uthread_self();
1011 }
1012
1013 int pthread_equal(pthread_t t1, pthread_t t2)
1014 {
1015   return t1 == t2;
1016 }
1017
1018 int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
1019 {
1020         /* pthread_once's init routine doesn't take an argument, like parlibs.  This
1021          * means the func will be run with an argument passed to it, but it'll be
1022          * ignored. */
1023         parlib_run_once(once_control, (void (*)(void *))init_routine, NULL);
1024         /* The return for pthread_once isn't an error from the function, it's just
1025          * an overall error.  Note pthread's init_routine() has no return value. */
1026         return 0;
1027 }
1028
1029 int pthread_barrier_init(pthread_barrier_t *b,
1030                          const pthread_barrierattr_t *a, int count)
1031 {
1032         b->total_threads = count;
1033         b->sense = 0;
1034         atomic_set(&b->count, count);
1035         spin_pdr_init(&b->lock);
1036         __uth_sync_init(&b->waiters);
1037         b->nr_waiters = 0;
1038         return 0;
1039 }
1040
1041 struct barrier_junk {
1042         pthread_barrier_t                               *b;
1043         int                                                             ls;
1044 };
1045
1046 /* Helper for spinning sync, returns TRUE if it is okay to keep spinning.
1047  *
1048  * Alternatives include:
1049  *              old_count <= num_vcores() (barrier code, pass in old_count as *state,
1050  *                                         but this only works if every awake pthread
1051  *                                         will belong to the barrier).
1052  *              just spin for a bit       (use *state to track spins)
1053  *              FALSE                     (always is safe)
1054  *              etc...
1055  * 'threads_ready' isn't too great since sometimes it'll be non-zero when it is
1056  * about to become 0.  We really want "I have no threads waiting to run that
1057  * aren't going to run on their on unless this core yields instead of spins". */
1058 /* TODO: consider making this a 2LS op */
1059 static inline bool safe_to_spin(unsigned int *state)
1060 {
1061         return (*state)++ % PTHREAD_BARRIER_SPINS;
1062 }
1063
1064 /* Callback/bottom half of barrier. */
1065 static void __pth_barrier_cb(struct uthread *uthread, void *junk)
1066 {
1067         pthread_barrier_t *b = ((struct barrier_junk*)junk)->b;
1068         int ls = ((struct barrier_junk*)junk)->ls;
1069
1070         uthread_has_blocked(uthread, UTH_EXT_BLK_MUTEX);
1071         /* TODO: if we used a trylock, we could bail as soon as we see sense */
1072         spin_pdr_lock(&b->lock);
1073         /* If sense is ls (our free value), we lost the race and shouldn't sleep */
1074         if (b->sense == ls) {
1075                 spin_pdr_unlock(&b->lock);
1076                 uthread_runnable(uthread);
1077                 return;
1078         }
1079         /* otherwise, we sleep */
1080         __uth_sync_enqueue(uthread, &b->waiters);
1081         b->nr_waiters++;
1082         spin_pdr_unlock(&b->lock);
1083 }
1084
1085 /* We assume that the same threads participating in the barrier this time will
1086  * also participate next time.  Imagine a thread stopped right after its fetch
1087  * and add - we know it is coming through eventually.  We finish and change the
1088  * sense, which should allow the delayed thread to eventually break through.
1089  * But if another n threads come in first, we'll set the sense back to the old
1090  * value, thereby catching the delayed thread til the next barrier. 
1091  *
1092  * A note on preemption: if any thread gets preempted and it is never dealt
1093  * with, eventually we deadlock, with all threads waiting on the last one to
1094  * enter (and any stragglers from one run will be the last in the next run).
1095  * One way or another, we need to handle preemptions.  The current 2LS requests
1096  * an IPI for a preempt, so we'll be fine.  Any other strategies will need to
1097  * consider how barriers work.  Any time we sleep, we'll be okay (since that
1098  * frees up our core to handle preemptions/run other threads. */
1099 int pthread_barrier_wait(pthread_barrier_t *b)
1100 {
1101         unsigned int spin_state = 0;
1102         int ls = !b->sense;     /* when b->sense is the value we read, then we're free*/
1103         uth_sync_t restartees;
1104         struct uthread *uth_i;
1105         struct barrier_junk local_junk;
1106         
1107         long old_count = atomic_fetch_and_add(&b->count, -1);
1108
1109         if (old_count == 1) {
1110                 /* TODO: we might want to grab the lock right away, so a few short
1111                  * circuit faster? */
1112                 atomic_set(&b->count, b->total_threads);
1113                 /* we still need to maintain ordering btw count and sense, in case
1114                  * another thread doesn't sleep (if we wrote sense first, they could
1115                  * break out, race around, and muck with count before it is time) */
1116                 /* wmb(); handled by the spin lock */
1117                 spin_pdr_lock(&b->lock);
1118                 /* Sense is only protected in addition to decisions to sleep */
1119                 b->sense = ls;  /* set to free everyone */
1120                 /* All access to nr_waiters is protected by the lock */
1121                 if (!b->nr_waiters) {
1122                         spin_pdr_unlock(&b->lock);
1123                         return PTHREAD_BARRIER_SERIAL_THREAD;
1124                 }
1125                 __uth_sync_init(&restartees);
1126                 __uth_sync_swap(&restartees, &b->waiters);
1127                 b->nr_waiters = 0;
1128                 spin_pdr_unlock(&b->lock);
1129                 __uth_sync_wake_all(&restartees);
1130                 return PTHREAD_BARRIER_SERIAL_THREAD;
1131         } else {
1132                 /* Spin if there are no other threads to run.  No sense sleeping */
1133                 do {
1134                         if (b->sense == ls)
1135                                 return 0;
1136                         cpu_relax();
1137                 } while (safe_to_spin(&spin_state));
1138
1139                 /* Try to sleep, when we wake/return, we're free to go */
1140                 local_junk.b = b;
1141                 local_junk.ls = ls;
1142                 uthread_yield(TRUE, __pth_barrier_cb, &local_junk);
1143                 // assert(b->sense == ls);
1144                 return 0;
1145         }
1146 }
1147
1148 int pthread_barrier_destroy(pthread_barrier_t *b)
1149 {
1150         assert(!b->nr_waiters);
1151         __uth_sync_destroy(&b->waiters);
1152         /* Free any locks (if we end up using an MCS) */
1153         return 0;
1154 }
1155
1156 int pthread_detach(pthread_t thread)
1157 {
1158         uthread_detach((struct uthread*)thread);
1159         return 0;
1160 }
1161
1162 int pthread_kill(pthread_t thread, int signo)
1163 {
1164         return uthread_signal(&thread->uthread, signo);
1165 }
1166
1167 int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
1168 {
1169         int ret = sigprocmask(how, set, oset);
1170
1171         /* Ensures any pending signals we just unmasked get processed. */
1172         if (set && ret == 0)
1173                 pthread_yield();
1174         return ret;
1175 }
1176
1177 int pthread_sigqueue(pthread_t *thread, int sig, const union sigval value)
1178 {
1179         printf("pthread_sigqueue is not yet implemented!");
1180         return -1;
1181 }
1182
1183 int pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
1184 {
1185         *key = dtls_key_create(destructor);
1186         assert(key);
1187         return 0;
1188 }
1189
1190 int pthread_key_delete(pthread_key_t key)
1191 {
1192         dtls_key_delete(key);
1193         return 0;
1194 }
1195
1196 void *pthread_getspecific(pthread_key_t key)
1197 {
1198         return get_dtls(key);
1199 }
1200
1201 int pthread_setspecific(pthread_key_t key, const void *value)
1202 {
1203         set_dtls(key, (void*)value);
1204         return 0;
1205 }
1206
1207
1208 /* Scheduling Stuff */
1209
1210 static bool policy_is_supported(int policy)
1211 {
1212         /* As our scheduler changes, we can add more policies here */
1213         switch (policy) {
1214                 case SCHED_FIFO:
1215                         return TRUE;
1216                 default:
1217                         return FALSE;
1218         }
1219 }
1220
1221 int pthread_attr_setschedparam(pthread_attr_t *attr,
1222                                const struct sched_param *param)
1223 {
1224         /* The set of acceptable priorities are based on the scheduling policy.
1225          * We'll just accept any old number, since we might not know the policy
1226          * yet.  I didn't see anything in the man pages saying attr had to have a
1227          * policy set before setting priority. */
1228         attr->sched_priority = param->sched_priority;
1229         return 0;
1230 }
1231
1232 int pthread_attr_getschedparam(pthread_attr_t *attr,
1233                                struct sched_param *param)
1234 {
1235         param->sched_priority = attr->sched_priority;
1236         return 0;
1237 }
1238
1239 int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
1240 {
1241         if (!policy_is_supported(policy))
1242                 return -EINVAL;
1243         attr->sched_policy = policy;
1244         return 0;
1245 }
1246
1247 int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *policy)
1248 {
1249         *policy = attr->sched_policy;
1250         return 0;
1251 }
1252
1253 /* We only support SCOPE_PROCESS, so we don't even use the attr. */
1254 int pthread_attr_setscope(pthread_attr_t *attr, int scope)
1255 {
1256         if (scope != PTHREAD_SCOPE_PROCESS)
1257                 return -ENOTSUP;
1258         return 0;
1259 }
1260
1261 int pthread_attr_getscope(pthread_attr_t *attr, int *scope)
1262 {
1263         *scope = PTHREAD_SCOPE_PROCESS;
1264         return 0;
1265 }
1266
1267 /* Inheritance refers to policy, priority, scope */
1268 int pthread_attr_setinheritsched(pthread_attr_t *attr,
1269                                  int inheritsched)
1270 {
1271         switch (inheritsched) {
1272                 case PTHREAD_INHERIT_SCHED:
1273                 case PTHREAD_EXPLICIT_SCHED:
1274                         break;
1275                 default:
1276                         return -EINVAL;
1277         }
1278         attr->sched_inherit = inheritsched;
1279         return 0;
1280 }
1281
1282 int pthread_attr_getinheritsched(const pthread_attr_t *attr,
1283                                  int *inheritsched)
1284 {
1285         *inheritsched = attr->sched_inherit;
1286         return 0;
1287 }
1288
1289 int pthread_setschedparam(pthread_t thread, int policy,
1290                            const struct sched_param *param)
1291 {
1292         if (!policy_is_supported(policy))
1293                 return -EINVAL;
1294         thread->sched_policy = policy;
1295         /* We actually could check if the priority falls in the range of the
1296          * specified policy here, since we have both policy and priority. */
1297         thread->sched_priority = param->sched_priority;
1298         return 0;
1299 }
1300
1301 int pthread_getschedparam(pthread_t thread, int *policy,
1302                            struct sched_param *param)
1303 {
1304         *policy = thread->sched_policy;
1305         param->sched_priority = thread->sched_priority;
1306         return 0;
1307 }