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