flounder: moving receiving cap slots from a thread to a dispatcher
[barrelfish] / lib / barrelfish / threads.c
1 /**
2  * \file
3  * \brief Threads implementation.
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <barrelfish/barrelfish.h>
19 #include <barrelfish/dispatch.h>
20 #include <barrelfish/dispatcher_arch.h>
21 #include <barrelfish/debug.h>
22 #include <barrelfish/slab.h>
23 #include <barrelfish/caddr.h>
24 #include <barrelfish/curdispatcher_arch.h>
25 #include <barrelfish/vspace_mmu_aware.h>
26 #include <barrelfish_kpi/cpu_arch.h>
27 #include <barrelfish_kpi/domain_params.h>
28 #include <arch/registers.h>
29 #include <trace/trace.h>
30
31 #include <trace_definitions/trace_defs.h>
32
33 #include "arch/threads.h"
34 #include "threads_priv.h"
35 #include "init.h"
36
37 #if defined(__x86_64__)
38 #  include "arch/ldt.h"
39 #endif
40
41 #ifdef FPU_LAZY_CONTEXT_SWITCH
42 #  include <arch/fpu.h>
43 #endif
44
45 /// Maximum number of threads in a domain, used to size VM region for thread structures
46 // there is no point having MAX_THREADS > LDT_NENTRIES on x86 (see ldt.c)
47 #define MAX_THREADS 256
48
49 /// 16-byte alignment required for x86-64
50 // FIXME: this should be in an arch header
51 #define STACK_ALIGNMENT (sizeof(uint64_t) * 2)
52
53 /// Static stack and storage for a bootstrap/cleanup thread
54 // XXX: 16-byte aligned for x86-64
55 static uintptr_t staticstack[THREADS_DEFAULT_STACK_BYTES / sizeof(uintptr_t)]
56 __attribute__((aligned(STACK_ALIGNMENT)));
57 static struct thread staticthread = {
58     .stack = staticstack,
59     .stack_top = (char *)staticstack + sizeof(staticstack)
60 };
61 static struct thread_mutex staticthread_lock = THREAD_MUTEX_INITIALIZER;
62
63 /// Storage metadata for thread structures (and TLS data)
64 static struct slab_allocator thread_slabs;
65 static struct vspace_mmu_aware thread_slabs_vm;
66
67 // XXX: mutex and spinlock protecting thread slabs in spanned domains
68 /* This ought to be just a mutex. However, thread_create() is called on the
69  * inter-disp message handler thread, and if it blocks in a mutex, there is no
70  * way to wake it up and we will deadlock. This is a quick-fix workaround:
71  *   The spinlock protects the data structure
72  *   The mutex avoids unneccessary spinning (it is acquired first when safe)
73  */
74 static spinlock_t thread_slabs_spinlock;
75 static struct thread_mutex thread_slabs_mutex = THREAD_MUTEX_INITIALIZER;
76
77 /// Base and size of the original ("pristine") thread-local storage init data
78 static void *tls_block_init_base;
79 static size_t tls_block_init_len;
80 static size_t tls_block_total_len;
81
82 /// Warning already issued about RSP usage.  (Prevent repeated warnings
83 /// from the same domain -- e.g., when using THC whose stacks appear
84 /// invalid here).
85 __attribute__((unused)) static bool stack_warned=0;
86
87 /// Wrapper function for most threads, runs given function then deletes itself
88 static void thread_entry(thread_func_t start_func, void *start_data)
89 {
90     assert((lvaddr_t)start_func >= BASE_PAGE_SIZE);
91     int retval = start_func(start_data);
92     thread_exit(retval);
93     assert(!"thread_exit returned");
94 }
95
96 /// int counter for assigning initial thread ids
97 static uintptr_t threadid = 0;
98
99 #ifndef NDEBUG
100 /// Debugging assertions on thread queues
101 static void check_queue(struct thread *queue)
102 {
103     if (queue == NULL) {
104         return;
105     }
106     struct thread *q = queue;
107     int i = 0;
108
109     do {
110         assert_disabled(q != NULL);
111
112         // check for NULL next and prev pointers
113         assert_disabled((lvaddr_t)q->next > BASE_PAGE_SIZE);
114         assert_disabled((lvaddr_t)q->prev > BASE_PAGE_SIZE);
115
116         // check that next and prev pointers are sane
117         assert_disabled(q->next->prev == q);
118         assert_disabled(q->prev->next == q);
119
120         // advance to next elem
121         q = q->next;
122         i++;
123         assert_disabled(i < MAX_THREADS);
124     } while (q != queue);
125 }
126 #else /* NDEBUG version */
127 static inline void check_queue(struct thread *queue) {}
128 #endif
129
130 /**
131  * \brief Enqueue a thread in the given queue
132  *
133  * For safety, should only happen while disabled.
134  */
135 void thread_enqueue(struct thread *thread, struct thread **queue)
136 {
137     assert_disabled(thread != NULL);
138     assert_disabled(queue != NULL);
139     check_queue(*queue);
140     if (*queue == NULL) {
141         *queue = thread->prev = thread->next = thread;
142     } else {
143         assert_disabled((*queue)->prev != NULL);
144         thread->prev = (*queue)->prev;
145         thread->next = *queue;
146         (*queue)->prev = thread;
147         assert_disabled(thread->prev != NULL);
148         thread->prev->next = thread;
149     }
150
151     check_queue(*queue);
152 }
153
154 /**
155  * \brief Dequeue the first thread on the given queue
156  *
157  * For safety, should only happen while disabled.
158  *
159  * \returns Pointer to thread that was dequeued
160  */
161 struct thread *thread_dequeue(struct thread **queue)
162 {
163     assert_disabled(queue != NULL);
164     struct thread *thread = *queue;
165     assert_disabled(thread != NULL);
166     check_queue(thread);
167     if (thread->prev == thread) {
168         assert_disabled(thread->next == thread);
169         *queue = NULL;
170     } else {
171         thread->prev->next = thread->next;
172         thread->next->prev = thread->prev;
173         *queue = thread->next;
174     }
175     check_queue(*queue);
176 #ifndef NDEBUG
177     thread->prev = thread->next = NULL;
178 #endif
179     return thread;
180 }
181
182 /**
183  * \brief Remove a specific thread from a queue
184  *
185  * Does not check that the thread is in the given queue, which it must be.
186  * For safety, should only happen while disabled.
187  */
188 void thread_remove_from_queue(struct thread **queue, struct thread *thread)
189 {
190     assert_disabled(queue != NULL);
191     assert_disabled(thread != NULL);
192     check_queue(*queue);
193     if (thread->prev == thread) {
194         assert_disabled(thread->next == thread);
195         assert_disabled(*queue == thread);
196         *queue = NULL;
197     } else {
198         thread->prev->next = thread->next;
199         thread->next->prev = thread->prev;
200         if (*queue == thread) {
201             *queue = thread->next;
202         }
203     }
204     check_queue(*queue);
205 #ifndef NDEBUG
206     thread->prev = thread->next = NULL;
207 #endif
208 }
209
210 /// Refill backing storage for thread region
211 static errval_t refill_thread_slabs(struct slab_allocator *slabs)
212 {
213     assert(slabs == &thread_slabs);
214
215     size_t size;
216     void *buf;
217     errval_t err;
218
219     size_t blocksize = sizeof(struct thread) + tls_block_total_len;
220     err = vspace_mmu_aware_map(&thread_slabs_vm, blocksize, &buf, &size);
221     if (err_is_fail(err)) {
222         return err_push(err, LIB_ERR_VSPACE_MMU_AWARE_MAP);
223     }
224
225     slab_grow(slabs, buf, size);
226
227     return SYS_ERR_OK;
228 }
229
230 /// Initialise the state of a new thread structure
231 static void thread_init(dispatcher_handle_t disp, struct thread *newthread)
232 {
233     newthread->self = newthread;
234 #ifndef NDEBUG
235     newthread->next = newthread->prev = NULL;
236 #endif
237     newthread->tls_dtv = NULL;
238     newthread->disp = disp;
239     newthread->coreid = get_dispatcher_generic(disp)->core_id;
240     newthread->userptr = NULL;
241     memset(newthread->userptrs, 0, sizeof(newthread->userptrs));
242     newthread->yield_epoch = 0;
243     newthread->wakeup_reason = NULL;
244     newthread->return_value = 0;
245     thread_cond_init(&newthread->exit_condition);
246     thread_mutex_init(&newthread->exit_lock);
247     newthread->state = THREAD_STATE_RUNNABLE;
248     newthread->detached = false;
249     newthread->joining = false;
250     newthread->in_exception = false;
251     newthread->used_fpu = false;
252     newthread->paused = false;
253     newthread->slab = NULL;
254     newthread->token = 0;
255     newthread->token_number = 1;
256
257     newthread->rpc_in_progress = false;
258     newthread->async_error = SYS_ERR_OK;
259     newthread->local_trigger = NULL;
260 }
261
262 /**
263  * \brief Handle FPU context switching
264  */
265 static void fpu_context_switch(struct dispatcher_generic *disp_gen,
266                                struct thread * next)
267 {
268 #ifdef FPU_LAZY_CONTEXT_SWITCH
269     if(disp_gen->fpu_thread == NULL) {
270         // FPU wasn't used -- no switching necessary
271         return;
272     }
273
274     // Switch FPU trap back on if we switch away from FPU thread
275     if(disp_gen->fpu_thread == disp_gen->current &&
276        disp_gen->fpu_thread != next) {
277         fpu_trap_on();
278     }
279 #endif
280 }
281
282 /**
283  * \brief Returns false if the stack pointer is out of bounds.
284  */
285 static bool thread_check_stack_bounds(struct thread *thread,
286                                       arch_registers_state_t *archregs) {
287     lvaddr_t sp = (lvaddr_t) registers_get_sp(archregs);
288     return sp > (lvaddr_t)thread->stack ||
289            sp <= (lvaddr_t)thread->stack_top;
290 }
291
292 /**
293  * \brief Schedule and run the next active thread, or yield the dispatcher.
294  *
295  * This may only be called from the dispatcher (on its stack and while
296  * disabled!).
297  *
298  * \param disp Dispatcher pointer
299  */
300 void thread_run_disabled(dispatcher_handle_t handle)
301 {
302     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
303     struct dispatcher_shared_generic *disp =
304         get_dispatcher_shared_generic(handle);
305     arch_registers_state_t *enabled_area =
306         dispatcher_get_enabled_save_area(handle);
307
308     if (disp_gen->current != NULL) {
309         assert_disabled(disp_gen->runq != NULL);
310
311         // check stack bounds
312         warn_disabled(&stack_warned,
313                       thread_check_stack_bounds(disp_gen->current, enabled_area));
314
315         struct thread *next = disp_gen->current->next;
316         assert_disabled(next != NULL);
317         if (next != disp_gen->current) {
318             fpu_context_switch(disp_gen, next);
319
320             // save previous thread's state
321             arch_registers_state_t *cur_regs = &disp_gen->current->regs;
322             memcpy(cur_regs, enabled_area, sizeof(arch_registers_state_t));
323             disp_gen->current = next;
324             disp_resume(handle, &next->regs);
325         } else {
326             // same thread as before
327             disp_resume(handle, enabled_area);
328         }
329     } else if (disp_gen->runq != NULL) {
330         fpu_context_switch(disp_gen, disp_gen->runq);
331         disp_gen->current = disp_gen->runq;
332         disp->haswork = true;
333         disp_resume(handle, &disp_gen->runq->regs);
334     } else {
335         // kernel gave us the CPU when we have nothing to do. block!
336         disp->haswork = havework_disabled(handle);
337         disp_gen->current = NULL;
338         disp_yield_disabled(handle);
339     }
340 }
341
342 /** Free all heap/slab-allocated state associated with a thread */
343 static void free_thread(struct thread *thread)
344 {
345 #if defined(__x86_64__) // XXX: gungy segment selector stuff
346     assert(thread->thread_seg_selector != 0);
347     uint16_t fs;
348     __asm("mov %%fs, %0" : "=r" (fs));
349     if (thread->thread_seg_selector == fs) {
350         assert(thread->disp == curdispatcher());
351         struct dispatcher_x86_64 *disp_priv = get_dispatcher_x86_64(thread->disp);
352         // we're freeing the current thread; make sure we reload a valid segment
353         // selector so that curdispatcher() keeps working!
354         __asm volatile("mov %%ax, %%fs"
355                        : /* No outputs */
356                        : "a" (disp_priv->disp_seg_selector));
357     }
358     ldt_free_segment(thread->thread_seg_selector);
359 #endif
360
361     free(thread->stack);
362     if (thread->tls_dtv != NULL) {
363         free(thread->tls_dtv);
364     }
365
366     thread_mutex_lock(&thread_slabs_mutex);
367     acquire_spinlock(&thread_slabs_spinlock);
368     slab_free(&thread_slabs, thread->slab); // frees thread itself
369     release_spinlock(&thread_slabs_spinlock);
370     thread_mutex_unlock(&thread_slabs_mutex);
371 }
372
373 /**
374  * \brief Creates a new thread that will not be runnable
375  *
376  * \param start_func Function to run on the new thread
377  * \param arg Argument to pass to function
378  * \param stacksize Size of stack, in bytes
379  *
380  * \returns Thread pointer on success, NULL on failure
381  */
382 struct thread *thread_create_unrunnable(thread_func_t start_func, void *arg,
383                                         size_t stacksize)
384 {
385     // allocate stack
386     assert((stacksize % sizeof(uintptr_t)) == 0);
387     void *stack = malloc(stacksize);
388     if (stack == NULL) {
389         return NULL;
390     }
391
392     // allocate space for TCB + initial TLS data
393     // no mutex as it may deadlock: see comment for thread_slabs_spinlock
394     // thread_mutex_lock(&thread_slabs_mutex);
395     acquire_spinlock(&thread_slabs_spinlock);
396     void *space = slab_alloc(&thread_slabs);
397     release_spinlock(&thread_slabs_spinlock);
398     // thread_mutex_unlock(&thread_slabs_mutex);
399     if (space == NULL) {
400         free(stack);
401         return NULL;
402     }
403
404     // split space into TLS data followed by TCB
405     // XXX: this layout is specific to the x86 ABIs! once other (saner)
406     // architectures support TLS, we'll need to break out the logic.
407     void *tls_data = space;
408     struct thread *newthread = (void *)((uintptr_t)space + tls_block_total_len);
409
410     // init thread
411     thread_init(curdispatcher(), newthread);
412     newthread->slab = space;
413
414     if (tls_block_total_len > 0) {
415         // populate initial TLS data from pristine copy
416         assert(tls_block_init_len <= tls_block_total_len);
417         memcpy(tls_data, tls_block_init_base, tls_block_init_len);
418
419         // zero-fill remainder
420         memset((char *)tls_data + tls_block_init_len, 0,
421                tls_block_total_len - tls_block_init_len);
422
423         // create a TLS thread vector
424         struct tls_dtv *dtv = malloc(sizeof(struct tls_dtv) + 1 * sizeof(void *));
425         assert(dtv != NULL);
426
427         dtv->gen = 0;
428         dtv->dtv[0] = tls_data;
429         newthread->tls_dtv = dtv;
430     }
431
432     // FIXME: make arch-specific
433 #if defined(__x86_64__) || defined(__k1om__)
434     // create segment for TCB
435     errval_t err = ldt_alloc_segment(newthread, &newthread->thread_seg_selector);
436     if (err_is_fail(err)) {
437         DEBUG_ERR(err, "error allocating LDT segment for new thread");
438         free_thread(newthread);
439         free(stack);
440         return NULL;
441     }
442 #endif
443
444     // init stack
445     newthread->stack = stack;
446     newthread->stack_top = (char *)stack + stacksize;
447
448     // waste space for alignment, if malloc gave us an unaligned stack
449     newthread->stack_top = (char *)newthread->stack_top
450         - (lvaddr_t)newthread->stack_top % STACK_ALIGNMENT;
451
452     // set thread's ID
453     newthread->id = threadid++;
454
455     // init registers
456     registers_set_initial(&newthread->regs, newthread, (lvaddr_t)thread_entry,
457                           (lvaddr_t)newthread->stack_top,
458                           (lvaddr_t)start_func, (lvaddr_t)arg, 0, 0);
459
460     return newthread;
461 }
462
463 /**
464  * \brief Creates a new thread, and makes it runnable
465  *
466  * \param start_func Function to run on the new thread
467  * \param arg Argument to pass to function
468  * \param stacksize Size of stack, in bytes
469  *
470  * \returns Thread pointer on success, NULL on failure
471  */
472 struct thread *thread_create_varstack(thread_func_t start_func, void *arg,
473                                       size_t stacksize)
474 {
475     struct thread *newthread = thread_create_unrunnable(start_func, arg, stacksize);
476     if (newthread) {
477         // enqueue on runq
478         dispatcher_handle_t handle = disp_disable();
479         struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
480         newthread->disp = handle;
481         thread_enqueue(newthread, &disp_gen->runq);
482         disp_enable(handle);
483     }
484     return newthread;
485 }
486
487 /**
488  * \brief Creates a new thread, and makes it runnable
489  *
490  * \param start_func Function to run on the new thread
491  * \param arg Argument to pass to function
492  *
493  * \returns Thread pointer on success, NULL on failure
494  */
495 struct thread *thread_create(thread_func_t start_func, void *arg)
496 {
497     return thread_create_varstack(start_func, arg, THREADS_DEFAULT_STACK_BYTES);
498 }
499
500 /**
501  * \brief Wait for termination of another thread
502  *
503  * \param thread        Pointer to thread to wait for
504  * \param retval        Pointer to variable to hold return value of thread, or NULL
505  *
506  * \returns SYS_ERR_OK on success, error code on error.
507  */
508 errval_t thread_join(struct thread *thread, int *retval)
509 {
510     assert(thread != NULL);
511     // this function should only be called for threads on same core
512     assert(thread->coreid == disp_get_core_id());
513
514     thread_mutex_lock(&thread->exit_lock);
515     if(thread->detached) {
516         // Thread is detached and thus not joinable
517         thread_mutex_unlock(&thread->exit_lock);
518         return LIB_ERR_THREAD_JOIN_DETACHED;
519     }
520
521     if(thread->joining) {
522         // Someone else already joins, that's an error
523         thread_mutex_unlock(&thread->exit_lock);
524         return LIB_ERR_THREAD_JOIN;
525     }
526
527     thread->joining = true;
528     if(thread->state != THREAD_STATE_EXITED) { // Possibly wait for thread exit
529         thread_cond_wait(&thread->exit_condition, &thread->exit_lock);
530     }
531
532     if(retval != NULL) {
533         *retval = thread->return_value;
534     }
535
536     thread_mutex_unlock(&thread->exit_lock);    // Not really needed
537     free_thread(thread);
538
539     return SYS_ERR_OK;
540 }
541
542 /**
543  * \brief Detach a thread. Free its state when it terminates.
544  *
545  * \param thread        Pointer to thread to detach
546  *
547  * \return SYS_ERR_OK on success.
548  */
549 errval_t thread_detach(struct thread *thread)
550 {
551     assert(thread != NULL);
552     thread_mutex_lock(&thread->exit_lock);
553
554     if(thread->joining) {
555         // Someone else already joins, that's an error
556         thread_mutex_unlock(&thread->exit_lock);
557         return LIB_ERR_THREAD_JOIN;
558     }
559
560     if(!thread->detached) {
561         thread->detached = true;
562     } else {
563         // Detaching more than once is an error
564         thread_mutex_unlock(&thread->exit_lock);
565         return LIB_ERR_THREAD_DETACHED;
566     }
567
568     if(thread->state == THREAD_STATE_EXITED) {
569         // Thread already exited before we detached, clean it up
570         free_thread(thread);
571         return SYS_ERR_OK;
572     }
573
574     thread_mutex_unlock(&thread->exit_lock);
575     return SYS_ERR_OK;
576 }
577
578 /**
579  * \brief Returns the thread pointer to the currently-running thread
580  */
581 struct thread *thread_self(void)
582 {
583     struct thread *me;
584 #if defined(__x86_64__) // XXX: AB's silly little arch-specific optimisation
585     __asm("movq %%fs:0, %0" : "=r" (me));
586 #else
587     // it's not necessary to disable, but might be once we do migration
588     bool was_enabled;
589     dispatcher_handle_t handle = disp_try_disable(&was_enabled);
590     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
591     me = disp_gen->current;
592     if (was_enabled)
593         disp_enable(handle);
594 #endif
595     return me;
596 }
597
598 struct thread *thread_self_disabled(void)
599 {
600     dispatcher_handle_t handle = curdispatcher();
601     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
602     return disp_gen->current;
603 }
604
605 uintptr_t thread_id(void)
606 {
607     return thread_self()->id;
608 }
609
610 uintptr_t thread_get_id(struct thread *t)
611 {
612     return t->id;
613 }
614
615 void thread_set_id(uintptr_t id)
616 {
617     struct thread *me = thread_self();
618     me->id = id;
619 }
620
621 uint32_t thread_set_token(struct waitset_chanstate *channel)
622 {
623     struct thread *me = thread_self();
624     // generate new token
625     uint32_t outgoing_token = (uint32_t)((me->id << 16) |
626          (me->coreid << 24) | ((me->token_number & 255) << 8)) | 1;
627     assert(me->token == 0);
628     me->token_number++;
629     if (!(me->token_number & 255))
630         me->token_number = 1;
631     me->token = outgoing_token & ~1;    // wait for this token
632     me->channel = channel;              // on that channel
633     return outgoing_token;
634 }
635
636 void thread_clear_token(struct waitset_chanstate *channel)
637 {
638     struct thread *me = thread_self();
639
640     me->token = 0;      // don't wait anymore
641     me->channel = NULL;
642 }
643
644 uint32_t thread_current_token(void)
645 {
646     return thread_self()->token;
647 }
648
649 void thread_set_outgoing_token(uint32_t token)
650 {
651     struct thread *me = thread_self();
652
653     assert(!me->outgoing_token);
654     me->outgoing_token = token;
655 }
656
657 void thread_get_outgoing_token(uint32_t *token)
658 {
659     struct thread *me = thread_self();
660     // if thread's outgoing token is set, get it
661     if (me->outgoing_token) {
662         *token = me->outgoing_token;
663         me->outgoing_token = 0;
664     }
665 }
666
667 void thread_set_local_trigger(struct waitset_chanstate *trigger)
668 {
669     struct thread *me = thread_self();
670     me->local_trigger = trigger;
671 }
672
673 struct waitset_chanstate * thread_get_local_trigger(void)
674 {
675     struct thread *me = thread_self();
676     return me->local_trigger;
677 }
678
679 void thread_set_rpc_in_progress(bool v)
680 {
681     thread_self()->rpc_in_progress = v;
682 }
683
684 bool thread_get_rpc_in_progress(void)
685 {
686     return thread_self()->rpc_in_progress;
687 }
688
689 void thread_set_async_error(errval_t e)
690 {
691     thread_self()->async_error = e;
692 }
693
694 errval_t thread_get_async_error(void)
695 {
696     return thread_self()->async_error;
697 }
698
699 /**
700  * \brief Store receive slot provided by rpc in thread state
701  */
702 void thread_store_recv_slot(struct capref recv_slot)
703 {
704     dispatcher_handle_t handle = disp_disable();
705     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
706
707     assert(disp_gen->recv_slot_count < MAX_RECV_SLOTS);
708     assert(disp_gen->recv_slot_count >= 0);
709     disp_gen->recv_slots[disp_gen->recv_slot_count++] = recv_slot;
710
711     disp_enable(handle);
712 }
713
714 struct capref thread_get_next_recv_slot(void)
715 {
716     dispatcher_handle_t handle = disp_disable();
717     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
718     struct capref retcap;
719
720     // HERE: recv_slot_count is > 0 if we have one+ caps stored
721     if (disp_gen->recv_slot_count <= 0) {
722         retcap = NULL_CAP;
723     } else {
724         retcap = disp_gen->recv_slots[--disp_gen->recv_slot_count];
725     }
726     disp_enable(handle);
727     return retcap;
728 }
729
730 void thread_set_status(int status) {
731     struct thread *me = thread_self();
732     me->return_value = status;
733 }
734
735 /**
736  * \brief Yield the calling thread
737  *
738  * Switches to the next runnable thread in this dispatcher, or if none is
739  * available, yields the dispatcher.
740  */
741 void thread_yield(void)
742 {
743     dispatcher_handle_t handle = disp_disable();
744     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
745     struct dispatcher_shared_generic *disp =
746         get_dispatcher_shared_generic(handle);
747     arch_registers_state_t *enabled_area =
748         dispatcher_get_enabled_save_area(handle);
749
750     struct thread *me = disp_gen->current;
751     struct thread *next = me;
752     me->yield_epoch = disp_gen->timeslice;
753
754     do {
755         assert_disabled(next != NULL);
756         next = next->next;
757         if (next == me) {
758             break; // Everybody yielded this timeslice
759         }
760     } while(next->yield_epoch == disp_gen->timeslice);
761
762     poll_channels_disabled(handle);
763
764     if (next != me) {
765         fpu_context_switch(disp_gen, next);
766         disp_gen->current = next;
767         disp_switch(handle, &me->regs, &next->regs);
768     } else {
769         assert_disabled(disp_gen->runq != NULL);
770         assert_disabled(disp->haswork);
771         trace_event(TRACE_SUBSYS_THREADS, TRACE_EVENT_THREADS_C_DISP_SAVE, 3);
772         disp_save(handle, enabled_area, true, CPTR_NULL);
773     }
774 }
775
776 /**
777  * \brief Yield both the calling thread, and the dispatcher to another domain
778  *
779  * \param endpoint Endpoint cap to which we wish to yield, or #CAP_NULL
780  *                  for an undirected yield
781  *
782  * Yields the dispatcher, optionally to another specified dispatcher.
783  */
784 void thread_yield_dispatcher(struct capref endpoint)
785 {
786     dispatcher_handle_t handle = disp_disable();
787     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
788     struct dispatcher_shared_generic *disp =
789         get_dispatcher_shared_generic(handle);
790     arch_registers_state_t *enabled_area =
791         dispatcher_get_enabled_save_area(handle);
792
793     assert_disabled(disp_gen->runq != NULL);
794     assert_disabled(disp->haswork);
795
796     trace_event(TRACE_SUBSYS_THREADS, TRACE_EVENT_THREADS_C_DISP_SAVE, 1);
797     disp_save(handle, enabled_area, true, get_cap_addr(endpoint));
798 }
799
800 /// Function that runs on the static thread/stack to clean up a "real" (alloced) thread
801 static int cleanup_thread(void *arg)
802 {
803     struct thread *thread = arg;
804
805     // free old thread and its stack
806     if (thread != NULL) {
807         free_thread(thread);
808     }
809
810     // disable and release static thread
811     dispatcher_handle_t handle = disp_disable();
812     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
813     struct dispatcher_shared_generic *disp =
814         get_dispatcher_shared_generic(handle);
815     struct thread *me = disp_gen->current;
816     struct thread *ft =
817         thread_mutex_unlock_disabled(handle, &disp_gen->cleanupthread_lock);
818     assert(ft == NULL);
819
820     // run the next thread, if any
821     struct thread *next = me->next;
822     thread_remove_from_queue(&disp_gen->runq, me);
823     if (next != me) {
824         disp_gen->current = next;
825         disp_resume(handle, &next->regs);
826     } else {
827         disp_gen->current = NULL;
828         disp->haswork = havework_disabled(handle);
829         disp_yield_disabled(handle);
830     }
831
832     return 0;
833 }
834
835 /**
836  * \brief Terminate the calling thread
837  */
838 void thread_exit(int status)
839 {
840     struct thread *me = thread_self();
841
842     thread_mutex_lock(&me->exit_lock);
843
844     // if this is the static thread, we don't need to do anything but cleanup
845     if (me == &staticthread) {
846         assert(me->detached);
847         // disable and release static thread
848         dispatcher_handle_t handle = disp_disable();
849         struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
850         struct dispatcher_shared_generic *disp =
851             get_dispatcher_shared_generic(handle);
852         assert_disabled(me == &staticthread);
853         assert_disabled(me->stack == staticstack);
854         struct thread *ft =
855             thread_mutex_unlock_disabled(handle, &staticthread_lock);
856         assert(ft == NULL);
857
858 #ifdef FPU_LAZY_CONTEXT_SWITCH
859         // No more FPU usage from here on
860         if(disp_gen->fpu_thread == me) {
861             disp_gen->fpu_thread = NULL;
862             fpu_trap_on();
863         }
864 #endif
865
866         // run the next thread, if any
867         struct thread *next = me->next;
868         thread_remove_from_queue(&disp_gen->runq, me);
869         if (next != me) {
870             fpu_context_switch(disp_gen, next);
871             disp_gen->current = next;
872             disp_resume(handle, &next->regs);
873         } else {
874             disp_gen->current = NULL;
875             disp->haswork = havework_disabled(handle);
876             disp_yield_disabled(handle);
877         }
878     }
879
880     if(me->detached) {
881         // otherwise, we use a dispatcher-local thread to perform cleanup
882         struct dispatcher_generic *dg = get_dispatcher_generic(curdispatcher());
883         thread_mutex_lock(&dg->cleanupthread_lock);
884         if(dg->cleanupthread == NULL) {
885             dg->cleanupthread =
886                 thread_create_unrunnable(cleanup_thread, me,
887                                          THREADS_DEFAULT_STACK_BYTES);
888         }
889         thread_init(curdispatcher(), dg->cleanupthread);
890
891         registers_set_initial(&dg->cleanupthread->regs, dg->cleanupthread,
892                               (lvaddr_t)cleanup_thread,
893                               (lvaddr_t)dg->cleanupthread->stack_top, (lvaddr_t)me,
894                               0, 0, 0);
895
896         // Switch to it (on this dispatcher)
897         dispatcher_handle_t handle = disp_disable();
898         struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
899
900 #ifdef FPU_LAZY_CONTEXT_SWITCH
901         // No more FPU usage from here on
902         if(disp_gen->fpu_thread == me) {
903             disp_gen->fpu_thread = NULL;
904             fpu_trap_on();
905         }
906 #endif
907
908         thread_remove_from_queue(&disp_gen->runq, me);
909         thread_enqueue(dg->cleanupthread, &disp_gen->runq);
910         disp_gen->cleanupthread->disp = handle;
911         fpu_context_switch(disp_gen, dg->cleanupthread);
912         disp_gen->current = dg->cleanupthread;
913         disp_resume(handle, &dg->cleanupthread->regs);
914     } else {
915         // We're not detached -- wakeup joiner
916         me->return_value = status;
917         me->state = THREAD_STATE_EXITED;
918         thread_cond_signal(&me->exit_condition);
919
920         // Disable and unlock exit lock
921         dispatcher_handle_t handle = disp_disable();
922         struct thread *wakeup =
923             thread_mutex_unlock_disabled(handle, &me->exit_lock);
924         struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
925         struct dispatcher_shared_generic *disp =
926             get_dispatcher_shared_generic(handle);
927
928         assert_disabled(wakeup == NULL);
929
930 #ifdef FPU_LAZY_CONTEXT_SWITCH
931         // No more FPU usage from here on
932         if(disp_gen->fpu_thread == me) {
933             disp_gen->fpu_thread = NULL;
934             fpu_trap_on();
935         }
936 #endif
937
938         // run the next thread, if any
939         struct thread *next = me->next;
940         thread_remove_from_queue(&disp_gen->runq, me);
941         if (next != me) {
942             fpu_context_switch(disp_gen, next);
943             disp_gen->current = next;
944             disp_resume(handle, &next->regs);
945         } else {
946             disp_gen->current = NULL;
947             disp->haswork = havework_disabled(handle);
948             disp_yield_disabled(handle);
949         }
950     }
951
952     USER_PANIC("should never be reached");
953 }
954
955 /**
956  * \brief Block the caller, and optionally release a spinlock, while disabled
957  *
958  * The caller is unconditionally blocked, and placed into the given queue
959  * pending a call that will unblock it. After manipulating the queues, and
960  * before switching threds, the given spinlock, if specified, is unlocked.
961  * This function must only be called while disabled.
962  *
963  * This function is intended for use by multi-processor thread synchronisation
964  * functions.
965  *
966  * \param disp Dispatcher pointer
967  * \param queue (Optional) Queue of threads in which to place caller
968  * \param spinlock (Optional) pointer to spinlock
969  *
970  * \returns Argument passed to thread_unblock, when unblocked
971  */
972 void *thread_block_and_release_spinlock_disabled(dispatcher_handle_t handle,
973                                                  struct thread **queue,
974                                                  spinlock_t *spinlock)
975 {
976     struct dispatcher_shared_generic *disp =
977         get_dispatcher_shared_generic(handle);
978     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
979     struct thread *me = disp_gen->current;
980     struct thread *next = me->next;
981     assert_disabled(next != NULL);
982
983     assert_disabled(me->state == THREAD_STATE_RUNNABLE);
984     me->state = THREAD_STATE_BLOCKED;
985
986     thread_remove_from_queue(&disp_gen->runq, me);
987     if (queue != NULL) {
988         thread_enqueue(me, queue);
989     }
990
991     if (spinlock != NULL) {
992         release_spinlock(spinlock);
993     }
994
995     if (next != me) {
996         assert_disabled(disp_gen->runq != NULL);
997         fpu_context_switch(disp_gen, next);
998         disp_gen->current = next;
999         disp_switch(handle, &me->regs, &next->regs);
1000     } else {
1001         assert_disabled(disp_gen->runq == NULL);
1002         disp_gen->current = NULL;
1003         disp->haswork = havework_disabled(handle);
1004         trace_event(TRACE_SUBSYS_THREADS, TRACE_EVENT_THREADS_C_DISP_SAVE, 2);
1005         disp_save(handle, &me->regs, true, CPTR_NULL);
1006     }
1007
1008     assert(me->disp == handle); // didn't migrate while asleep
1009     return me->wakeup_reason;
1010 }
1011
1012 /**
1013  * \brief Block the calling thread, while disabled
1014  *
1015  * The caller is unconditionally blocked, and placed into the given queue
1016  * pending a call that will unblock it.
1017  * This function must only be called while disabled.
1018  *
1019  * \param disp Dispatcher pointer
1020  * \param queue Queue of threads in which to place caller
1021  *
1022  * \returns Argument passed to thread_unblock, when unblocked
1023  */
1024 void *thread_block_disabled(dispatcher_handle_t disp, struct thread **queue)
1025 {
1026     return thread_block_and_release_spinlock_disabled(disp, queue, NULL);
1027 }
1028
1029 /**
1030  * \brief Block the calling thread, while enabled
1031  *
1032  * The caller is unconditionally blocked, and placed into the given queue
1033  * pending a call that will unblock it.
1034  * This function must only be called while enabled.
1035  *
1036  * \param queue Queue of threads in which to place caller
1037  *
1038  * \returns Argument passed to thread_unblock, when unblocked
1039  */
1040 void *thread_block(struct thread **queue)
1041 {
1042     return thread_block_disabled(disp_disable(), queue);
1043 }
1044
1045 /**
1046  * \brief Unblock a single thread from a given queue, while disabled
1047  *
1048  * A single thread is removed from the queue of blocked threads, and awoken.
1049  * This function must only be called while disabled.
1050  *
1051  * \param disp   Dispatcher pointer
1052  * \param queue  Queue of threads from which to unblock one
1053  * \param reason Value to be returned from thread_block()
1054  *
1055  * \returns Pointer to thread to be woken on a foreign dispatcher
1056  */
1057 struct thread *thread_unblock_one_disabled(dispatcher_handle_t handle,
1058                                            struct thread **queue,
1059                                            void *reason)
1060 {
1061     assert_disabled(queue != NULL);
1062
1063     // Any threads in queue?
1064     if (*queue == NULL) {
1065         return NULL;
1066     }
1067
1068     // Wakeup one waiting thread
1069     struct thread *wakeup = thread_dequeue(queue);
1070     wakeup->wakeup_reason = reason;
1071     assert_disabled(wakeup->state == THREAD_STATE_BLOCKED);
1072     wakeup->state = THREAD_STATE_RUNNABLE;
1073
1074     /* enqueue on run queue if it's "our" thread, and not paused */
1075     if (wakeup->disp == handle) {
1076         if (!wakeup->paused) {
1077             struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
1078             thread_enqueue(wakeup, &disp_gen->runq);
1079         }
1080         return NULL;
1081     } else {
1082         return wakeup;
1083     }
1084 }
1085
1086 /**
1087  * \brief Unblock a single thread from a given queue, while enabled
1088  *
1089  * A single thread is removed from the queue of blocked threads, and awoken.
1090  * This function must only be called while enabled.
1091  *
1092  * \param queue  Queue of threads from which to unblock one
1093  * \param reason Value to be returned from thread_block()
1094  *
1095  * \returns Pointer to thread to be woken on a foreign dispatcher
1096  */
1097 struct thread *thread_unblock_one(struct thread **queue, void *reason)
1098 {
1099     struct thread *thread;
1100
1101     dispatcher_handle_t handle = disp_disable();
1102     thread = thread_unblock_one_disabled(handle, queue, reason);
1103     disp_enable(handle);
1104     return thread;
1105 }
1106
1107 /**
1108  * \brief Unblock all threads on a given queue, while disabled
1109  *
1110  * All threads on the queue of blocked threads are awoken.
1111  * This function must only be called while disabled.
1112  *
1113  * \param disp   Dispatcher pointer
1114  * \param queue  Queue of threads to unblock
1115  * \param reason Value to be returned from thread_block()
1116  *
1117  * \returns Pointer to list of threads to be woken on a foreign dispatcher
1118  */
1119 struct thread *thread_unblock_all_disabled(dispatcher_handle_t handle,
1120                                            struct thread **queue, void *reason)
1121 {
1122     assert_disabled(queue != NULL);
1123     struct thread *wakeupq = NULL;
1124
1125     // Wakeup all waiting threads
1126     while (*queue != NULL) {
1127         struct thread *wakeup = thread_unblock_one_disabled(handle, queue, reason);
1128         if (wakeup != NULL) {
1129             wakeup->next = wakeupq;
1130             wakeupq = wakeup;
1131         }
1132     }
1133
1134     return wakeupq;
1135 }
1136
1137 extern int _main(int argc, const char *argv[]);
1138
1139 /// Thread created in new domain that runs main()
1140 static int main_thread(void *params)
1141 {
1142     struct spawn_domain_params *p = params;
1143     exit(_main(p->argc, p->argv));
1144     return EXIT_FAILURE;
1145 }
1146
1147 static bool init_domain_global; // XXX
1148
1149 /// Thread created on static stack in new domain that runs init code
1150 static int bootstrap_thread(struct spawn_domain_params *params)
1151 //int bootstrap_thread(struct spawn_domain_params *params);
1152 //int bootstrap_thread(struct spawn_domain_params *params)
1153 {
1154     errval_t err;
1155
1156     // Set libc function pointers
1157     barrelfish_libc_glue_init();
1158
1159     if (params == NULL) {
1160         printf("%s: error in creating a thread, NULL parameters given\n",
1161                 disp_name());
1162     }
1163     assert(params != NULL);
1164
1165     // Do we have TLS data?
1166     tls_block_init_base = params->tls_init_base;
1167     tls_block_init_len = params->tls_init_len;
1168     tls_block_total_len = params->tls_total_len;
1169
1170     // Initialize subsystems
1171     err = barrelfish_init_onthread(params);
1172     if (err_is_fail(err)) {
1173         DEBUG_ERR(err, "error during libbarrelfish init");
1174         exit(EXIT_FAILURE);
1175         assert(!"exit returned!");
1176     }
1177
1178     // Allocate storage region for real threads
1179     size_t blocksize = sizeof(struct thread) + tls_block_total_len;
1180     err = vspace_mmu_aware_init(&thread_slabs_vm, MAX_THREADS * blocksize);
1181     if (err_is_fail(err)) {
1182         USER_PANIC_ERR(err, "vspace_mmu_aware_init for thread region failed\n");
1183     }
1184     slab_init(&thread_slabs, blocksize, refill_thread_slabs);
1185
1186     if (init_domain_global) {
1187         // run main() on this thread, since we can't allocate
1188         if (tls_block_total_len > 0) {
1189             USER_PANIC("unsupported: use of TLS data in bootstrap domain\n");
1190         }
1191         main_thread(params);
1192     } else {
1193         // Start real thread to run main()
1194         struct thread *thread = thread_create(main_thread, params);
1195         assert(thread != NULL);
1196     }
1197
1198     return 0; // ignored
1199 }
1200
1201 /**
1202  * \brief Initialise thread system while still disabled
1203  *
1204  * This function initialises the thread system while the dispatcher is still
1205  * disabled, before enabling the dispatcher, running the general initialisation
1206  * code, and calling main().
1207  *
1208  * \param disp Dispatcher pointer
1209  * \param init_domain True if we are a bootstrap domain
1210  */
1211 void thread_init_disabled(dispatcher_handle_t handle, bool init_domain)
1212 {
1213     struct dispatcher_shared_generic *disp =
1214         get_dispatcher_shared_generic(handle);
1215     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
1216     arch_registers_state_t *enabled_area =
1217         dispatcher_get_enabled_save_area(handle);
1218
1219     init_domain_global = init_domain;
1220
1221     // Create the first thread manually
1222     struct thread *thread = &staticthread;
1223     staticthread_lock.locked = true; // XXX: safe while disabled
1224
1225     // waste space for alignment, if unaligned
1226     thread->stack_top = (char *)thread->stack_top
1227         - (lvaddr_t)thread->stack_top % STACK_ALIGNMENT;
1228
1229     // Initialise the first (static) thread
1230     thread_init(handle, thread);
1231     thread->detached = true;
1232
1233 #if defined(__x86_64__)
1234     // create segment for TCB
1235     errval_t err = ldt_alloc_segment_disabled(handle, thread,
1236                                               &thread->thread_seg_selector);
1237     if (err_is_fail(err)) {
1238         USER_PANIC_ERR(err, "error allocating LDT segment for first thread");
1239     }
1240 #endif
1241
1242     uintptr_t param;
1243     registers_get_param(enabled_area, &param);
1244
1245     registers_set_initial(&thread->regs, thread, (lvaddr_t)thread_entry,
1246                           /* TODO: pass stack base and limit, choose in arch
1247                            * code (possibly setting up other hints on stack) */
1248                           (lvaddr_t)thread->stack_top,
1249                           (lvaddr_t)bootstrap_thread, param, 0, 0);
1250
1251     // Switch to it (always on this dispatcher)
1252     thread->disp = handle;
1253     thread_enqueue(thread, &disp_gen->runq);
1254     disp_gen->current = thread;
1255     disp->haswork = true;
1256     disp_resume(handle, &thread->regs);
1257 }
1258
1259 /**
1260  * \brief Called on the remote core when spanning a domain across cores
1261  *
1262  * Runs the provided thread after enqueuing it and enabling the dispatcher
1263  */
1264 void thread_init_remote(dispatcher_handle_t handle, struct thread *thread)
1265 {
1266     struct dispatcher_shared_generic *disp =
1267         get_dispatcher_shared_generic(handle);
1268     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
1269     thread_enqueue(thread, &disp_gen->runq);
1270     disp_gen->current = thread;
1271     disp->haswork = true;
1272     disp_resume(handle, &thread->regs);
1273 }
1274
1275 /**
1276  * \brief Prepare to span the current domain
1277  *
1278  * This is a kludge. It is called from domain.c when creating a new dispatcher,
1279  * and is responsible for pre-allocating all the storage that might be needed
1280  * for thread metadata in the slab allocator. It can go away once we sanely
1281  * manage the vspace across multiple dispatchers in a domain.
1282  */
1283 void threads_prepare_to_span(dispatcher_handle_t newdh)
1284 {
1285     static bool called;
1286
1287     if (!called) {
1288         called = true;
1289
1290         thread_mutex_lock(&thread_slabs_mutex);
1291         acquire_spinlock(&thread_slabs_spinlock);
1292
1293         while (slab_freecount(&thread_slabs) < MAX_THREADS - 1) {
1294             size_t size;
1295             void *buf;
1296             errval_t err;
1297
1298             size_t blocksize = sizeof(struct thread) + tls_block_total_len;
1299             err = vspace_mmu_aware_map(&thread_slabs_vm, 64 * blocksize,
1300                                        &buf, &size);
1301             if (err_is_fail(err)) {
1302                 if (err_no(err) == LIB_ERR_VSPACE_MMU_AWARE_NO_SPACE) {
1303                     // we've wasted space with fragmentation
1304                     // cross our fingers and hope for the best...
1305                     break;
1306                 }
1307                 USER_PANIC_ERR(err, "in vspace_mmu_aware_map while prefilling "
1308                                "thread slabs\n");
1309             }
1310
1311             slab_grow(&thread_slabs, buf, size);
1312         }
1313
1314         release_spinlock(&thread_slabs_spinlock);
1315         thread_mutex_unlock(&thread_slabs_mutex);
1316     }
1317 }
1318
1319 /**
1320  * \brief Pause (suspend execution of) the given thread, and optionally capture its register state
1321  *
1322  * The thread will not be run, until a subsequent call to thread_resume()
1323  */
1324 void thread_pause_and_capture_state(struct thread *thread,
1325                                     arch_registers_state_t **ret_regs,
1326                                     arch_registers_fpu_state_t **ret_fpuregs)
1327 {
1328     assert(thread != NULL);
1329     dispatcher_handle_t dh = disp_disable();
1330     struct dispatcher_generic *disp = get_dispatcher_generic(dh);
1331     if (thread->disp == dh) {
1332         if (!thread->paused) {
1333             thread->paused = true;
1334             if (thread == disp->current) { // doesn't make much sense...
1335                 sys_print("Warning: pausing current thread!\n",100);
1336                 assert_disabled(thread->state == THREAD_STATE_RUNNABLE);
1337                 thread_block_disabled(dh, NULL);
1338             } else if (thread->state == THREAD_STATE_RUNNABLE) {
1339                 thread_remove_from_queue(&disp->runq, thread);
1340             }
1341         }
1342         if (ret_regs != NULL) {
1343             *ret_regs = &thread->regs;
1344         }
1345         if (ret_fpuregs != NULL) {
1346             if (thread->used_fpu) {
1347                 // FIXME: this may not be the right FPU state?
1348                 *ret_fpuregs = &thread->fpu_state;
1349             } else {
1350                 *ret_fpuregs = NULL;
1351             }
1352         }
1353     } else {
1354         USER_PANIC("NYI: remote dispatcher thread_pause()");
1355     }
1356     disp_enable(dh);
1357 }
1358
1359 /**
1360  * \brief Pause (suspend execution of) the given thread
1361  *
1362  * The thread will not be run, until a subsequent call to thread_resume()
1363  */
1364 void thread_pause(struct thread *thread)
1365 {
1366     thread_pause_and_capture_state(thread, NULL, NULL);
1367 }
1368
1369 /**
1370  * \brief Resume execution of a thread previously suspended by thread_pause()
1371  */
1372 void thread_resume(struct thread *thread)
1373 {
1374     assert(thread != NULL);
1375     dispatcher_handle_t dh = disp_disable();
1376     struct dispatcher_generic *disp = get_dispatcher_generic(dh);
1377     if (thread->disp == dh) {
1378         if (thread->paused) {
1379             thread->paused = false;
1380             if (thread->state == THREAD_STATE_RUNNABLE) {
1381                 thread_enqueue(thread, &disp->runq);
1382             }
1383         }
1384     } else {
1385         USER_PANIC("NYI: remote dispatcher thread_resume()");
1386     }
1387     disp_enable(dh);
1388 }
1389
1390 /**
1391  * \brief Set old-style thread-local storage pointer.
1392  * \param p   User's pointer
1393  */
1394 void thread_set_tls(void *p)
1395 {
1396     struct thread *me = thread_self();
1397     me->userptr = p;
1398 }
1399
1400 void thread_set_tls_key(int key, void *p)
1401 {
1402     struct thread *me = thread_self();
1403     me->userptrs[key] = p;
1404 }
1405
1406 /**
1407  * \brief Return old-style thread-local storage pointer.
1408  * \return User's pointer, previously passed to thread_set_tls()
1409  */
1410 void *thread_get_tls(void)
1411 {
1412     struct thread *me = thread_self();
1413     return me->userptr;
1414 }
1415
1416 void *thread_get_tls_key(int key)
1417 {
1418     struct thread *me = thread_self();
1419     return me->userptrs[key];
1420 }
1421
1422 /**
1423  * \brief Set the exception handler function for the current thread.
1424  *        Optionally also change its stack, and return the old values.
1425  *
1426  * \param newhandler New exception handler. Pass NULL to disable an existing handler.
1427  * \param oldhandler If non-NULL, returns previous exception handler
1428  * \param new_stack_base If non-NULL, sets a new exception handler stack (base)
1429  * \param new_stack_top  If non-NULL, sets a new exception handler stack (top)
1430  * \param old_stack_base If non-NULL, returns previous stack base
1431  * \param old_stack_top If non-NULL, returns previous stack top
1432  */
1433 errval_t thread_set_exception_handler(exception_handler_fn newhandler,
1434                                       exception_handler_fn *oldhandler,
1435                                       void *new_stack_base, void *new_stack_top,
1436                                       void **old_stack_base, void **old_stack_top)
1437 {
1438     struct thread *me = thread_self();
1439
1440     if (oldhandler != NULL) {
1441         *oldhandler = me->exception_handler;
1442     }
1443
1444     if (old_stack_base != NULL) {
1445         *old_stack_base = me->exception_stack;
1446     }
1447
1448     if (old_stack_top != NULL) {
1449         *old_stack_top = me->exception_stack_top;
1450     }
1451
1452     me->exception_handler = newhandler;
1453
1454     if (new_stack_base != NULL && new_stack_top != NULL) {
1455         me->exception_stack = new_stack_base;
1456         me->exception_stack_top = new_stack_top;
1457     }
1458
1459     return SYS_ERR_OK;
1460 }
1461
1462 static void exception_handler_wrapper(arch_registers_state_t *cpuframe,
1463                                       arch_registers_fpu_state_t *fpuframe,
1464                                       uintptr_t hack_arg, void *addr)
1465 {
1466     struct thread *me = thread_self();
1467
1468     assert(me->in_exception);
1469     assert(me->exception_handler != NULL);
1470
1471     // XXX: unpack hack arg
1472     enum exception_type type = hack_arg >> 16;
1473     int subtype = hack_arg & 0xffff;
1474
1475     // run handler
1476     me->exception_handler(type, subtype, addr, cpuframe, fpuframe);
1477
1478     // resume state
1479     dispatcher_handle_t dh = disp_disable();
1480     struct dispatcher_generic *disp_gen = get_dispatcher_generic(dh);
1481     //memcpy(&me->regs, cpuframe, sizeof(arch_registers_state_t));
1482
1483 #ifdef FPU_LAZY_CONTEXT_SWITCH
1484     if (fpuframe != NULL) {
1485         assert_disabled(me->used_fpu);
1486         arch_registers_fpu_state_t *dest;
1487         if (disp_gen->fpu_thread == me) {
1488             dest = dispatcher_get_enabled_fpu_save_area(dh);
1489         } else {
1490             dest = &me->fpu_state;
1491         }
1492         fpu_copy(dest, fpuframe);
1493         fpu_trap_on();
1494     }
1495 #endif
1496
1497     assert_disabled(me->in_exception);
1498     me->in_exception = false;
1499
1500     assert_disabled(disp_gen->current == me);
1501     disp_resume(dh, cpuframe);
1502 }
1503
1504 #if 0
1505 void thread_debug_regs(struct thread *t);
1506 void thread_debug_regs(struct thread *t)
1507 {
1508   printf("%d: RIP = %lx, RSP = %lx\n", disp_get_domain_id(),
1509          t->regs.rip, t->regs.rsp);
1510   uint64_t *stack = (uint64_t *)t->regs.rsp;
1511   printf("%d: ", disp_get_domain_id());
1512   for(int i = 0; i < 30; i++) {
1513     printf("%lx ", stack[i]);
1514   }
1515   printf("\n");
1516 }
1517 #endif
1518
1519 /**
1520  * \brief Deliver an exception to the current thread, and resume.
1521  *
1522  * This may only be called from the dispatcher (on its stack and while
1523  * disabled!).
1524  *
1525  * \param handle Dispatcher handle
1526  * \param type   Exception type
1527  * \param subtype Exception subtype
1528  * \param addr   Exception address
1529  * \param regs   CPU register state at time of exception
1530  */
1531 void thread_deliver_exception_disabled(dispatcher_handle_t handle,
1532                                        enum exception_type type, int subtype,
1533                                        void *addr, arch_registers_state_t *regs)
1534 {
1535     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
1536     struct thread *thread = disp_gen->current;
1537     assert_disabled(thread != NULL);
1538     assert_disabled(disp_gen->runq != NULL);
1539
1540     // can we deliver the exception?
1541     if (thread->exception_handler == NULL || thread->exception_stack_top == NULL
1542         || thread->in_exception) {
1543         if (thread->in_exception) {
1544             sys_print("Can't deliver exception to thread: already in handler\n",
1545                       100);
1546         } else {
1547             sys_print("Can't deliver exception to thread: handler not set\n",
1548                       100);
1549         }
1550
1551         // warn on stack overflow.
1552         lvaddr_t sp = (lvaddr_t) registers_get_sp(regs);
1553         if (sp < (lvaddr_t)thread->stack ||
1554             sp > (lvaddr_t)thread->stack_top) {
1555             char str[256];
1556             snprintf(str, sizeof(str), "Error: stack bounds exceeded: sp = 0x%"
1557                      PRIxPTR " but [bottom, top] = [0x%" PRIxPTR ", 0x%"
1558                      PRIxPTR "]\n", (lvaddr_t) sp, (lvaddr_t) thread->stack,
1559                      (lvaddr_t) thread->stack_top);
1560             sys_print(str, sizeof(str));
1561         }
1562
1563         // TODO: actually delete the thread!
1564         disp_gen->current = NULL;
1565         thread_remove_from_queue(&disp_gen->runq, thread);
1566         return;
1567     }
1568
1569     thread->in_exception = true;
1570
1571     lvaddr_t stack_top = (lvaddr_t)thread->exception_stack_top;
1572
1573     // save thread's state at time of fault on top of exception stack
1574     stack_top -= sizeof(arch_registers_state_t);
1575     arch_registers_state_t *cpuframe = (void *)stack_top;
1576     memcpy(cpuframe, regs, sizeof(arch_registers_state_t));
1577
1578     arch_registers_fpu_state_t *fpuframe = NULL;
1579 #ifdef FPU_LAZY_CONTEXT_SWITCH
1580     if (thread->used_fpu) {
1581         stack_top -= sizeof(arch_registers_fpu_state_t);
1582         fpuframe = (void *)stack_top;
1583         fpu_copy(fpuframe, &thread->fpu_state);
1584     }
1585 #endif
1586
1587     // align stack
1588     stack_top -= stack_top % STACK_ALIGNMENT;
1589
1590     // XXX: sanity-check to ensure we have a sensible amount of exception stack left
1591     assert_disabled(stack_top > (lvaddr_t)thread->exception_stack + 8192);
1592
1593     // XXX: pack two small ints together to fit into a single register
1594     uintptr_t hack_arg = (uintptr_t)type << 16 | (subtype & 0xffff);
1595
1596     registers_set_initial(&thread->regs, thread,
1597                           (lvaddr_t)exception_handler_wrapper,
1598                           stack_top, (lvaddr_t)cpuframe, (lvaddr_t)fpuframe,
1599                           hack_arg, (lvaddr_t)addr);
1600
1601     disp_resume(handle, &thread->regs);
1602 }