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