Handing over alignment paramenter of morecore when spanning
[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 *b[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->b[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->b[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->b[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->b[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->b[core_id] != NULL);
428
429         struct interdisp_binding *b = domain_state->b[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->b[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 #if 1
784     while(!span_domain_state->initialized) {
785         event_dispatch(get_default_waitset());
786     }
787
788     /* Free state */
789     free(span_domain_state);
790 #endif
791
792     return SYS_ERR_OK;
793 }
794
795 /**
796  * \brief Creates a dispatcher on a remote core
797  *
798  * \param core_id   Id of the core to create the dispatcher on
799  * \param callback  Callback to use when new dispatcher is created
800  *
801  * The new dispatcher is created with the same vroot, sharing the same vspace.
802  * The new dispatcher also has a urpc connection to the core that created it.
803  */
804 errval_t domain_new_dispatcher(coreid_t core_id,
805                                domain_spanned_callback_t callback,
806                                void *callback_arg)
807 {
808     return domain_new_dispatcher_varstack(core_id, callback, callback_arg,
809                                           THREADS_DEFAULT_STACK_BYTES);
810 }
811
812 errval_t domain_send_cap(coreid_t core_id, struct capref cap)
813 {
814     errval_t err;
815     struct domain_state *domain_state = get_domain_state();
816     if (!domain_state->b[core_id]) {
817         return LIB_ERR_NO_SPANNED_DISP;
818     }
819
820     send_cap_err = SYS_ERR_OK;
821     cap_received = false;
822
823     struct interdisp_binding *b = domain_state->b[core_id];
824     err = b->tx_vtbl.send_cap_request(b, NOP_CONT, cap, (uintptr_t)&cap);
825     if (err_is_fail(err)) {
826         return err_push(err, LIB_ERR_SEND_CAP_REQUEST);
827     }
828
829     assert(!"NYI");
830     // TODO: Handled on different thread
831     /* while(!cap_received) { */
832     /*     messages_wait_and_handle_next(); */
833     /* } */
834
835     return send_cap_err;
836 }
837
838 /**
839  * \brief Wakeup a thread on a foreign dispatcher while disabled.
840  *
841  * \param core_id       Core ID to wakeup on
842  * \param thread        Pointer to thread to wakeup
843  * \param mydisp        Dispatcher this function is running on
844  *
845  * \return SYS_ERR_OK on success.
846  */
847 static errval_t domain_wakeup_on_coreid_disabled(coreid_t core_id,
848                                                  struct thread *thread,
849                                                  dispatcher_handle_t mydisp)
850 {
851     struct domain_state *ds = get_domain_state();
852
853     // XXX: Ugly hack to allow waking up on a core id we don't have a
854     // dispatcher handler for
855     thread->coreid = core_id;
856
857     // Catch this early
858     assert_disabled(ds != NULL);
859     if (ds->b[core_id] == NULL) {
860         return LIB_ERR_NO_SPANNED_DISP;
861     }
862
863     thread_enqueue(thread, &ds->remote_wakeup_queue);
864
865     // Signal the inter-disp waitset of this event
866     struct event_closure closure = {
867         .handler = handle_wakeup_on
868     };
869     errval_t err =
870         waitset_chan_trigger_closure_disabled(&ds->interdisp_ws,
871                                               &ds->remote_wakeup_event,
872                                               closure,
873                                               mydisp);
874     assert_disabled(err_is_ok(err) ||
875                     err_no(err) == LIB_ERR_CHAN_ALREADY_REGISTERED);
876
877     return SYS_ERR_OK;
878 }
879
880 errval_t domain_wakeup_on_disabled(dispatcher_handle_t disp,
881                                    struct thread *thread,
882                                    dispatcher_handle_t mydisp)
883 {
884     coreid_t core_id = disp_handle_get_core_id(disp);
885
886     // TODO: Can't wakeup on anyone else than the owning dispatcher yet
887     assert_disabled(disp == thread->disp);
888
889     return domain_wakeup_on_coreid_disabled(core_id, thread, mydisp);
890 }
891
892 errval_t domain_wakeup_on(dispatcher_handle_t disp,
893                           struct thread *thread)
894 {
895     dispatcher_handle_t mydisp = disp_disable();
896     errval_t err = domain_wakeup_on_disabled(disp, thread, mydisp);
897     disp_enable(mydisp);
898     return err;
899 }
900
901 errval_t domain_thread_move_to(struct thread *thread, coreid_t core_id)
902 {
903     assert(thread == thread_self());
904     dispatcher_handle_t mydisp = disp_disable();
905     struct dispatcher_generic *disp_gen = get_dispatcher_generic(mydisp);
906     struct dispatcher_shared_generic *disp =
907         get_dispatcher_shared_generic(mydisp);
908
909     struct thread *next = thread->next;
910     thread_remove_from_queue(&disp_gen->runq, thread);
911
912     errval_t err = domain_wakeup_on_coreid_disabled(core_id, thread, mydisp);
913     if(err_is_fail(err)) {
914         thread_enqueue(thread, &disp_gen->runq);
915         disp_enable(mydisp);
916         return err;
917     }
918
919     // run the next thread, if any
920     if (next != thread) {
921         disp_gen->current = next;
922         disp_resume(mydisp, &next->regs);
923     } else {
924         disp_gen->current = NULL;
925         disp->haswork = havework_disabled(mydisp);
926         disp_yield_disabled(mydisp);
927     }
928
929     USER_PANIC("should never be reached");
930 }
931
932 errval_t domain_thread_create_on_varstack(coreid_t core_id,
933                                           thread_func_t start_func,
934                                           void *arg, size_t stacksize,
935                                           struct thread **newthread)
936 {
937     if (disp_get_core_id() == core_id) {
938         struct thread *th = NULL;
939         if (stacksize == 0) {
940             th = thread_create(start_func, arg);
941         } else {
942             th = thread_create_varstack(start_func, arg, stacksize);
943         }
944         if (th != NULL) {
945             if (newthread) {
946                 *newthread = th;
947             }
948             return SYS_ERR_OK;
949         } else {
950             return LIB_ERR_THREAD_CREATE;
951         }
952     } else {
953         struct domain_state *domain_state = get_domain_state();
954         errval_t err;
955
956         if (domain_state->b[core_id] == NULL) {
957             return LIB_ERR_NO_SPANNED_DISP;
958         }
959
960         struct interdisp_binding *b = domain_state->b[core_id];
961         struct create_thread_req *req = malloc(sizeof(*req));
962         req->reply_received = false;
963         // use special waitset to make sure loop exits properly.
964         struct waitset ws, *old_ws = b->waitset;
965         waitset_init(&ws);
966         b->change_waitset(b, &ws);
967         err = b->tx_vtbl.create_thread_request(b, NOP_CONT,
968                                                (genvaddr_t)(uintptr_t)start_func,
969                                                (genvaddr_t)(uintptr_t)arg,
970                                                stacksize,
971                                                (genvaddr_t)(lvaddr_t)req);
972         if (err_is_fail(err)) {
973             return err;
974         }
975
976         while (!req->reply_received) {
977             event_dispatch(&ws);
978         }
979
980         if (newthread) {
981             *newthread = req->thread;
982         }
983         free(req);
984
985         b->change_waitset(b, old_ws);
986
987         return SYS_ERR_OK;
988     }
989 }
990
991 errval_t domain_thread_create_on(coreid_t core_id, thread_func_t start_func,
992                                  void *arg, struct thread **newthread)
993 {
994     return domain_thread_create_on_varstack(core_id, start_func, arg, 0, newthread);
995 }
996
997 errval_t domain_thread_join(struct thread *thread, int *retval)
998 {
999     coreid_t core_id = thread->coreid;
1000     debug_printf("%s: joining %p, coreid %d\n", __FUNCTION__, thread, core_id);
1001     if (disp_get_core_id() == core_id) {
1002         return thread_join(thread, retval);
1003     } else {
1004         struct domain_state *domain_state = get_domain_state();
1005         errval_t err;
1006
1007         if (domain_state->b[core_id] == NULL) {
1008             return LIB_ERR_NO_SPANNED_DISP;
1009         }
1010
1011         struct interdisp_binding *b = domain_state->b[core_id];
1012         struct join_thread_req *req = malloc(sizeof(*req));
1013         req->reply_received = false;
1014         // use special waitset to make sure loop exits properly.
1015         struct waitset ws, *old_ws = b->waitset;
1016         waitset_init(&ws);
1017         b->change_waitset(b, &ws);
1018         err = b->tx_vtbl.join_thread_request(b, NOP_CONT,
1019                                              (genvaddr_t)(lvaddr_t)thread,
1020                                              (genvaddr_t)(lvaddr_t)req);
1021         if (err_is_fail(err)) {
1022             return err;
1023         }
1024
1025         while (!req->reply_received) {
1026             event_dispatch(&ws);
1027         }
1028         // change waitset back
1029         b->change_waitset(b, old_ws);
1030
1031         if (retval) {
1032             *retval = req->retval;
1033         }
1034         err = req->err;
1035         free(req);
1036
1037         return err;
1038     }
1039 }
1040
1041 /**
1042  * \brief set the core_id.
1043  *
1044  * Code using this should do a kernel_cap invocation to get the core_id first.
1045  */
1046 void disp_set_core_id(coreid_t core_id)
1047 {
1048     dispatcher_handle_t handle = curdispatcher();
1049     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1050     disp->core_id = core_id;
1051 }
1052
1053 /**
1054  * \brief returns the address and the size of the EH frame
1055  *
1056  * \param eh_frame      returned virtual address of the EH frame
1057  * \param eh_frame_size returned size of the EH frame
1058  */
1059 void disp_get_eh_frame(lvaddr_t *eh_frame,
1060                        size_t *eh_frame_size)
1061 {
1062     dispatcher_handle_t handle = curdispatcher();
1063     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1064     if (eh_frame) {
1065         *eh_frame = disp->eh_frame;
1066     }
1067     if (eh_frame_size) {
1068         *eh_frame_size = disp->eh_frame_size;
1069     }
1070 }
1071
1072 /**
1073  * \brief returns the address and the size of the EH frame header
1074  *
1075  * \param eh_frame      returned virtual address of the EH frame
1076  * \param eh_frame_size returned size of the EH frame
1077  */
1078 void disp_get_eh_frame_hdr(lvaddr_t *eh_frame_hdr,
1079                        size_t *eh_frame_hdr_size)
1080 {
1081     dispatcher_handle_t handle = curdispatcher();
1082     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1083     if (eh_frame_hdr) {
1084         *eh_frame_hdr = disp->eh_frame_hdr;
1085     }
1086     if (eh_frame_hdr_size) {
1087         *eh_frame_hdr_size = disp->eh_frame_hdr_size;
1088     }
1089 }
1090
1091 /**
1092  * \brief returns the core_id stored in disp_priv struct
1093  */
1094 coreid_t disp_get_core_id(void)
1095 {
1096     dispatcher_handle_t handle = curdispatcher();
1097     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1098     return disp->core_id;
1099 }
1100
1101 /**
1102  * \brief returns the current core_id stored in disp_shared struct
1103  */
1104 coreid_t disp_get_current_core_id(void)
1105 {
1106     dispatcher_handle_t handle = curdispatcher();
1107     struct dispatcher_shared_generic* disp = get_dispatcher_shared_generic(handle);
1108     return disp->curr_core_id;
1109 }
1110
1111 /**
1112  * \brief returns the domain_id stored in disp_priv struct
1113  */
1114 domainid_t disp_get_domain_id(void)
1115 {
1116     dispatcher_handle_t handle = curdispatcher();
1117     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1118     return disp->domain_id;
1119 }
1120
1121 /**
1122  * \brief returns the core_id stored in disp_priv struct
1123  */
1124 coreid_t disp_handle_get_core_id(dispatcher_handle_t handle)
1125 {
1126     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1127     return disp->core_id;
1128 }
1129
1130 struct waitset *get_default_waitset(void)
1131 {
1132     dispatcher_handle_t handle = curdispatcher();
1133     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1134     return &disp->core_state.c.default_waitset;
1135 }
1136
1137 /**
1138  * \brief set the monitor client binding on the dispatcher priv
1139  */
1140 void set_monitor_binding(struct monitor_binding *b)
1141 {
1142     dispatcher_handle_t handle = curdispatcher();
1143     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1144     disp->core_state.c.monitor_binding = b;
1145 }
1146
1147 /**
1148  * \brief Returns the monitor client binding on the dispatcher priv
1149  */
1150 struct monitor_binding *get_monitor_binding(void)
1151 {
1152     dispatcher_handle_t handle = curdispatcher();
1153     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1154     return disp->core_state.c.monitor_binding;
1155 }
1156
1157
1158 /**
1159  * \brief set the  blocking rpc monitor client binding on the dispatcher priv
1160  */
1161 void set_monitor_blocking_rpc_client(struct monitor_blocking_rpc_client *st)
1162 {
1163     dispatcher_handle_t handle = curdispatcher();
1164     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1165     disp->core_state.c.monitor_blocking_rpc_client = st;
1166 }
1167
1168 /**
1169  * \brief Returns the blocking rpc monitor client binding on the
1170  * dispatcher priv
1171  */
1172 struct monitor_blocking_rpc_client *get_monitor_blocking_rpc_client(void)
1173 {
1174     dispatcher_handle_t handle = curdispatcher();
1175     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1176     return disp->core_state.c.monitor_blocking_rpc_client;
1177 }
1178
1179 /**
1180  * \brief set the mem client on the dispatcher priv
1181  */
1182 void set_mem_client(struct mem_rpc_client *st)
1183 {
1184     dispatcher_handle_t handle = curdispatcher();
1185     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1186     disp->core_state.c.mem_st = st;
1187 }
1188
1189 /**
1190  * \brief Returns the mem client on the dispatcher priv
1191  */
1192 struct mem_rpc_client *get_mem_client(void)
1193 {
1194     dispatcher_handle_t handle = curdispatcher();
1195     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1196     return disp->core_state.c.mem_st;
1197 }
1198
1199 /**
1200  * \brief Returns a pointer to the current vspace on the dispatcher priv
1201  */
1202 struct vspace *get_current_vspace(void)
1203 {
1204     dispatcher_handle_t handle = curdispatcher();
1205     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1206     return &disp->core_state.vspace_state.vspace;
1207 }
1208
1209 /**
1210  * \brief Returns a pointer to the current pinned state on the dispatcher priv
1211  */
1212 struct pinned_state *get_current_pinned_state(void)
1213 {
1214     dispatcher_handle_t handle = curdispatcher();
1215     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1216     return &disp->core_state.pinned_state;
1217 }
1218
1219 /**
1220  * \brief Returns a pointer to the current pmap on the dispatcher priv
1221  */
1222 struct pmap *get_current_pmap(void)
1223 {
1224     dispatcher_handle_t handle = curdispatcher();
1225     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1226     return (struct pmap*)&disp->core_state.vspace_state.pmap;
1227 }
1228
1229 /**
1230  * \brief Returns a pointer to the morecore state on the dispatcher priv
1231  */
1232 struct morecore_state *get_morecore_state(void)
1233 {
1234     dispatcher_handle_t handle = curdispatcher();
1235     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1236     return &disp->core_state.c.morecore_state;
1237 }
1238
1239 /**
1240  * \brief Returns a pointer to the ram_alloc state on the dispatcher priv
1241  */
1242 struct ram_alloc_state *get_ram_alloc_state(void)
1243 {
1244     dispatcher_handle_t handle = curdispatcher();
1245     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1246     return &disp->core_state.c.ram_alloc_state;
1247 }
1248
1249 /**
1250  * \brief Returns a pointer to the ram_alloc state on the dispatcher priv
1251  */
1252 struct skb_state *get_skb_state(void)
1253 {
1254     dispatcher_handle_t handle = curdispatcher();
1255     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1256     return &disp->core_state.c.skb_state;
1257 }
1258
1259 /**
1260  * \brief Returns a pointer to the octopus rpc client on the dispatcher priv
1261  */
1262 struct octopus_rpc_client *get_octopus_rpc_client(void)
1263 {
1264     dispatcher_handle_t handle = curdispatcher();
1265     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1266     return disp->core_state.c.octopus_rpc_client;
1267 }
1268
1269 /**
1270  * \brief Sets the octopus rpc client on the dispatcher priv
1271  */
1272 void set_octopus_rpc_client(struct octopus_rpc_client *c)
1273 {
1274     dispatcher_handle_t handle = curdispatcher();
1275     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1276     disp->core_state.c.octopus_rpc_client = c;
1277 }
1278
1279 /**
1280  * \brief Returns a pointer to the chips_context state on the dispatcher priv
1281  */
1282 struct spawn_rpc_client *get_spawn_rpc_client(coreid_t core)
1283 {
1284     dispatcher_handle_t handle = curdispatcher();
1285     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1286     assert(core < MAX_CPUS);
1287     return disp->core_state.c.spawn_rpc_clients[core];
1288 }
1289
1290 /**
1291  * \brief set the chips_context state on the dispatcher priv
1292  */
1293 void set_spawn_rpc_client(coreid_t core, struct spawn_rpc_client *c)
1294 {
1295     dispatcher_handle_t handle = curdispatcher();
1296     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1297     assert(core < MAX_CPUS);
1298     disp->core_state.c.spawn_rpc_clients[core] = c;
1299 }
1300
1301 struct arrakis_rpc_client *get_arrakis_rpc_client(coreid_t core)
1302 {
1303     dispatcher_handle_t handle = curdispatcher();
1304     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1305     assert(core < MAX_CPUS);
1306     return disp->core_state.c.arrakis_rpc_clients[core];
1307 }
1308
1309 /**
1310  * \brief set the chips_context state on the dispatcher priv
1311  */
1312 void set_arrakis_rpc_client(coreid_t core, struct arrakis_rpc_client *c)
1313 {
1314     dispatcher_handle_t handle = curdispatcher();
1315     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1316     assert(core < MAX_CPUS);
1317     disp->core_state.c.arrakis_rpc_clients[core] = c;
1318 }
1319
1320 /**
1321  * \brief Returns a pointer to the terminal state on the dispatcher priv
1322  */
1323 struct terminal_state *get_terminal_state(void)
1324 {
1325     dispatcher_handle_t handle = curdispatcher();
1326     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1327     return disp->core_state.c.terminal_state;
1328 }
1329
1330 /**
1331  * \brief set the terminal state on the dispatcher priv
1332  */
1333 void set_terminal_state(struct terminal_state *st)
1334 {
1335     dispatcher_handle_t handle = curdispatcher();
1336     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1337     disp->core_state.c.terminal_state = st;
1338 }
1339
1340 /**
1341  * \brief Returns a pointer to the domain state on the dispatcher priv
1342  */
1343 struct domain_state *get_domain_state(void)
1344 {
1345     dispatcher_handle_t handle = curdispatcher();
1346     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1347     return disp->core_state.c.domain_state;
1348 }
1349
1350 /**
1351  * \brief set the domain state on the dispatcher priv
1352  */
1353 void set_domain_state(struct domain_state *st)
1354 {
1355     dispatcher_handle_t handle = curdispatcher();
1356     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1357     disp->core_state.c.domain_state = st;
1358 }
1359
1360 /**
1361  * \brief Returns a pointer to the spawn state on the dispatcher priv
1362  */
1363 struct spawn_state *get_spawn_state(void)
1364 {
1365     dispatcher_handle_t handle = curdispatcher();
1366     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1367     return disp->core_state.c.spawn_state;
1368 }
1369
1370 /**
1371  * \brief set the spawn state on the dispatcher priv
1372  */
1373 void set_spawn_state(struct spawn_state *st)
1374 {
1375     dispatcher_handle_t handle = curdispatcher();
1376     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1377     disp->core_state.c.spawn_state = st;
1378 }
1379
1380 /**
1381  * \brief Returns a pointer to the spawn state on the dispatcher priv
1382  */
1383 struct slot_alloc_state *get_slot_alloc_state(void)
1384 {
1385     dispatcher_handle_t handle = curdispatcher();
1386     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
1387     return &disp->core_state.c.slot_alloc_state;
1388 }