Fix bug in libdomain/domain_cap_hash()
[barrelfish] / lib / barrelfish / domain.c
1 /**
2  * \file
3  * \brief Manage domain spanning cores
4  *
5  * \bug Need to specify how big the default thread on the spanned dispatcher
6  * should be because we cannot dynamically grow our stacks
7  *
8  * \bug Can only do domain_new_dispatcher() when no other dispatchers have
9  * threads (except for the internal interdisp-thread).
10  */
11
12 /*
13  * Copyright (c) 2009, 2010, 2011, 2012, ETH Zurich.
14  * All rights reserved.
15  *
16  * This file is distributed under the terms in the attached LICENSE file.
17  * If you do not find this file, copies can be found by writing to:
18  * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
19  * Attn: Systems Group.
20  */
21
22 #include <limits.h>
23 #include <stdio.h>
24 #include <barrelfish/barrelfish.h>
25 #include <barrelfish/curdispatcher_arch.h>
26 #include <barrelfish/dispatcher_arch.h>
27 #include <barrelfish/monitor_client.h>
28 #include <barrelfish/waitset_chan.h>
29 #include <barrelfish_kpi/domain_params.h>
30 #include <arch/registers.h>
31 #include <barrelfish/dispatch.h>
32 #include <if/interdisp_defs.h>
33 #include "arch/threads.h"
34 #include "init.h"
35 #include <if/monitor_defs.h>
36 #include "threads_priv.h"
37 #include "waitset_chan_priv.h"
38
39 ///< Struct to maintain per dispatcher domain library state
40 struct domain_state {
41     iref_t iref;  ///< Iref for the interdisp service
42     struct interdisp_binding *binding[MAX_CPUS];
43     struct waitset interdisp_ws;
44     struct thread *default_waitset_handler;
45     struct thread *remote_wakeup_queue;
46     struct waitset_chanstate remote_wakeup_event;
47     bool conditional;
48 };
49
50 ///< Struct to send init information to the dispatcher that was spanned
51 struct remote_core_state {
52     iref_t iref;                  ///< Iref of the interdisp service to connect to
53     uint8_t core_id;              ///< Core id of the domain that spanned this dispatcher
54     struct span_domain_state *span_domain_state; ///< Reference to the span_domain_state of the "server"
55     bool initialized;             ///< true if remote core is fully initialized
56     int cnt;                      ///< Used to count dispatcher connected
57     size_t pagesize;              ///< the pagesize to be used for the heap
58 };
59
60 ///< Array of all interdisp IREFs in the domain
61 static iref_t allirefs[MAX_CPUS];
62
63 static void dispatcher_initialized_handler(void *arg)
64 {
65     struct span_domain_state *span_domain_state = arg;
66 #if 0
67     struct domain_state *domain_state = get_domain_state();
68
69     // XXX: Tell currently active interdisp-threads to handle default waitset
70     for(int i = 0; i < MAX_CPUS; i++) {
71         struct interdisp_binding *b = domain_state->binding[i];
72
73         if(disp_get_core_id() != i &&
74            span_domain_state->core_id != i && b != NULL) {
75             errval_t err = b->tx_vtbl.span_slave_done(b, NOP_CONT);
76             assert(err_is_ok(err));
77         }
78     }
79 #endif
80     /* Upcall into the domain_new_dispatcher callback if registered */
81     if (span_domain_state->callback) {
82         span_domain_state->callback(span_domain_state->callback_arg, SYS_ERR_OK);
83     }
84     span_domain_state->initialized = 1;
85     //free(span_domain_state);
86 }
87
88 /**
89  * \brief Handled for dispatcher_initialized msg type
90  *
91  * Called when a recently spanned dispatcher has initialized.
92  * Store it's connection object, and upcall into the registered callback
93  */
94 static void dispatcher_initialized(struct interdisp_binding *st, genvaddr_t id)
95 {
96     struct span_domain_state *span_domain_state = (struct span_domain_state*)(uintptr_t)id;
97
98     // Signal the default waitset of this event
99     struct event_closure closure = {
100         .handler = dispatcher_initialized_handler,
101         .arg = span_domain_state,
102     };
103     waitset_chanstate_init(&span_domain_state->initev, CHANTYPE_EVENT_QUEUE);
104     errval_t err = waitset_chan_trigger_closure(get_default_waitset(),
105                                                 &span_domain_state->initev,
106                                                 closure);
107     if(err_is_fail(err)) {
108         USER_PANIC_ERR(err, "Triggering default waitset");
109     }
110 }
111
112 static void send_cap_request(struct interdisp_binding *st,
113                              struct capref cap, genvaddr_t info)
114 {
115     errval_t err = SYS_ERR_OK, err2;
116     struct capref *dest = (struct capref *)(uintptr_t)info;
117
118     err = cap_copy(*dest, cap);
119     if(err_is_fail(err)) {
120         err_push(err, LIB_ERR_CAP_COPY_FAIL);
121         DEBUG_ERR(err, "cap_copy");
122         abort();
123         goto send_reply;
124     }
125     err = cap_destroy(cap);
126     if(err_is_fail(err)) {
127         err_push(err, LIB_ERR_CAP_DELETE_FAIL);
128         DEBUG_ERR(err, "cap_destroy default");
129         abort();
130         goto send_reply;
131     }
132
133  send_reply:
134     err2 = st->tx_vtbl.send_cap_reply(st, NOP_CONT, err);
135     if (err_is_fail(err2)) {
136         DEBUG_ERR(err, "Failed to send send_cap_reply");
137     }
138 }
139
140 static errval_t send_cap_err = SYS_ERR_OK;
141 static bool cap_received = false;
142
143 static void send_cap_reply(struct interdisp_binding *st, errval_t err)
144 {
145     send_cap_err = err;
146     cap_received = true;
147 }
148
149 static void create_thread_request(struct interdisp_binding *b,
150                                   genvaddr_t funcaddr, genvaddr_t argaddr,
151                                   uint64_t stacksize, genvaddr_t req)
152 {
153     thread_func_t start_func = (thread_func_t)(uintptr_t)funcaddr;
154     void *arg = (void *)(uintptr_t)argaddr;
155     struct thread *newthread;
156
157     // XXX: Probably want to return pointer to thread struct to caller
158     if(stacksize > 0) {
159         newthread = thread_create_varstack(start_func, arg, stacksize);
160     } else {
161         newthread = thread_create(start_func, arg);
162     }
163     assert(newthread != NULL);
164     errval_t err = b->tx_vtbl.create_thread_reply(b, NOP_CONT, SYS_ERR_OK,
165                                                   (genvaddr_t)(lvaddr_t)newthread,
166                                                   req);
167     assert(err_is_ok(err));
168 }
169
170 struct create_thread_req {
171     struct thread *thread;
172     bool reply_received;
173 };
174
175 static void create_thread_reply(struct interdisp_binding *b,
176                                 errval_t err, genvaddr_t thread, genvaddr_t req)
177 {
178     assert(err_is_ok(err));
179     // fill out request
180     struct create_thread_req *r = (struct create_thread_req*)(lvaddr_t)req;
181     r->thread = (struct thread *)(lvaddr_t)thread;
182     r->reply_received = true;
183 }
184
185 static void wakeup_thread_request(struct interdisp_binding *b,
186                                   genvaddr_t taddr)
187 {
188     coreid_t core_id = disp_get_core_id();
189     struct thread *wakeup = (struct thread *)(uintptr_t)taddr;
190     dispatcher_handle_t handle = disp_disable();
191     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
192     /* assert_disabled(wakeup->disp == handle); */
193     assert_disabled(wakeup->coreid == core_id);
194     wakeup->disp = handle;
195     thread_enqueue(wakeup, &disp_gen->runq);
196     disp_enable(handle);
197 }
198
199 static void join_thread_request(struct interdisp_binding *b,
200                                 genvaddr_t taddr, genvaddr_t req)
201 {
202     struct thread *thread = (struct thread *)(lvaddr_t)taddr;
203     assert(thread->coreid == disp_get_core_id());
204     int retval = 0;
205     errval_t err = thread_join(thread, &retval);
206     err = b->tx_vtbl.join_thread_reply(b, NOP_CONT, err, retval, req);
207     assert(err_is_ok(err));
208 }
209
210 struct join_thread_req {
211     errval_t err;
212     int retval;
213     bool reply_received;
214 };
215
216 static void join_thread_reply(struct interdisp_binding *b,
217                               errval_t err, uint64_t retval, genvaddr_t req)
218 {
219     struct join_thread_req *r = (struct join_thread_req *)(lvaddr_t)req;
220     r->err = err;
221     r->retval = retval;
222     r->reply_received = true;
223 }
224
225 /*
226  * XXX: The whole span_slave*() thing is a hack to allow all
227  * dispatchers to wait on both the monitor and interdisp waitsets
228  * while we bind to all.
229  */
230
231 static int span_slave_thread(void *arg)
232 {
233     errval_t err = thread_detach(thread_self());
234     assert(err_is_ok(err));
235
236     for(;;) {
237         event_dispatch(get_default_waitset());
238     }
239
240     return 0;
241 }
242
243 static void span_slave_request(struct interdisp_binding *b)
244 {
245     USER_PANIC("shouldn't be called");
246     thread_create(span_slave_thread, NULL);
247 }
248
249 static void span_slave_done_handler(void *cs)
250 {
251     USER_PANIC("shouldn't be called");
252     free(cs);
253     thread_exit(0);
254 }
255
256 static void span_slave_done_request(struct interdisp_binding *b)
257 {
258     USER_PANIC("shouldn't be called");
259     struct waitset_chanstate *cs = malloc(sizeof(struct waitset_chanstate));
260
261     // Signal the default waitset of this event
262     struct event_closure closure = {
263         .handler = span_slave_done_handler,
264         .arg = cs,
265     };
266     waitset_chanstate_init(cs, CHANTYPE_EVENT_QUEUE);
267     errval_t err = waitset_chan_trigger_closure(get_default_waitset(), cs,
268                                                 closure);
269     if(err_is_fail(err)) {
270         USER_PANIC_ERR(err, "Triggering default waitset");
271     }
272 }
273
274 static void span_eager_connect_request(struct interdisp_binding *b,
275                                        coreid_t core_id)
276 {
277     struct domain_state *domain_state = get_domain_state();
278
279     /* Store the sending core's connection */
280     domain_state->binding[core_id] = b;
281 }
282
283 static struct interdisp_rx_vtbl interdisp_vtbl = {
284     .dispatcher_initialized = dispatcher_initialized,
285
286     .send_cap_request = send_cap_request,
287     .send_cap_reply = send_cap_reply,
288
289     .wakeup_thread         = wakeup_thread_request,
290     .create_thread_request = create_thread_request,
291     .create_thread_reply   = create_thread_reply,
292
293     .join_thread_request   = join_thread_request,
294     .join_thread_reply     = join_thread_reply,
295
296     // XXX: Hack to allow domain_new_dispatcher() to proceed when not all
297     // default waitsets are serviced
298     .span_slave       = span_slave_request,
299     .span_slave_done  = span_slave_done_request,
300     .span_eager_connect = span_eager_connect_request,
301 };
302
303 /**
304  * \brief Called when the "client" connects to "server"
305  *
306  * Make the connection a "server" connection, free unnecessary state.
307  * Send init msg to the dispatcher that spanned this dispatcher.
308  */
309 static void client_connected(void *st, errval_t err,
310                              struct interdisp_binding *b)
311 {
312     struct remote_core_state *state = (struct remote_core_state*)st;
313     struct domain_state *domain_state = get_domain_state();
314
315     if(err_is_fail(err)) {
316         DEBUG_ERR(err, "binding to interdisp service");
317         abort();
318     }
319
320     /* Set it on the domain library state */
321     b->rx_vtbl = interdisp_vtbl;
322     domain_state->binding[state->cnt] = b;
323
324     // Send it our core id
325     err = b->tx_vtbl.span_eager_connect(b, NOP_CONT, disp_get_core_id());
326     if(err_is_fail(err)) {
327         USER_PANIC_ERR(err, "sending span_eager_connect");
328     }
329
330     // Connect to next active dispatcher
331     do {
332         state->cnt++;
333         if(state->cnt == disp_get_core_id()) {
334             state->cnt++;
335         }
336     } while(allirefs[state->cnt] == NULL_IREF && state->cnt < MAX_CPUS);
337
338     if(state->cnt < MAX_CPUS) {
339         err = interdisp_bind(allirefs[state->cnt], client_connected,
340                              state, &domain_state->interdisp_ws,
341                              IDC_BIND_FLAGS_DEFAULT);
342         if(err_is_fail(err)) {
343             USER_PANIC_ERR(err, "Binding to inter-dispatcher service");
344         }
345     } else {
346         struct interdisp_binding *sb = domain_state->binding[state->core_id];
347         /* Send initialized msg to the dispatcher that spanned us */
348         errval_t err2 = sb->tx_vtbl.
349             dispatcher_initialized(sb, NOP_CONT,
350                                    (uintptr_t)state->span_domain_state);
351         if (err_is_fail(err2)) {
352             DEBUG_ERR(err, "failed to send initalized msg");
353             abort();
354         }
355
356         state->initialized = true;
357     }
358 }
359
360 static errval_t server_connected(void *st, struct interdisp_binding *b)
361 {
362     b->rx_vtbl = interdisp_vtbl;
363     return SYS_ERR_OK;
364 }
365
366 /**
367  * \brief Called when domain gets a interdisp service.
368  * It will set it on the domain_state.
369  */
370 static void server_listening(void *st, errval_t err, iref_t iref)
371 {
372     if(err_is_fail(err)) {
373         DEBUG_ERR(err, "interdisp service export");
374         abort();
375     }
376
377     struct domain_state *domain_state = get_domain_state();
378     domain_state->iref = iref;
379
380     // Also set in the global array
381     allirefs[disp_get_core_id()] = iref;
382     domain_state->conditional = true;
383 }
384
385 /**
386  * \brief Called on the inter-disp handler thread, when another thread
387  * on this dispatcher wants to wakeup a thread on a foreign dispatcher.
388  */
389 static void handle_wakeup_on(void *arg)
390 {
391     struct domain_state *domain_state = get_domain_state();
392     errval_t err;
393
394     assert(domain_state != NULL);
395
396     // Dequeue all (disable to ensure mutual exclusion -- per dispatcher)
397     for(;;) {
398         struct thread *thread = NULL;
399
400         dispatcher_handle_t disp = disp_disable();
401         if(domain_state->remote_wakeup_queue != NULL) {
402             thread = thread_dequeue(&domain_state->remote_wakeup_queue);
403         }
404         disp_enable(disp);
405
406         // Break if queue empty
407         if(thread == NULL) {
408             break;
409         }
410
411         // XXX: Hack
412         /* coreid_t core_id = disp_handle_get_core_id(thread->disp); */
413         coreid_t core_id = thread->coreid;
414
415         assert(domain_state->binding[core_id] != NULL);
416
417         struct interdisp_binding *b = domain_state->binding[core_id];
418         err = b->tx_vtbl.wakeup_thread(b, NOP_CONT, (genvaddr_t)(uintptr_t)thread);
419         if (err_is_fail(err)) {
420             USER_PANIC_ERR(err, "wakeup_thread");
421         }
422     }
423 }
424
425 /**
426  * \brief Handler thread for inter-dispatcher messages
427  * \param arg   Pointer to inter-dispatcher waitset
428  * \return 0 on successful exit
429  */
430 static int interdisp_msg_handler(void *arg)
431 {
432     struct waitset *ws = arg;
433     assert(ws != NULL);
434
435     debug_printf("Looping on inter-dispatcher message handler\n");
436     for(;;) {
437         errval_t err = event_dispatch(ws);
438         if(err_is_fail(err)) {
439             USER_PANIC_ERR(err, "error on event dispatch");
440         }
441     }
442
443     return 0;
444 }
445
446 /**
447  * \brief Runs enabled on the remote core to initialize the dispatcher
448  */
449 static int remote_core_init_enabled(void *arg)
450 {
451     errval_t err;
452     struct remote_core_state *remote_core_state =
453         (struct remote_core_state*)arg;
454
455     /* construct a temporary spawn param to supply the morecore alignment */
456     struct spawn_domain_params params;
457     memset(&params, 0, sizeof(params));
458     params.pagesize =  remote_core_state->pagesize;
459
460     /* Initialize the barrelfish library */
461     err = barrelfish_init_onthread(&params);
462     if (err_is_fail(err)) {
463         DEBUG_ERR(err, "barrelfish_init_onthread failed");
464         abort();
465         return -1;
466     }
467
468     // Connect to all dispatchers eagerly
469     remote_core_state->cnt = 0;
470     while(allirefs[remote_core_state->cnt] == NULL_IREF && remote_core_state->cnt < MAX_CPUS) {
471         remote_core_state->cnt++;
472         if(remote_core_state->cnt == disp_get_core_id()) {
473             remote_core_state->cnt++;
474         }
475     }
476     // Don't move before barrelfish_init_onthread()
477     struct domain_state *st = get_domain_state();
478     if(remote_core_state->cnt != MAX_CPUS) {
479         err = interdisp_bind(allirefs[remote_core_state->cnt], client_connected,
480                              remote_core_state, &st->interdisp_ws,
481                              IDC_BIND_FLAGS_DEFAULT);
482         if(err_is_fail(err)) {
483             USER_PANIC_ERR(err, "Failure binding to inter-dispatcher service");
484         }
485     }
486
487     while(!remote_core_state->initialized) {
488         event_dispatch(get_default_waitset());
489     }
490
491     /* Free unnecessary state */
492     free(remote_core_state);
493
494     /* XXX: create a thread that will handle the default waitset */
495     st->default_waitset_handler = thread_create(span_slave_thread, NULL);
496     assert(st->default_waitset_handler != NULL);
497
498     return interdisp_msg_handler(&st->interdisp_ws);
499 }
500
501 /**
502  * \brief Runs disabled on the remote core to initialize
503  */
504 static void remote_core_init_disabled(struct thread *thread)
505 {
506     dispatcher_handle_t disp = thread->disp;
507
508     /* Initialize the dispatcher */
509     disp_init_disabled(disp);
510
511     /* Initialize the threads library, and call remote_core_init_enabled */
512     thread_init_remote(disp, thread);
513 }
514
515 /**
516  * \brief Initialize the domain library
517  *
518  * Registers a iref with the monitor to offer the interdisp service on this core
519  * Does not block for completion.
520  */
521 errval_t domain_init(void)
522 {
523     errval_t err;
524     struct domain_state *domain_state = malloc(sizeof(struct domain_state));
525     if (!domain_state) {
526         return LIB_ERR_MALLOC_FAIL;
527     }
528     set_domain_state(domain_state);
529
530     domain_state->iref = 0;
531     domain_state->default_waitset_handler = NULL;
532     domain_state->remote_wakeup_queue = NULL;
533     waitset_chanstate_init(&domain_state->remote_wakeup_event,
534                            CHANTYPE_EVENT_QUEUE);
535     for (int i = 0; i < MAX_CPUS; i++) {
536         domain_state->binding[i] = NULL;
537     }
538
539     waitset_init(&domain_state->interdisp_ws);
540     domain_state->conditional = false;
541     err = interdisp_export(NULL, server_listening, server_connected,
542                            &domain_state->interdisp_ws, IDC_EXPORT_FLAGS_DEFAULT);
543     if (err_is_fail(err)) {
544         return err;
545     }
546
547     // XXX: Wait for the export to finish before returning
548     while(!domain_state->conditional) {
549         messages_wait_and_handle_next();
550     }
551
552     return SYS_ERR_OK;
553 }
554
555 /**
556  * \brief Handler to continue spanning domain state machine
557  */
558 static void span_domain_reply(struct monitor_binding *mb,
559                               errval_t msgerr, uintptr_t domain_id)
560 {
561     /* On success, no further action needed */
562     if (err_is_ok(msgerr)) {
563         return;
564     }
565
566     /* On failure, release resources and notify the caller */
567     struct span_domain_state *span_domain_state =
568         (struct span_domain_state*)domain_id;
569     errval_t err = cap_destroy(span_domain_state->frame);
570     if (err_is_fail(err)) {
571         err_push(msgerr, LIB_ERR_CAP_DESTROY);
572     }
573
574     if (span_domain_state->callback) { /* Use the callback to return error */
575         span_domain_state->callback(span_domain_state->callback_arg, msgerr);
576     } else { /* Use debug_err if no callback registered */
577         DEBUG_ERR(msgerr, "Failure in span_domain_reply");
578     }
579 }
580
581 static void span_domain_request_sender(void *arg)
582 {
583     struct monitor_binding *mb = arg;
584     struct span_domain_state *st = mb->st;
585
586     errval_t err = mb->tx_vtbl.
587         span_domain_request(mb, NOP_CONT, (uintptr_t)st, st->core_id, st->vroot,
588                             st->frame);
589     if (err_is_ok(err)) {
590         event_mutex_unlock(&mb->mutex);
591     } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
592         /* Wait to use the monitor binding */
593         err = mb->register_send(mb, mb->waitset,
594                                 MKCONT(span_domain_request_sender,mb));
595         if(err_is_fail(err)) { // shouldn't fail, as we have the mutex
596             USER_PANIC_ERR(err, "register_send");
597         }
598     } else { // permanent error
599         event_mutex_unlock(&mb->mutex);
600         err = err_push(err, MON_CLIENT_ERR_SPAN_DOMAIN_REQUEST);
601         DEBUG_ERR(err, "span_domain_request");
602     }
603 }
604
605 static void span_domain_request_sender_wrapper(void *st)
606 {
607     struct monitor_binding *mb = get_monitor_binding();
608     mb->st = st;
609     span_domain_request_sender(mb);
610 }
611
612 /**
613  * \brief Since we cannot dynamically grow our stack yet, we need a
614  * verion that will create threads on remote core with variable stack size
615  *
616  * \bug this is a hack
617  */
618 static errval_t domain_new_dispatcher_varstack(coreid_t core_id,
619                                                domain_spanned_callback_t callback,
620                                                void *callback_arg, size_t stack_size,
621                                                struct span_domain_state **ret_span_state)
622 {
623     assert(core_id != disp_get_core_id());
624
625     errval_t err;
626     struct domain_state *domain_state = get_domain_state();
627     assert(domain_state != NULL);
628
629     while(domain_state->iref == 0) { /* If not initialized, wait */
630         messages_wait_and_handle_next();
631     }
632
633     /* Create the remote_core_state passed to the new dispatcher */
634     struct remote_core_state *remote_core_state =
635         calloc(1, sizeof(struct remote_core_state));
636     if (!remote_core_state) {
637         return LIB_ERR_MALLOC_FAIL;
638     }
639     remote_core_state->core_id = disp_get_core_id();
640     remote_core_state->iref    = domain_state->iref;
641
642     /* get the alignment of the morecore state */
643     struct morecore_state *state = get_morecore_state();
644     remote_core_state->pagesize = state->mmu_state.alignment;
645
646     /* Create the thread for the new dispatcher to init on */
647     struct thread *newthread =
648         thread_create_unrunnable(remote_core_init_enabled,
649                                  (void*)remote_core_state, stack_size);
650     if (newthread == NULL) {
651         return LIB_ERR_THREAD_CREATE;
652     }
653
654     /* Save the state for later steps of the spanning state machine */
655     struct span_domain_state *span_domain_state =
656         malloc(sizeof(struct span_domain_state));
657     if (!span_domain_state) {
658         return LIB_ERR_MALLOC_FAIL;
659     }
660     span_domain_state->thread       = newthread;
661     span_domain_state->core_id      = core_id;
662     span_domain_state->callback     = callback;
663     span_domain_state->callback_arg = callback_arg;
664
665     /* Give remote_core_state pointer to span_domain_state */
666     remote_core_state->span_domain_state = span_domain_state;
667
668     /* Start spanning domain state machine by sending vroot to the monitor */
669     struct capref vroot = {
670         .cnode = cnode_page,
671         .slot = 0
672     };
673
674     /* Create new dispatcher frame */
675     struct capref frame;
676     size_t dispsize = ((size_t)1) << DISPATCHER_FRAME_BITS;
677     err = frame_alloc(&frame, dispsize, &dispsize);
678     if (err_is_fail(err)) {
679         return err_push(err, LIB_ERR_FRAME_ALLOC);
680     }
681     lvaddr_t dispaddr;
682
683     err = vspace_map_one_frame((void **)&dispaddr, dispsize, frame, NULL, NULL);
684     if (err_is_fail(err)) {
685         return err_push(err, LIB_ERR_VSPACE_MAP);
686     }
687
688     dispatcher_handle_t handle = dispaddr;
689     struct dispatcher_shared_generic *disp =
690         get_dispatcher_shared_generic(handle);
691     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
692     arch_registers_state_t *disabled_area =
693         dispatcher_get_disabled_save_area(handle);
694
695     /* Set dispatcher on the newthread */
696     span_domain_state->thread->disp = handle;
697     span_domain_state->frame = frame;
698     span_domain_state->vroot = vroot;
699
700     /* Setup dispatcher */
701     disp->udisp = (lvaddr_t)handle;
702     disp->disabled = true;
703     disp->fpu_trap = 1;
704     disp_gen->core_id = span_domain_state->core_id;
705     // Setup the dispatcher to run remote_core_init_disabled
706     // and pass the created thread as an argument
707     registers_set_initial(disabled_area, span_domain_state->thread,
708                           (lvaddr_t)remote_core_init_disabled,
709                           (lvaddr_t)&disp_gen->stack[DISPATCHER_STACK_WORDS],
710                           (uintptr_t)span_domain_state->thread, 0, 0, 0);
711     // Give dispatcher a unique name for debugging
712     snprintf(disp->name, DISP_NAME_LEN, "%s%d", disp_name(),
713              span_domain_state->core_id);
714
715 #ifdef __x86_64__
716     // XXX: share LDT state between all dispatchers
717     // this needs to happen before the remote core starts, otherwise the segment
718     // selectors in the new thread state are invalid
719     struct dispatcher_shared_x86_64 *disp_x64
720         = get_dispatcher_shared_x86_64(handle);
721     struct dispatcher_shared_x86_64 *mydisp_x64
722         = get_dispatcher_shared_x86_64(curdispatcher());
723
724     disp_x64->ldt_base = mydisp_x64->ldt_base;
725     disp_x64->ldt_npages = mydisp_x64->ldt_npages;
726 #endif
727
728     threads_prepare_to_span(handle);
729
730     // Setup new local thread for inter-dispatcher messages, if not already done
731     static struct thread *interdisp_thread = NULL;
732     if(interdisp_thread == NULL) {
733         interdisp_thread = thread_create(interdisp_msg_handler,
734                                          &domain_state->interdisp_ws);
735         err = thread_detach(interdisp_thread);
736         assert(err_is_ok(err));
737     }
738
739 #if 0
740     // XXX: Tell currently active interdisp-threads to handle default waitset
741     for(int i = 0; i < MAX_CPUS; i++) {
742         struct interdisp_binding *b = domain_state->b[i];
743
744         if(disp_get_core_id() != i && b != NULL) {
745             err = b->tx_vtbl.span_slave(b, NOP_CONT);
746             assert(err_is_ok(err));
747         }
748     }
749 #endif
750
751     #if 0
752     /* XXX: create a thread that will handle the default waitset */
753     if (domain_state->default_waitset_handler == NULL) {
754         domain_state->default_waitset_handler
755             = thread_create(span_slave_thread, NULL);
756         assert(domain_state->default_waitset_handler != NULL);
757     }
758 #endif
759
760     if (ret_span_state != NULL) {
761         *ret_span_state = span_domain_state;
762     }
763
764     return SYS_ERR_OK;
765 }
766
767 /**
768  * \brief Creates a dispatcher on a remote core
769  *
770  * \param core_id   Id of the core to create the dispatcher on
771  * \param callback  Callback to use when new dispatcher is created
772  *
773  * The new dispatcher is created with the same vroot, sharing the same vspace.
774  * The new dispatcher also has a urpc connection to the core that created it.
775  */
776 errval_t domain_new_dispatcher(coreid_t core_id,
777                                domain_spanned_callback_t callback,
778                                void *callback_arg)
779 {
780     struct span_domain_state *span_domain_state;
781     errval_t err = domain_new_dispatcher_varstack(core_id,
782                                                   callback, callback_arg,
783                                                   THREADS_DEFAULT_STACK_BYTES,
784                                                   &span_domain_state);
785     if (err_is_fail(err)) {
786         return err;
787     }
788
789     /* Wait to use the monitor binding */
790     struct monitor_binding *mcb = get_monitor_binding();
791     /* Set reply handler */
792     mcb->rx_vtbl.span_domain_reply = span_domain_reply;
793     event_mutex_enqueue_lock(&mcb->mutex, &span_domain_state->event_qnode,
794                           (struct event_closure) {
795                               .handler = span_domain_request_sender_wrapper,
796                                   .arg = span_domain_state });
797
798     while(!span_domain_state->initialized) {
799         event_dispatch(get_default_waitset());
800     }
801
802     free(span_domain_state);
803
804     return SYS_ERR_OK;
805 }
806
807 /**
808  * \brief Creates a dispatcher for a remote core, without running it.
809  *
810  * \param core_id   Id of the core to create the dispatcher on
811  * \param ret_state If non-null, will contain the spanned domain state, which
812  *                  can be used to retrieve the vroot and dispframe, as well as
813  *                  to check when the new dispatcher is up
814  *
815  * The new dispatcher is created with the same vroot, sharing the same vspace.
816  * The new dispatcher also has a urpc connection to the core that created it.
817  */
818 errval_t domain_new_dispatcher_setup_only(coreid_t core_id,
819                                           struct span_domain_state **ret_state)
820 {
821     assert(ret_state != NULL);
822     return domain_new_dispatcher_varstack(core_id, NULL, NULL,
823                                           THREADS_DEFAULT_STACK_BYTES,
824                                           ret_state);
825 }
826
827 errval_t domain_send_cap(coreid_t core_id, struct capref cap)
828 {
829     errval_t err;
830     struct domain_state *domain_state = get_domain_state();
831     if (!domain_state->binding[core_id]) {
832         return LIB_ERR_NO_SPANNED_DISP;
833     }
834
835     send_cap_err = SYS_ERR_OK;
836     cap_received = false;
837
838     struct interdisp_binding *b = domain_state->binding[core_id];
839     err = b->tx_vtbl.send_cap_request(b, NOP_CONT, cap, (uintptr_t)&cap);
840     if (err_is_fail(err)) {
841         return err_push(err, LIB_ERR_SEND_CAP_REQUEST);
842     }
843
844     assert(!"NYI");
845     // TODO: Handled on different thread
846     /* while(!cap_received) { */
847     /*     messages_wait_and_handle_next(); */
848     /* } */
849
850     return send_cap_err;
851 }
852
853 /**
854  * \brief Wakeup a thread on a foreign dispatcher while disabled.
855  *
856  * \param core_id       Core ID to wakeup on
857  * \param thread        Pointer to thread to wakeup
858  * \param mydisp        Dispatcher this function is running on
859  *
860  * \return SYS_ERR_OK on success.
861  */
862 static errval_t domain_wakeup_on_coreid_disabled(coreid_t core_id,
863                                                  struct thread *thread,
864                                                  dispatcher_handle_t mydisp)
865 {
866     struct domain_state *ds = get_domain_state();
867
868     // XXX: Ugly hack to allow waking up on a core id we don't have a
869     // dispatcher handler for
870     thread->coreid = core_id;
871
872     // Catch this early
873     assert_disabled(ds != NULL);
874     if (ds->binding[core_id] == NULL) {
875         return LIB_ERR_NO_SPANNED_DISP;
876     }
877
878     thread_enqueue(thread, &ds->remote_wakeup_queue);
879
880     // Signal the inter-disp waitset of this event
881     struct event_closure closure = {
882         .handler = handle_wakeup_on
883     };
884     errval_t err =
885         waitset_chan_trigger_closure_disabled(&ds->interdisp_ws,
886                                               &ds->remote_wakeup_event,
887                                               closure,
888                                               mydisp);
889     assert_disabled(err_is_ok(err) ||
890                     err_no(err) == LIB_ERR_CHAN_ALREADY_REGISTERED);
891
892     return SYS_ERR_OK;
893 }
894
895 errval_t domain_wakeup_on_disabled(dispatcher_handle_t disp,
896                                    struct thread *thread,
897                                    dispatcher_handle_t mydisp)
898 {
899     coreid_t core_id = disp_handle_get_core_id(disp);
900
901     // TODO: Can't wakeup on anyone else than the owning dispatcher yet
902     assert_disabled(disp == thread->disp);
903
904     return domain_wakeup_on_coreid_disabled(core_id, thread, mydisp);
905 }
906
907 errval_t domain_wakeup_on(dispatcher_handle_t disp,
908                           struct thread *thread)
909 {
910     dispatcher_handle_t mydisp = disp_disable();
911     errval_t err = domain_wakeup_on_disabled(disp, thread, mydisp);
912     disp_enable(mydisp);
913     return err;
914 }
915
916 errval_t domain_thread_move_to(struct thread *thread, coreid_t core_id)
917 {
918     assert(thread == thread_self());
919     dispatcher_handle_t mydisp = disp_disable();
920     struct dispatcher_generic *disp_gen = get_dispatcher_generic(mydisp);
921     struct dispatcher_shared_generic *disp =
922         get_dispatcher_shared_generic(mydisp);
923
924     struct thread *next = thread->next;
925     thread_remove_from_queue(&disp_gen->runq, thread);
926
927     errval_t err = domain_wakeup_on_coreid_disabled(core_id, thread, mydisp);
928     if(err_is_fail(err)) {
929         thread_enqueue(thread, &disp_gen->runq);
930         disp_enable(mydisp);
931         return err;
932     }
933
934     // run the next thread, if any
935     if (next != thread) {
936         disp_gen->current = next;
937         disp_resume(mydisp, &next->regs);
938     } else {
939         disp_gen->current = NULL;
940         disp->haswork = havework_disabled(mydisp);
941         disp_yield_disabled(mydisp);
942     }
943
944     USER_PANIC("should never be reached");
945 }
946
947 errval_t domain_thread_create_on_varstack(coreid_t core_id,
948                                           thread_func_t start_func,
949                                           void *arg, size_t stacksize,
950                                           struct thread **newthread)
951 {
952     if (disp_get_core_id() == core_id) {
953         struct thread *th = NULL;
954         if (stacksize == 0) {
955             th = thread_create(start_func, arg);
956         } else {
957             th = thread_create_varstack(start_func, arg, stacksize);
958         }
959         if (th != NULL) {
960             if (newthread) {
961                 *newthread = th;
962             }
963             return SYS_ERR_OK;
964         } else {
965             return LIB_ERR_THREAD_CREATE;
966         }
967     } else {
968         struct domain_state *domain_state = get_domain_state();
969         errval_t err;
970
971         if (domain_state->binding[core_id] == NULL) {
972             return LIB_ERR_NO_SPANNED_DISP;
973         }
974
975         struct interdisp_binding *b = domain_state->binding[core_id];
976         struct create_thread_req *req = malloc(sizeof(*req));
977         req->reply_received = false;
978         // use special waitset to make sure loop exits properly.
979         struct waitset ws, *old_ws = b->waitset;
980         waitset_init(&ws);
981         b->change_waitset(b, &ws);
982         err = b->tx_vtbl.create_thread_request(b, NOP_CONT,
983                                                (genvaddr_t)(uintptr_t)start_func,
984                                                (genvaddr_t)(uintptr_t)arg,
985                                                stacksize,
986                                                (genvaddr_t)(lvaddr_t)req);
987         if (err_is_fail(err)) {
988             return err;
989         }
990
991         while (!req->reply_received) {
992             event_dispatch(&ws);
993         }
994
995         if (newthread) {
996             *newthread = req->thread;
997         }
998         free(req);
999
1000         b->change_waitset(b, old_ws);
1001
1002         return SYS_ERR_OK;
1003     }
1004 }
1005
1006 errval_t domain_thread_create_on(coreid_t core_id, thread_func_t start_func,
1007                                  void *arg, struct thread **newthread)
1008 {
1009     return domain_thread_create_on_varstack(core_id, start_func, arg, 0, newthread);
1010 }
1011
1012 errval_t domain_thread_join(struct thread *thread, int *retval)
1013 {
1014     coreid_t core_id = thread->coreid;
1015     if (disp_get_core_id() == core_id) {
1016         return thread_join(thread, retval);
1017     } else {
1018         struct domain_state *domain_state = get_domain_state();
1019         errval_t err;
1020
1021         if (domain_state->binding[core_id] == NULL) {
1022             return LIB_ERR_NO_SPANNED_DISP;
1023         }
1024
1025         struct interdisp_binding *b = domain_state->binding[core_id];
1026         struct join_thread_req *req = malloc(sizeof(*req));
1027         req->reply_received = false;
1028         // use special waitset to make sure loop exits properly.
1029         struct waitset ws, *old_ws = b->waitset;
1030         waitset_init(&ws);
1031         b->change_waitset(b, &ws);
1032         err = b->tx_vtbl.join_thread_request(b, NOP_CONT,
1033                                              (genvaddr_t)(lvaddr_t)thread,
1034                                              (genvaddr_t)(lvaddr_t)req);
1035         if (err_is_fail(err)) {
1036             return err;
1037         }
1038
1039         while (!req->reply_received) {
1040             event_dispatch(&ws);
1041         }
1042         // change waitset back
1043         b->change_waitset(b, old_ws);
1044
1045         if (retval) {
1046             *retval = req->retval;
1047         }
1048         err = req->err;
1049         free(req);
1050
1051         return err;
1052     }
1053 }
1054
1055 /**
1056  * \brief set the core_id.
1057  *
1058  * Code using this should do a kernel_cap invocation to get the core_id first.
1059  */
1060 void disp_set_core_id(coreid_t core_id)
1061 {
1062     dispatcher_handle_t handle = curdispatcher();
1063     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1064     disp->core_id = core_id;
1065 }
1066
1067
1068 /**
1069  * \brief returns the address and the size of the EH frame
1070  *
1071  * \param eh_frame      returned virtual address of the EH frame
1072  * \param eh_frame_size returned size of the EH frame
1073  */
1074 void disp_get_eh_frame(lvaddr_t *eh_frame,
1075                        size_t *eh_frame_size)
1076 {
1077     dispatcher_handle_t handle = curdispatcher();
1078     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1079     if (eh_frame) {
1080         *eh_frame = disp->eh_frame;
1081     }
1082     if (eh_frame_size) {
1083         *eh_frame_size = disp->eh_frame_size;
1084     }
1085 }
1086
1087 /**
1088  * \brief returns the address and the size of the EH frame header
1089  *
1090  * \param eh_frame      returned virtual address of the EH frame
1091  * \param eh_frame_size returned size of the EH frame
1092  */
1093 void disp_get_eh_frame_hdr(lvaddr_t *eh_frame_hdr,
1094                        size_t *eh_frame_hdr_size)
1095 {
1096     dispatcher_handle_t handle = curdispatcher();
1097     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1098     if (eh_frame_hdr) {
1099         *eh_frame_hdr = disp->eh_frame_hdr;
1100     }
1101     if (eh_frame_hdr_size) {
1102         *eh_frame_hdr_size = disp->eh_frame_hdr_size;
1103     }
1104 }
1105
1106 /**
1107  * \brief returns the core_id stored in disp_priv struct
1108  */
1109 coreid_t disp_get_core_id(void)
1110 {
1111     dispatcher_handle_t handle = curdispatcher();
1112     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1113     return disp->core_id;
1114 }
1115
1116 /**
1117  * \brief returns the current core_id stored in disp_shared struct
1118  */
1119 coreid_t disp_get_current_core_id(void)
1120 {
1121     dispatcher_handle_t handle = curdispatcher();
1122     struct dispatcher_shared_generic* disp = get_dispatcher_shared_generic(handle);
1123     return disp->curr_core_id;
1124 }
1125
1126 /**
1127  * \brief returns the domain_id stored in disp_priv struct
1128  */
1129 domainid_t disp_get_domain_id(void)
1130 {
1131     dispatcher_handle_t handle = curdispatcher();
1132     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1133     return disp->domain_id;
1134 }
1135
1136 /**
1137  * \brief returns the core_id stored in disp_priv struct
1138  */
1139 coreid_t disp_handle_get_core_id(dispatcher_handle_t handle)
1140 {
1141     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1142     return disp->core_id;
1143 }
1144
1145 struct waitset *get_default_waitset(void)
1146 {
1147     dispatcher_handle_t handle = curdispatcher();
1148     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1149     return &disp->core_state.c.default_waitset;
1150 }
1151
1152 /**
1153  * \brief set the monitor client binding on the dispatcher priv
1154  */
1155 void set_monitor_binding(struct monitor_binding *b)
1156 {
1157     dispatcher_handle_t handle = curdispatcher();
1158     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1159     disp->core_state.c.monitor_binding = b;
1160 }
1161
1162 /**
1163  * \brief Returns the monitor client binding on the dispatcher priv
1164  */
1165 struct monitor_binding *get_monitor_binding(void)
1166 {
1167     dispatcher_handle_t handle = curdispatcher();
1168     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1169     return disp->core_state.c.monitor_binding;
1170 }
1171
1172 struct waitset_chanstate *get_monitor_binding_chanstate(void)
1173 {
1174     struct monitor_binding *mb = get_monitor_binding();
1175     return mb->get_receiving_chanstate(mb);
1176 }
1177
1178 /**
1179  * \brief set the  blocking rpc monitor client binding on the dispatcher priv
1180  */
1181 void set_monitor_blocking_binding(struct monitor_blocking_binding *st)
1182 {
1183     dispatcher_handle_t handle = curdispatcher();
1184     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1185     disp->core_state.c.monitor_blocking_binding = st;
1186 }
1187
1188 /**
1189  * \brief Returns the blocking rpc monitor client binding on the
1190  * dispatcher priv
1191  */
1192 struct monitor_blocking_binding *get_monitor_blocking_binding(void)
1193 {
1194     dispatcher_handle_t handle = curdispatcher();
1195     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1196     return disp->core_state.c.monitor_blocking_binding;
1197 }
1198
1199 /**
1200  * \brief set the mem client on the dispatcher priv
1201  */
1202 void set_mem_client(struct mem_binding *st)
1203 {
1204     dispatcher_handle_t handle = curdispatcher();
1205     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1206     disp->core_state.c.mem_st = st;
1207 }
1208
1209 /**
1210  * \brief Returns the mem client on the dispatcher priv
1211  */
1212 struct mem_binding *get_mem_client(void)
1213 {
1214     dispatcher_handle_t handle = curdispatcher();
1215     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1216     return disp->core_state.c.mem_st;
1217 }
1218
1219 /**
1220  * \brief Returns a pointer to the current vspace on the dispatcher priv
1221  */
1222 struct vspace *get_current_vspace(void)
1223 {
1224     dispatcher_handle_t handle = curdispatcher();
1225     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1226     return &disp->core_state.vspace_state.vspace;
1227 }
1228
1229 /**
1230  * \brief Returns a pointer to the current pinned state on the dispatcher priv
1231  */
1232 struct pinned_state *get_current_pinned_state(void)
1233 {
1234     dispatcher_handle_t handle = curdispatcher();
1235     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1236     return &disp->core_state.pinned_state;
1237 }
1238
1239 /**
1240  * \brief Returns a pointer to the current pmap on the dispatcher priv
1241  */
1242 struct pmap *get_current_pmap(void)
1243 {
1244     dispatcher_handle_t handle = curdispatcher();
1245     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1246     return (struct pmap*)&disp->core_state.vspace_state.pmap;
1247 }
1248
1249 /**
1250  * \brief Returns a pointer to the morecore state on the dispatcher priv
1251  */
1252 struct morecore_state *get_morecore_state(void)
1253 {
1254     dispatcher_handle_t handle = curdispatcher();
1255     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1256     return &disp->core_state.c.morecore_state;
1257 }
1258
1259 /**
1260  * \brief Returns a pointer to the ram_alloc state on the dispatcher priv
1261  */
1262 struct ram_alloc_state *get_ram_alloc_state(void)
1263 {
1264     dispatcher_handle_t handle = curdispatcher();
1265     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1266     return &disp->core_state.c.ram_alloc_state;
1267 }
1268
1269 /**
1270  * \brief Returns a pointer to the ram_alloc state on the dispatcher priv
1271  */
1272 struct skb_state *get_skb_state(void)
1273 {
1274     dispatcher_handle_t handle = curdispatcher();
1275     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1276     return &disp->core_state.c.skb_state;
1277 }
1278
1279 /**
1280  * \brief Returns a pointer to the octopus rpc client on the dispatcher priv
1281  */
1282 struct octopus_binding *get_octopus_binding(void)
1283 {
1284     dispatcher_handle_t handle = curdispatcher();
1285     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1286     return disp->core_state.c.octopus_binding;
1287 }
1288
1289 /**
1290  * \brief Sets the octopus rpc client on the dispatcher priv
1291  */
1292 void set_octopus_binding(struct octopus_binding *c)
1293 {
1294     dispatcher_handle_t handle = curdispatcher();
1295     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1296     disp->core_state.c.octopus_binding = c;
1297 }
1298
1299 /**
1300  * \brief Returns a pointer to the chips_context state on the dispatcher priv
1301  */
1302 struct spawn_binding *get_spawn_binding(coreid_t core)
1303 {
1304     dispatcher_handle_t handle = curdispatcher();
1305     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1306     assert(core < MAX_CPUS);
1307     return disp->core_state.c.spawn_bindings[core];
1308 }
1309
1310 /**
1311  * \brief set the chips_context state on the dispatcher priv
1312  */
1313 void set_spawn_binding(coreid_t core, struct spawn_binding *c)
1314 {
1315     dispatcher_handle_t handle = curdispatcher();
1316     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1317     assert(core < MAX_CPUS);
1318     disp->core_state.c.spawn_bindings[core] = c;
1319 }
1320 /**
1321  * \brief Returns a pointer to the proc_mgmt rpc client on the dispatcher priv
1322  */
1323 struct proc_mgmt_binding *get_proc_mgmt_binding(void)
1324 {
1325     dispatcher_handle_t handle = curdispatcher();
1326     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1327     return disp->core_state.c.proc_mgmt_binding;
1328 }
1329
1330 /**
1331  * \brief Sets the prog_mgmt rpc client on the dispatcher priv
1332  */
1333 void set_proc_mgmt_binding(struct proc_mgmt_binding *c)
1334 {
1335     dispatcher_handle_t handle = curdispatcher();
1336     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1337     disp->core_state.c.proc_mgmt_binding = c;
1338 }
1339
1340 struct arrakis_binding *get_arrakis_binding(coreid_t core)
1341 {
1342     dispatcher_handle_t handle = curdispatcher();
1343     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1344     assert(core < MAX_CPUS);
1345     return disp->core_state.c.arrakis_bindings[core];
1346 }
1347
1348 /**
1349  * \brief set the chips_context state on the dispatcher priv
1350  */
1351 void set_arrakis_binding(coreid_t core, struct arrakis_binding *c)
1352 {
1353     dispatcher_handle_t handle = curdispatcher();
1354     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1355     assert(core < MAX_CPUS);
1356     disp->core_state.c.arrakis_bindings[core] = c;
1357 }
1358
1359 /**
1360  * \brief Returns a pointer to the terminal state on the dispatcher priv
1361  */
1362 struct terminal_state *get_terminal_state(void)
1363 {
1364     dispatcher_handle_t handle = curdispatcher();
1365     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1366     return disp->core_state.c.terminal_state;
1367 }
1368
1369 /**
1370  * \brief set the terminal state on the dispatcher priv
1371  */
1372 void set_terminal_state(struct terminal_state *st)
1373 {
1374     dispatcher_handle_t handle = curdispatcher();
1375     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1376     disp->core_state.c.terminal_state = st;
1377 }
1378
1379 /**
1380  * \brief Returns a pointer to the domain state on the dispatcher priv
1381  */
1382 struct domain_state *get_domain_state(void)
1383 {
1384     dispatcher_handle_t handle = curdispatcher();
1385     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1386     return disp->core_state.c.domain_state;
1387 }
1388
1389 /**
1390  * \brief set the domain state on the dispatcher priv
1391  */
1392 void set_domain_state(struct domain_state *st)
1393 {
1394     dispatcher_handle_t handle = curdispatcher();
1395     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1396     disp->core_state.c.domain_state = st;
1397 }
1398
1399 /**
1400  * \brief Returns a pointer to the spawn state on the dispatcher priv
1401  */
1402 struct spawn_state *get_spawn_state(void)
1403 {
1404     dispatcher_handle_t handle = curdispatcher();
1405     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1406     return disp->core_state.c.spawn_state;
1407 }
1408
1409 /**
1410  * \brief set the spawn state on the dispatcher priv
1411  */
1412 void set_spawn_state(struct spawn_state *st)
1413 {
1414     dispatcher_handle_t handle = curdispatcher();
1415     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1416     disp->core_state.c.spawn_state = st;
1417 }
1418
1419 /**
1420  * \brief Returns a pointer to the spawn state on the dispatcher priv
1421  */
1422 struct slot_alloc_state *get_slot_alloc_state(void)
1423 {
1424     dispatcher_handle_t handle = curdispatcher();
1425     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1426     return &disp->core_state.c.slot_alloc_state;
1427 }
1428
1429 /**
1430  * \brief Returns a 64-bit hash code for a given domain cap.
1431  */
1432 errval_t domain_cap_hash(struct capref domain_cap, uint64_t *ret_hash)
1433 {
1434     assert(ret_hash != NULL);
1435
1436     struct capability ret_cap;
1437     errval_t err = monitor_cap_identify_remote(domain_cap, &ret_cap);
1438     if (err_is_fail(err)) {
1439         return err_push(err, PROC_MGMT_ERR_DOMAIN_CAP_HASH);
1440     }
1441     if (ret_cap.type != ObjType_Domain) {
1442         return PROC_MGMT_ERR_DOMAIN_CAP_HASH;
1443     }
1444
1445     static uint64_t base = 1 + (uint64_t) MAX_DOMAINID;
1446     *ret_hash = base * ret_cap.u.domain.core_local_id + ret_cap.u.domain.coreid;
1447
1448     return SYS_ERR_OK;
1449 }