Pthread code makes sure it goes into _M mode
[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 <rstdio.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
19 struct pthread_queue ready_queue = TAILQ_HEAD_INITIALIZER(ready_queue);
20 struct pthread_queue active_queue = TAILQ_HEAD_INITIALIZER(active_queue);
21 mcs_lock_t queue_lock = MCS_LOCK_INIT;
22 pthread_once_t init_once = PTHREAD_ONCE_INIT;
23 int threads_ready = 0;
24 int threads_active = 0;
25
26 /* Helper / local functions */
27 static int get_next_pid(void);
28 static inline void spin_to_sleep(unsigned int spins, unsigned int *spun);
29
30 __thread struct pthread_tcb *current_thread = 0;
31
32 void _pthread_init()
33 {
34         if (vcore_init())
35                 printf("vcore_init() failed, we're fucked!\n");
36         
37         assert(vcore_id() == 0);
38         assert(!in_vcore_context());
39
40         /* Tell the kernel where and how we want to receive events.  This is just an
41          * example of what to do to have a notification turned on.  We're turning on
42          * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to
43          * send to vcore 0.  Note sys_self_notify will ignore the vcoreid pref.
44          * Also note that enable_kevent() is just an example, and you probably want
45          * to use parts of event.c to do what you want. */
46         enable_kevent(EV_USER_IPI, 0, EVENT_IPI);
47
48         /* don't forget to enable notifs on vcore0.  if you don't, the kernel will
49          * restart your _S with notifs disabled, which is a path to confusion. */
50         enable_notifs(0);
51
52         /* Create a pthread_tcb for the main thread */
53         pthread_t t = (pthread_t)calloc(1, sizeof(struct pthread_tcb));
54         t->id = get_next_pid();
55         assert(t->id == 0);
56         /* Put the new pthread on the active queue */
57         mcs_lock_lock(&queue_lock);
58         threads_active++;
59         TAILQ_INSERT_TAIL(&active_queue, t, next);
60         mcs_lock_unlock(&queue_lock);
61         
62         /* Save a pointer to the newly created threads tls region into its tcb */
63         t->tls_desc = get_tls_desc(0);
64         /* Save a pointer to the pthread in its own TLS */
65         current_thread = t;
66
67         /* Change temporarily to vcore0s tls region so we can save the newly created
68          * tcb into its current_thread variable and then restore it.  One minor
69          * issue is that vcore0's transition-TLS isn't TLS_INITed yet.  Until it is
70          * (right before vcore_entry(), don't try and take the address of any of
71          * its TLS vars. */
72         extern void** vcore_thread_control_blocks;
73         set_tls_desc(vcore_thread_control_blocks[0], 0);
74         current_thread = t;
75         set_tls_desc(t->tls_desc, 0);
76         assert(!in_vcore_context());
77 }
78
79 void __attribute__((noreturn)) vcore_entry()
80 {
81         uint32_t vcoreid = vcore_id();
82
83         struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
84
85         /* Should always have notifications disabled when coming in here. */
86         assert(vcpd->notif_enabled == FALSE);
87         assert(in_vcore_context());
88
89         check_preempt_pending(vcoreid);
90         handle_events(vcoreid);
91         assert(in_vcore_context());     /* double check, in case and event changed it */
92         // TODO: consider making this restart path work for restarting as well as
93         // freshly starting
94         if (current_thread) {
95                 clear_notif_pending(vcoreid);
96                 set_tls_desc(current_thread->tls_desc, vcoreid);
97                 /* Pop the user trap frame */
98                 pop_ros_tf(&vcpd->notif_tf, vcoreid);
99                 assert(0);
100         }
101
102         /* no one currently running, so lets get someone from the ready queue */
103         struct pthread_tcb *new_thread = NULL;
104         mcs_lock_lock(&queue_lock);
105         new_thread = TAILQ_FIRST(&ready_queue);
106         if (new_thread) {
107                 TAILQ_REMOVE(&ready_queue, new_thread, next);
108                 TAILQ_INSERT_TAIL(&active_queue, new_thread, next);
109                 threads_active++;
110                 threads_ready--;
111         }
112         mcs_lock_unlock(&queue_lock);
113         if (!new_thread) {
114                 /* TODO: consider doing something more intelligent here */
115                 printd("[P] No threads, vcore %d is yielding\n", vcoreid);
116                 sys_yield(0);
117         }
118         /* Save a ptr to the pthread running in the transition context's TLS */
119         current_thread = new_thread;
120         printd("[P] Vcore %d is starting pthread %d\n", vcoreid, new_thread->id);
121
122         clear_notif_pending(vcoreid);
123         set_tls_desc(new_thread->tls_desc, vcoreid);
124
125         /* Load silly state (Floating point) too.  For real */
126         // TODO: (HSS)
127
128         /* Pop the user trap frame */
129         pop_ros_tf(&new_thread->utf, vcoreid);
130         assert(0);
131 }
132
133 int pthread_attr_init(pthread_attr_t *a)
134 {
135         a->stacksize = PTHREAD_STACK_SIZE;
136         a->detachstate = PTHREAD_CREATE_JOINABLE;
137         return 0;
138 }
139
140 int pthread_attr_destroy(pthread_attr_t *a)
141 {
142         return 0;
143 }
144
145 /* TODO: probably don't want to dealloc.  Considering caching */
146 static void __pthread_free_tls(struct pthread_tcb *pt)
147 {
148         extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
149
150         assert(pt->tls_desc);
151         _dl_deallocate_tls(pt->tls_desc, TRUE);
152         pt->tls_desc = NULL;
153 }
154
155 static int __pthread_allocate_tls(struct pthread_tcb *pt)
156 {
157         assert(!pt->tls_desc);
158         pt->tls_desc = allocate_tls();
159         if (!pt->tls_desc) {
160                 errno = ENOMEM;
161                 return -1;
162         }
163         return 0;
164 }
165
166
167 static void __pthread_free_stack(struct pthread_tcb *pt)
168 {
169         assert(!munmap(pt->stacktop - PTHREAD_STACK_SIZE, PTHREAD_STACK_SIZE));
170 }
171
172 static int __pthread_allocate_stack(struct pthread_tcb *pt)
173 {
174         assert(pt->stacksize);
175         void* stackbot = mmap(0, pt->stacksize,
176                               PROT_READ|PROT_WRITE|PROT_EXEC,
177                               MAP_POPULATE|MAP_ANONYMOUS, -1, 0);
178         if (stackbot == MAP_FAILED)
179                 return -1; // errno set by mmap
180         pt->stacktop = stackbot + pt->stacksize;
181         return 0;
182 }
183
184 void __pthread_run(void)
185 {
186         struct pthread_tcb *me = current_thread;
187         pthread_exit(me->start_routine(me->arg));
188 }
189
190 // Warning, this will reuse numbers eventually
191 static int get_next_pid(void)
192 {
193         static uint32_t next_pid = 0;
194         return next_pid++;
195 }
196
197
198 int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
199 {
200         attr->stacksize = stacksize;
201         return 0;
202 }
203 int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
204 {
205         *stacksize = attr->stacksize;
206         return 0;
207 }
208
209 int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
210                    void *(*start_routine)(void *), void* arg)
211 {
212         /* After this init, we are an MCP and the caller is a pthread */
213         pthread_once(&init_once, &_pthread_init);
214
215         struct pthread_tcb *t = pthread_self();
216         assert(t);
217         assert(!in_vcore_context());
218         /* Don't migrate this thread to another vcore, since it depends on being on
219          * the same vcore throughout. */
220         t->dont_migrate = TRUE;
221         wmb();
222         /* Note the first time we call this, we technically aren't on a vcore */
223         uint32_t vcoreid = vcore_id();
224         *thread = (pthread_t)calloc(1, sizeof(struct pthread_tcb));
225         (*thread)->start_routine = start_routine;
226         (*thread)->arg = arg;
227         (*thread)->stacksize = PTHREAD_STACK_SIZE;      /* default */
228         (*thread)->id = get_next_pid();
229         (*thread)->detached = FALSE;                            /* default */
230         /* Respect the attributes*/
231         if (attr) {
232                 if (attr->stacksize)                                    /* don't set a 0 stacksize */
233                         (*thread)->stacksize = attr->stacksize;
234                 if (attr->detachstate == PTHREAD_CREATE_DETACHED)
235                         (*thread)->detached = TRUE;
236         }
237         if (__pthread_allocate_stack(*thread) ||  __pthread_allocate_tls(*thread))
238                 printf("We're fucked\n");
239         /* Save the ptr to the new pthread in that pthread's TLS */
240         set_tls_desc((*thread)->tls_desc, vcoreid);
241         current_thread = *thread;
242         set_tls_desc(t->tls_desc, vcoreid);
243         /* Set the u_tf to start up in __pthread_run, which will call the real
244          * start_routine and pass it the arg. */
245         init_user_tf(&(*thread)->utf, (uint32_t)__pthread_run, 
246                  (uint32_t)((*thread)->stacktop));
247         /* Insert the newly created thread into the ready queue of threads.
248          * It will be removed from this queue later when vcore_entry() comes up */
249         mcs_lock_lock(&queue_lock);
250         TAILQ_INSERT_TAIL(&ready_queue, *thread, next);
251         threads_ready++;
252         mcs_lock_unlock(&queue_lock);
253         /* Okay to migrate now. */
254         wmb();
255         t->dont_migrate = FALSE;
256
257         /* Need to get some vcores.  If this is the first time, we'd like to get
258          * two: one for the main thread (aka thread0), and another for the pthread
259          * we are creating.  Can rework this if we get another vcore interface that
260          * deals with absolute core counts.
261          *
262          * Need to get at least one core to put us in _M mode so we can run the 2LS,
263          * etc, so for now we'll just spin until we get at least one (might be none
264          * available).
265          *
266          * TODO: do something smarter regarding asking for cores (paired with
267          * yielding), and block or something until one core is available (will need
268          * kernel support). */
269         static bool first_time = TRUE;
270         if (first_time) {
271                 first_time = FALSE;
272                 /* Try for two, don't settle for less than 1 */
273                 while (num_vcores() < 1) {
274                         vcore_request(2);
275                         cpu_relax();
276                 }
277         } else {        /* common case */
278                 /* Try to get another for the new thread, but doesn't matter if we get
279                  * one or not, so long as we still have at least 1. */
280                 vcore_request(1);
281         }
282         assert(num_vcores() > 0);
283         assert(!in_vcore_context());    /* still are the calling u_thread */
284         return 0;
285 }
286
287 int pthread_join(pthread_t thread, void** retval)
288 {
289         /* Not sure if this is the right semantics.  There is a race if we deref
290          * thread and he is already freed (which would have happened if he was
291          * detached. */
292         if (thread->detached) {
293                 printf("[pthread] trying to join on a detached pthread");
294                 return -1;
295         }
296         while (!thread->finished)
297                 pthread_yield();
298         if (retval)
299                 *retval = thread->retval;
300         free(thread);
301         return 0;
302 }
303
304 static void __attribute__((noinline, noreturn)) 
305 __pthread_yield(struct pthread_tcb *t)
306 {
307         assert(in_vcore_context());
308         /* TODO: want to set this to FALSE once we no longer depend on being on this
309          * vcore.  Though if we are using TLS, we are depending on the vcore.  Since
310          * notifs are disabled and we are in a transition context, we probably
311          * shouldn't be moved anyway.  It does mean that a pthread could get jammed.
312          * If we do this after putting it on the active list, we'll have a race on
313          * dont_migrate. */
314         t->dont_migrate = FALSE;
315         /* Take from the active list, and put on the ready list (tail).  Don't do
316          * this until we are done completely with the thread, since it can be
317          * restarted somewhere else. */
318         mcs_lock_lock(&queue_lock);
319         threads_active--;
320         TAILQ_REMOVE(&active_queue, t, next);
321         threads_ready++;
322         TAILQ_INSERT_TAIL(&ready_queue, t, next);
323         mcs_lock_unlock(&queue_lock);
324         /* Leave the current vcore completely */
325         current_thread = NULL; // this might be okay, even with a migration
326         /* Go back to the entry point, where we can handle notifications or
327          * reschedule someone. */
328         vcore_entry();
329 }
330
331 int pthread_yield(void)
332 {
333         struct pthread_tcb *t = pthread_self();
334         volatile bool yielding = TRUE; /* signal to short circuit when restarting */
335
336         /* TODO: (HSS) Save silly state */
337         // save_fp_state(&t->as);
338
339         assert(!in_vcore_context());
340         /* Don't migrate this thread to another vcore, since it depends on being on
341          * the same vcore throughout (once it disables notifs). */
342         t->dont_migrate = TRUE;
343         wmb();
344         uint32_t vcoreid = vcore_id();
345         printd("[P] Pthread id %d is yielding on vcore %d\n", t->id, vcoreid);
346         struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
347         /* once we do this, we might miss a notif_pending, so we need to enter vcore
348          * entry later.  Need to disable notifs so we don't get in weird loops with
349          * save_ros_tf() and pop_ros_tf(). */
350         disable_notifs(vcoreid);
351         /* take the current state and save it into t->utf when this pthread
352          * restarts, it will continue from right after this, see yielding is false,
353          * and short ciruit the function. */
354         save_ros_tf(&t->utf);
355         if (!yielding)
356                 goto yield_return_path;
357         yielding = FALSE; /* for when it starts back up */
358         /* Change to the transition context (both TLS and stack). */
359         extern void** vcore_thread_control_blocks;
360         set_tls_desc(vcore_thread_control_blocks[vcoreid], vcoreid);
361         assert(current_thread == t);    
362         assert(in_vcore_context());     /* technically, we aren't fully in vcore context */
363         /* After this, make sure you don't use local variables.  Note the warning in
364          * pthread_exit() */
365         set_stack_pointer((void*)vcpd->transition_stack);
366         /* Finish exiting in another function. */
367         __pthread_yield(current_thread);
368         /* Should never get here */
369         assert(0);
370         /* Will jump here when the pthread's trapframe is restarted/popped. */
371 yield_return_path:
372         printd("[P] pthread %d returning from a yield!\n", t->id);
373         return 0;
374 }
375
376 int pthread_mutexattr_init(pthread_mutexattr_t* attr)
377 {
378   attr->type = PTHREAD_MUTEX_DEFAULT;
379   return 0;
380 }
381
382 int pthread_mutexattr_destroy(pthread_mutexattr_t* attr)
383 {
384   return 0;
385 }
386
387
388 int pthread_attr_setdetachstate(pthread_attr_t *__attr, int __detachstate)
389 {
390         __attr->detachstate = __detachstate;
391         return 0;
392 }
393
394 int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type)
395 {
396   *type = attr ? attr->type : PTHREAD_MUTEX_DEFAULT;
397   return 0;
398 }
399
400 int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type)
401 {
402   if(type != PTHREAD_MUTEX_NORMAL)
403     return EINVAL;
404   attr->type = type;
405   return 0;
406 }
407
408 int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr)
409 {
410   m->attr = attr;
411   m->lock = 0;
412   return 0;
413 }
414
415 /* Set *spun to 0 when calling this the first time.  It will yield after 'spins'
416  * calls.  Use this for adaptive mutexes and such. */
417 static inline void spin_to_sleep(unsigned int spins, unsigned int *spun)
418 {
419         if ((*spun)++ == spins) {
420                 pthread_yield();
421                 *spun = 0;
422         }
423 }
424
425 int pthread_mutex_lock(pthread_mutex_t* m)
426 {
427         unsigned int spinner = 0;
428         while(pthread_mutex_trylock(m))
429                 while(*(volatile size_t*)&m->lock) {
430                         cpu_relax();
431                         spin_to_sleep(PTHREAD_MUTEX_SPINS, &spinner);
432                 }
433         return 0;
434 }
435
436 int pthread_mutex_trylock(pthread_mutex_t* m)
437 {
438   return atomic_swap(&m->lock,1) == 0 ? 0 : EBUSY;
439 }
440
441 int pthread_mutex_unlock(pthread_mutex_t* m)
442 {
443   /* Need to prevent the compiler (and some arches) from reordering older
444    * stores */
445   wmb();
446   m->lock = 0;
447   return 0;
448 }
449
450 int pthread_mutex_destroy(pthread_mutex_t* m)
451 {
452   return 0;
453 }
454
455 int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a)
456 {
457   c->attr = a;
458   memset(c->waiters,0,sizeof(c->waiters));
459   memset(c->in_use,0,sizeof(c->in_use));
460   c->next_waiter = 0;
461   return 0;
462 }
463
464 int pthread_cond_destroy(pthread_cond_t *c)
465 {
466   return 0;
467 }
468
469 int pthread_cond_broadcast(pthread_cond_t *c)
470 {
471   memset(c->waiters,0,sizeof(c->waiters));
472   return 0;
473 }
474
475 int pthread_cond_signal(pthread_cond_t *c)
476 {
477   int i;
478   for(i = 0; i < MAX_PTHREADS; i++)
479   {
480     if(c->waiters[i])
481     {
482       c->waiters[i] = 0;
483       break;
484     }
485   }
486   return 0;
487 }
488
489 int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
490 {
491   int old_waiter = c->next_waiter;
492   int my_waiter = c->next_waiter;
493   
494   //allocate a slot
495   while (atomic_swap (& (c->in_use[my_waiter]), SLOT_IN_USE) == SLOT_IN_USE)
496   {
497     my_waiter = (my_waiter + 1) % MAX_PTHREADS;
498     assert (old_waiter != my_waiter);  // do not want to wrap around
499   }
500   c->waiters[my_waiter] = WAITER_WAITING;
501   c->next_waiter = (my_waiter+1) % MAX_PTHREADS;  // race on next_waiter but ok, because it is advisary
502
503   pthread_mutex_unlock(m);
504
505   volatile int* poll = &c->waiters[my_waiter];
506   while(*poll);
507   c->in_use[my_waiter] = SLOT_FREE;
508   pthread_mutex_lock(m);
509
510   return 0;
511 }
512
513 int pthread_condattr_init(pthread_condattr_t *a)
514 {
515   a = PTHREAD_PROCESS_PRIVATE;
516   return 0;
517 }
518
519 int pthread_condattr_destroy(pthread_condattr_t *a)
520 {
521   return 0;
522 }
523
524 int pthread_condattr_setpshared(pthread_condattr_t *a, int s)
525 {
526   a->pshared = s;
527   return 0;
528 }
529
530 int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
531 {
532   *s = a->pshared;
533   return 0;
534 }
535
536 pthread_t pthread_self()
537 {
538   return current_thread;
539 }
540
541 int pthread_equal(pthread_t t1, pthread_t t2)
542 {
543   return t1 == t2;
544 }
545
546 /* Need to have this as a separate, non-inlined function since we clobber the
547  * stack pointer before calling it, and don't want the compiler to play games
548  * with my hart. */
549 static void __attribute__((noinline, noreturn)) 
550 __pthread_exit(struct pthread_tcb *t)
551 {
552         assert(in_vcore_context());
553         __pthread_free_tls(t);
554         __pthread_free_stack(t);
555         /* TODO: race on detach state */
556         if (t->detached)
557                 free(t);
558         /* Once we do this, our joiner can free us.  He won't free us if we're
559          * detached, but there is still a potential race there (since he's accessing
560          * someone who is freed. */
561         t->finished = 1;
562         current_thread = NULL;
563         /* Go back to the entry point, where we can handle notifications or
564          * reschedule someone. */
565         vcore_entry();
566 }
567
568 /* This function cannot be migrated to a different vcore by the userspace
569  * scheduler.  Will need to sort that shit out.  */
570 void pthread_exit(void* ret)
571 {
572         assert(!in_vcore_context());
573         struct pthread_tcb *t = pthread_self();
574         /* Don't migrate this thread to anothe vcore, since it depends on being on
575          * the same vcore throughout. */
576         t->dont_migrate = TRUE; // won't set this to false later, since he is dying
577         wmb();
578
579         uint32_t vcoreid = vcore_id();
580         struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
581
582         t->retval = ret;
583         mcs_lock_lock(&queue_lock);
584         threads_active--;
585         TAILQ_REMOVE(&active_queue, t, next);
586         mcs_lock_unlock(&queue_lock);
587
588         printd("[P] Pthread id %d is exiting on vcore %d\n", t->id, vcoreid);
589         
590         /* once we do this, we might miss a notif_pending, so we need to enter vcore
591          * entry later. */
592         disable_notifs(vcoreid);
593
594         /* Change to the transition context (both TLS and stack). */
595         extern void** vcore_thread_control_blocks;
596         set_tls_desc(vcore_thread_control_blocks[vcoreid], vcoreid);
597         assert(current_thread == t);    
598         /* After this, make sure you don't use local variables.  Also, make sure the
599          * compiler doesn't use them without telling you (TODO).
600          *
601          * In each arch's set_stack_pointer, make sure you subtract off as much room
602          * as you need to any local vars that might be pushed before calling the
603          * next function, or for whatever other reason the compiler/hardware might
604          * walk up the stack a bit when calling a noreturn function. */
605         set_stack_pointer((void*)vcpd->transition_stack);
606         /* Finish exiting in another function.  Ugh. */
607         __pthread_exit(current_thread);
608 }
609
610 int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
611 {
612   if(atomic_swap(once_control,1) == 0)
613     init_routine();
614   return 0;
615 }
616
617 int pthread_barrier_init(pthread_barrier_t* b, const pthread_barrierattr_t* a, int count)
618 {
619   b->nprocs = b->count = count;
620   b->sense = 0;
621   pthread_mutex_init(&b->pmutex, 0);
622   return 0;
623 }
624
625 int pthread_barrier_wait(pthread_barrier_t* b)
626 {
627   unsigned int spinner = 0;
628   int ls = !b->sense;
629
630   pthread_mutex_lock(&b->pmutex);
631   int count = --b->count;
632   pthread_mutex_unlock(&b->pmutex);
633
634   if(count == 0)
635   {
636     printd("Thread %d is last to hit the barrier, resetting...\n", pthread_self()->id);
637     b->count = b->nprocs;
638         wmb();
639     b->sense = ls;
640     return PTHREAD_BARRIER_SERIAL_THREAD;
641   }
642   else
643   {
644     while(b->sense != ls) {
645       cpu_relax();
646       spin_to_sleep(PTHREAD_BARRIER_SPINS, &spinner);
647     }
648     return 0;
649   }
650 }
651
652 int pthread_barrier_destroy(pthread_barrier_t* b)
653 {
654   pthread_mutex_destroy(&b->pmutex);
655   return 0;
656 }
657
658 int pthread_detach(pthread_t thread)
659 {
660         thread->detached = TRUE;
661         return 0;
662 }