3 * \brief Process management service.
7 * Copyright (c) 2017, ETH Zurich.
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
15 #include <barrelfish/barrelfish.h>
16 #include <barrelfish/nameservice_client.h>
17 #include <barrelfish/proc_mgmt_client.h>
18 #include <barrelfish/spawn_client.h>
19 #include <if/monitor_defs.h>
20 #include <if/proc_mgmt_defs.h>
21 #include <if/spawn_defs.h>
25 #include "pending_clients.h"
26 #include "spawnd_state.h"
28 static void add_spawnd_handler(struct proc_mgmt_binding *b, coreid_t core_id,
31 if (spawnd_state_exists(core_id)) {
32 DEBUG_ERR(PROC_MGMT_ERR_SPAWND_EXISTS, "spawnd_state_exists");
36 // Bind with the spawnd.
37 struct spawn_binding *spawnb;
38 errval_t err = spawn_bind_iref(iref, &spawnb);
39 if (err_is_fail(err)) {
40 DEBUG_ERR(err, "spawn_bind_iref");
44 err = spawnd_state_alloc(core_id, spawnb);
45 if (err_is_fail(err)) {
46 DEBUG_ERR(err, "spawnd_state_alloc");
49 debug_printf("Process manager bound with spawnd.%u on iref %u\n", core_id,
53 static void add_spawnd_handler_non_monitor(struct proc_mgmt_binding *b,
54 coreid_t core_id, iref_t iref)
56 // debug_printf("Ignoring add_spawnd call: %s\n",
57 // err_getstring(PROC_MGMT_ERR_NOT_MONITOR));
60 static bool cleanup_request_sender(struct msg_queue_elem *m);
63 #define PROC_MGMT_BENCH 1
64 #define PROC_MGMT_BENCH_MIN_RUNS 150
66 #ifdef PROC_MGMT_BENCH
67 #include <bench/bench.h>
69 static inline cycles_t calculate_time(cycles_t tsc_start, cycles_t tsc_end)
72 if (tsc_end < tsc_start) {
73 result = (LONG_MAX - tsc_start) + tsc_end - bench_tscoverhead();
75 result = (tsc_end - tsc_start - bench_tscoverhead());
80 static bench_ctl_t *req_ctl_1;
81 static bench_ctl_t *req_ctl_2;
82 static bench_ctl_t *req_ctl_3;
83 static bench_ctl_t *req_ctl_4;
84 static bench_ctl_t *req_ctl_5;
85 static bench_ctl_t *resp_ctl;
86 static uint64_t tscperus;
89 static void spawn_reply_handler(struct spawn_binding *b, errval_t spawn_err)
91 #ifdef PROC_MGMT_BENCH
92 cycles_t tsc_start, tsc_end;
95 tsc_start = bench_tsc();
98 struct pending_client *cl =
99 (struct pending_client*) spawnd_state_dequeue_recv(b->st);
101 struct pending_spawn *spawn = NULL;
102 struct pending_span *span = NULL;
103 struct pending_kill_cleanup *kc = NULL;
105 struct domain_entry *entry;
107 errval_t err, resp_err;
110 case ClientType_Spawn:
111 case ClientType_SpawnWithCaps:
112 spawn = (struct pending_spawn*) cl->st;
114 if (err_is_ok(spawn_err)) {
115 err = domain_spawn(spawn->cap_node, spawn->core_id);
116 if (cl->type == ClientType_Spawn) {
117 resp_err = cl->b->tx_vtbl.spawn_response(cl->b, NOP_CONT,
119 spawn->cap_node->domain_cap);
121 resp_err = cl->b->tx_vtbl.spawn_with_caps_response(cl->b,
124 spawn->cap_node->domain_cap);
130 #ifdef PROC_MGMT_BENCH
131 tsc_end = bench_tsc();
132 result = calculate_time(tsc_start, tsc_end);
134 if (resp_ctl != NULL && bench_ctl_add_run(resp_ctl, &result)) {
135 bench_ctl_dump_analysis(resp_ctl, 0, "proc_mgmt_resp",
137 bench_ctl_destroy(resp_ctl);
143 case ClientType_Span:
144 span = (struct pending_span*) cl->st;
146 if (entry->status == DOMAIN_STATUS_RUNNING) {
147 resp_err = cl->b->tx_vtbl.span_response(cl->b, NOP_CONT,
154 case ClientType_Cleanup:
155 kc = (struct pending_kill_cleanup*) cl->st;
158 assert(entry->num_spawnds_resources > 0);
159 assert(entry->status != DOMAIN_STATUS_CLEANED);
161 --entry->num_spawnds_resources;
162 if (entry->num_spawnds_resources == 0) {
163 entry->status = DOMAIN_STATUS_CLEANED;
165 // At this point, the domain exists in state CLEANED for history
166 // reasons. For instance, if some other domain issues a wait
167 // call for this one, the process manager can return the exit
168 // status directly. At some point, however, we might want to
169 // just clean up the domain entry and recycle the domain cap.
175 case ClientType_Kill:
176 case ClientType_Exit:
177 kc = (struct pending_kill_cleanup*) cl->st;
180 assert(entry->num_spawnds_running > 0);
181 assert(entry->status != DOMAIN_STATUS_STOPPED);
183 --entry->num_spawnds_running;
185 if (entry->num_spawnds_running == 0) {
186 entry->status = DOMAIN_STATUS_STOPPED;
188 if (cl->type == ClientType_Kill) {
189 entry->exit_status = EXIT_STATUS_KILLED;
190 resp_err = cl->b->tx_vtbl.kill_response(cl->b, NOP_CONT,
194 struct domain_waiter *waiter = entry->waiters;
195 while (waiter != NULL) {
196 waiter->b->tx_vtbl.wait_response(waiter->b, NOP_CONT,
199 struct domain_waiter *tmp = waiter;
200 waiter = waiter->next;
204 for (coreid_t i = 0; i < MAX_COREID; ++i) {
205 if (entry->spawnds[i] == NULL) {
209 struct spawn_binding *spb = entry->spawnds[i]->b;
211 struct pending_kill_cleanup *cleanup =
212 (struct pending_kill_cleanup*) malloc(
213 sizeof(struct pending_kill_cleanup));
215 cleanup->domain_cap = kc->domain_cap;
216 cleanup->entry = entry;
218 struct pending_client *cleanup_cl =
219 (struct pending_client*) malloc(
220 sizeof(struct pending_client));
221 cleanup_cl->b = cl->b;
222 cleanup_cl->type = ClientType_Cleanup;
223 cleanup_cl->st = cleanup;
225 struct msg_queue_elem *msg = (struct msg_queue_elem*) malloc(
226 sizeof(struct msg_queue_elem));
227 msg->st = cleanup_cl;
228 msg->cont = cleanup_request_sender;
230 err = spawnd_state_enqueue_send(entry->spawnds[i], msg);
232 if (err_is_fail(err)) {
233 DEBUG_ERR(err, "enqueuing cleanup request");
245 USER_PANIC("Unknown client type in spawn_reply_handler: %u\n",
252 static bool spawn_request_sender(struct msg_queue_elem *m)
254 struct pending_client *cl = (struct pending_client*) m->st;
255 struct pending_spawn *spawn = (struct pending_spawn*) cl->st;
256 spawn->b->rx_vtbl.spawn_reply = spawn_reply_handler;
259 bool with_caps = !(capref_is_null(spawn->inheritcn_cap) &&
260 capref_is_null(spawn->argcn_cap));
262 err = spawn->b->tx_vtbl.spawn_with_caps_request(spawn->b, NOP_CONT,
264 spawn->cap_node->domain_cap,
270 spawn->inheritcn_cap,
274 err = spawn->b->tx_vtbl.spawn_request(spawn->b, NOP_CONT, cap_procmng,
275 spawn->cap_node->domain_cap,
276 spawn->path, spawn->argvbuf,
277 spawn->argvbytes, spawn->envbuf,
278 spawn->envbytes, spawn->flags);
281 if (err_is_fail(err)) {
282 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
285 USER_PANIC_ERR(err, "sending spawn request");
294 static bool span_request_sender(struct msg_queue_elem *m)
296 struct pending_client *cl = (struct pending_client*) m->st;
297 struct pending_span *span = (struct pending_span*) cl->st;
300 span->b->rx_vtbl.spawn_reply = spawn_reply_handler;
301 err = span->b->tx_vtbl.span_request(span->b, NOP_CONT, cap_procmng,
302 span->domain_cap, span->vroot,
305 if (err_is_fail(err)) {
306 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
309 USER_PANIC_ERR(err, "sending span request");
318 static bool kill_request_sender(struct msg_queue_elem *m)
320 struct pending_client *cl = (struct pending_client*) m->st;
321 struct pending_kill_cleanup *kill = (struct pending_kill_cleanup*) cl->st;
324 kill->b->rx_vtbl.spawn_reply = spawn_reply_handler;
325 err = kill->b->tx_vtbl.kill_request(kill->b, NOP_CONT, cap_procmng,
328 if (err_is_fail(err)) {
329 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
332 USER_PANIC_ERR(err, "sending kill request");
341 static bool cleanup_request_sender(struct msg_queue_elem *m)
343 struct pending_client *cl = (struct pending_client*) m->st;
344 struct pending_kill_cleanup *cleanup = (struct pending_kill_cleanup*) cl->st;
347 cleanup->b->rx_vtbl.spawn_reply = spawn_reply_handler;
348 err = cleanup->b->tx_vtbl.cleanup_request(cleanup->b, NOP_CONT,
350 cleanup->domain_cap);
352 if (err_is_fail(err)) {
353 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
356 USER_PANIC_ERR(err, "sending cleanup request");
365 static errval_t spawn_handler_common(struct proc_mgmt_binding *b,
366 enum ClientType type,
367 coreid_t core_id, const char *path,
368 const char *argvbuf, size_t argvbytes,
369 const char *envbuf, size_t envbytes,
370 struct capref inheritcn_cap,
371 struct capref argcn_cap, uint8_t flags)
373 #ifdef PROC_MGMT_BENCH
374 cycles_t tsc_start, tsc_end;
377 tsc_start = bench_tsc();
379 if (!spawnd_state_exists(core_id)) {
380 return PROC_MGMT_ERR_INVALID_SPAWND;
382 #ifdef PROC_MGMT_BENCH
383 tsc_end = bench_tsc();
384 result = calculate_time(tsc_start, tsc_end);
386 if (req_ctl_1 != NULL && bench_ctl_add_run(req_ctl_1, &result)) {
387 bench_ctl_dump_analysis(req_ctl_1, 0, "proc_mgmt_req 1", tscperus);
388 bench_ctl_destroy(req_ctl_1);
393 #ifdef PROC_MGMT_BENCH
394 tsc_start = bench_tsc();
396 struct spawnd_state *spawnd = spawnd_state_get(core_id);
397 assert(spawnd != NULL);
398 struct spawn_binding *cl = spawnd->b;
400 #ifdef PROC_MGMT_BENCH
401 tsc_end = bench_tsc();
402 result = calculate_time(tsc_start, tsc_end);
404 if (req_ctl_2 != NULL && bench_ctl_add_run(req_ctl_2, &result)) {
405 bench_ctl_dump_analysis(req_ctl_2, 0, "proc_mgmt_req 2", tscperus);
406 bench_ctl_destroy(req_ctl_2);
411 #ifdef PROC_MGMT_BENCH
412 tsc_start = bench_tsc();
415 if (domain_should_refill_caps()) {
416 err = domain_prealloc_caps();
417 if (err_is_fail(err)) {
418 return err_push(err, PROC_MGMT_ERR_CREATE_DOMAIN_CAP);
422 struct domain_cap_node *cap_node = next_cap_node();
424 // struct capref domain_cap;
425 // errval_t err = slot_alloc(&domain_cap);
426 // if (err_is_fail(err)) {
427 // DEBUG_ERR(err, "slot_alloc domain_cap");
428 // return err_push(err, PROC_MGMT_ERR_CREATE_DOMAIN_CAP);
430 #ifdef PROC_MGMT_BENCH
431 tsc_end = bench_tsc();
432 result = calculate_time(tsc_start, tsc_end);
434 if (req_ctl_3 != NULL && bench_ctl_add_run(req_ctl_3, &result)) {
435 bench_ctl_dump_analysis(req_ctl_3, 0, "proc_mgmt_req 3", tscperus);
436 bench_ctl_destroy(req_ctl_3);
441 #ifdef PROC_MGMT_BENCH
442 tsc_start = bench_tsc();
444 struct pending_spawn *spawn = (struct pending_spawn*) malloc(
445 sizeof(struct pending_spawn));
446 spawn->cap_node = cap_node;
447 // spawn->domain_cap = domain_cap;
449 spawn->core_id = core_id;
451 spawn->argvbuf = argvbuf;
452 spawn->argvbytes = argvbytes;
453 spawn->envbuf = envbuf;
454 spawn->envbytes = envbytes;
455 spawn->inheritcn_cap = inheritcn_cap;
456 spawn->argcn_cap = argcn_cap;
457 spawn->flags = flags;
459 struct pending_client *spawn_cl = (struct pending_client*) malloc(
460 sizeof(struct pending_client));
462 spawn_cl->type = type;
463 spawn_cl->st = spawn;
465 struct msg_queue_elem *msg = (struct msg_queue_elem*) malloc(
466 sizeof(struct msg_queue_elem));
468 msg->cont = spawn_request_sender;
470 err = spawnd_state_enqueue_send(spawnd, msg);
471 if (err_is_fail(err)) {
472 DEBUG_ERR(err, "enqueuing spawn request");
478 #ifdef PROC_MGMT_BENCH
479 tsc_end = bench_tsc();
480 result = calculate_time(tsc_start, tsc_end);
482 if (req_ctl_5 != NULL && bench_ctl_add_run(req_ctl_5, &result)) {
483 bench_ctl_dump_analysis(req_ctl_5, 0, "proc_mgmt_req 5", tscperus);
484 bench_ctl_destroy(req_ctl_5);
492 static void spawn_handler(struct proc_mgmt_binding *b, coreid_t core_id,
493 const char *path, const char *argvbuf,
494 size_t argvbytes, const char *envbuf, size_t envbytes,
497 errval_t err, resp_err;
498 err = spawn_handler_common(b, ClientType_Spawn, core_id, path, argvbuf,
499 argvbytes, envbuf, envbytes, NULL_CAP, NULL_CAP,
502 if (err_is_fail(err)) {
503 resp_err = b->tx_vtbl.spawn_response(b, NOP_CONT, err, NULL_CAP);
504 if (err_is_fail(resp_err)) {
505 DEBUG_ERR(resp_err, "failed to send spawn_response");
510 static void spawn_with_caps_handler(struct proc_mgmt_binding *b,
511 coreid_t core_id, const char *path,
512 const char *argvbuf, size_t argvbytes,
513 const char *envbuf, size_t envbytes,
514 struct capref inheritcn_cap,
515 struct capref argcn_cap, uint8_t flags)
517 errval_t err, resp_err;
518 err = spawn_handler_common(b, ClientType_SpawnWithCaps, core_id, path,
519 argvbuf, argvbytes, envbuf, envbytes,
520 inheritcn_cap, argcn_cap, flags);
521 if (err_is_ok(err)) {
522 // Will respond to client when we get the reply from spawnd.
526 resp_err = b->tx_vtbl.spawn_with_caps_response(b, NOP_CONT, err,
528 if (err_is_fail(resp_err)) {
529 DEBUG_ERR(resp_err, "failed to send spawn_with_caps_response");
533 static void span_handler(struct proc_mgmt_binding *b, struct capref domain_cap,
534 coreid_t core_id, struct capref vroot,
535 struct capref dispframe)
537 errval_t err, resp_err;
538 struct domain_entry *entry = NULL;
539 err = domain_get_by_cap(domain_cap, &entry);
540 if (err_is_fail(err)) {
541 goto respond_with_err;
544 assert(entry != NULL);
545 if (entry->status != DOMAIN_STATUS_RUNNING) {
546 err = PROC_MGMT_ERR_DOMAIN_NOT_RUNNING;
547 goto respond_with_err;
550 if (entry->spawnds[core_id] != NULL) {
551 // TODO(razvan): Maybe we want to allow the same domain to span multiple
552 // dispatchers onto the same core?
553 err = PROC_MGMT_ERR_ALREADY_SPANNED;
554 goto respond_with_err;
557 if (!spawnd_state_exists(core_id)) {
558 err = PROC_MGMT_ERR_INVALID_SPAWND;
559 goto respond_with_err;
562 struct spawnd_state *spawnd = spawnd_state_get(core_id);
563 assert(spawnd != NULL);
564 struct spawn_binding *cl = spawnd->b;
567 struct pending_span *span = (struct pending_span*) malloc(
568 sizeof(struct pending_span));
569 span->domain_cap = domain_cap;
572 span->core_id = core_id;
574 span->dispframe = dispframe;
576 struct pending_client *span_cl = (struct pending_client*) malloc(
577 sizeof(struct pending_client));
579 span_cl->type = ClientType_Span;
582 struct msg_queue_elem *msg = (struct msg_queue_elem*) malloc(
583 sizeof(struct msg_queue_elem));
585 msg->cont = span_request_sender;
587 err = spawnd_state_enqueue_send(spawnd, msg);
589 if (err_is_fail(err)) {
590 DEBUG_ERR(err, "enqueuing span request");
597 resp_err = b->tx_vtbl.span_response(b, NOP_CONT, err);
598 if (err_is_fail(resp_err)) {
599 DEBUG_ERR(resp_err, "failed to send span_response");
603 static errval_t kill_handler_common(struct proc_mgmt_binding *b,
604 struct capref domain_cap,
605 enum ClientType type,
608 struct domain_entry *entry;
609 errval_t err = domain_get_by_cap(domain_cap, &entry);
610 if (err_is_fail(err)) {
614 entry->exit_status = exit_status;
615 domain_stop_pending(entry);
617 for (coreid_t i = 0; i < MAX_COREID; ++i) {
618 if (entry->spawnds[i] == NULL) {
622 struct spawn_binding *spb = entry->spawnds[i]->b;
624 struct pending_kill_cleanup *cmd = (struct pending_kill_cleanup*) malloc(
625 sizeof(struct pending_kill_cleanup));
626 cmd->domain_cap = domain_cap;
630 struct pending_client *cl = (struct pending_client*) malloc(
631 sizeof(struct pending_client));
636 struct msg_queue_elem *msg = (struct msg_queue_elem*) malloc(
637 sizeof(struct msg_queue_elem));
639 msg->cont = kill_request_sender;
641 err = spawnd_state_enqueue_send(entry->spawnds[i], msg);
642 if (err_is_fail(err)) {
643 DEBUG_ERR(err, "enqueuing kill request");
653 static void kill_handler(struct proc_mgmt_binding *b,
654 struct capref victim_domain_cap)
656 errval_t err = kill_handler_common(b, victim_domain_cap, ClientType_Kill,
658 if (err_is_fail(err)) {
659 errval_t resp_err = b->tx_vtbl.kill_response(b, NOP_CONT, err);
660 if (err_is_fail(resp_err)) {
661 DEBUG_ERR(resp_err, "failed to send kill_response");
666 static void exit_handler(struct proc_mgmt_binding *b, struct capref domain_cap,
669 errval_t err = kill_handler_common(b, domain_cap, ClientType_Exit,
671 if (err_is_fail(err)) {
672 DEBUG_ERR(err, "processing exit_handler for requesting domain, exit "
673 "code %u", exit_status);
675 // Error or not, there's no client to respond to anymore.
678 static void wait_handler(struct proc_mgmt_binding *b, struct capref domain_cap)
680 errval_t err, resp_err;
681 struct domain_entry *entry;
682 err = domain_get_by_cap(domain_cap, &entry);
683 if (err_is_fail(err)) {
687 if (entry->status == DOMAIN_STATUS_STOPPED) {
688 // Domain has already been stopped, so just reply with exit status.
692 struct domain_waiter *waiter = (struct domain_waiter*) malloc(
693 sizeof(struct domain_waiter));
695 waiter->next = entry->waiters;
696 entry->waiters = waiter;
697 // Will respond when domain is stopped.
701 resp_err = b->tx_vtbl.wait_response(b, NOP_CONT, err, entry->exit_status);
702 if (err_is_fail(resp_err)) {
703 DEBUG_ERR(resp_err, "failed to send wait_response");
707 static struct proc_mgmt_rx_vtbl monitor_vtbl = {
708 .add_spawnd = add_spawnd_handler,
709 .spawn_call = spawn_handler,
710 .spawn_with_caps_call = spawn_with_caps_handler,
711 .span_call = span_handler,
712 .kill_call = kill_handler,
713 // .exit_call = exit_handler,
714 .exit = exit_handler,
715 .wait_call = wait_handler
718 static struct proc_mgmt_rx_vtbl non_monitor_vtbl = {
719 .add_spawnd = add_spawnd_handler_non_monitor,
720 .spawn_call = spawn_handler,
721 .spawn_with_caps_call = spawn_with_caps_handler,
722 .span_call = span_handler,
723 .kill_call = kill_handler,
724 // .exit_call = exit_handler,
725 .exit = exit_handler,
726 .wait_call = wait_handler
729 static errval_t alloc_ep_for_monitor(struct capref *ep)
731 struct proc_mgmt_lmp_binding *lmpb =
732 malloc(sizeof(struct proc_mgmt_lmp_binding));
733 assert(lmpb != NULL);
735 // setup our end of the binding
736 errval_t err = proc_mgmt_client_lmp_accept(lmpb, get_default_waitset(),
737 DEFAULT_LMP_BUF_WORDS);
738 if (err_is_fail(err)) {
740 return err_push(err, LIB_ERR_PROC_MGMT_CLIENT_ACCEPT);
743 *ep = lmpb->chan.local_cap;
744 lmpb->b.rx_vtbl = monitor_vtbl;
749 static void export_cb(void *st, errval_t err, iref_t iref)
751 if (err_is_fail(err)) {
752 USER_PANIC_ERR(err, "export failed");
755 // Allocate an endpoint for the local monitor, who will use it to inform
756 // us about new spawnd irefs on behalf of other monitors.
758 err = alloc_ep_for_monitor(&ep);
759 if (err_is_fail(err)) {
760 USER_PANIC_ERR(err, "failed to allocate LMP EP for local monitor");
763 // Send the endpoint to the monitor, so it can finish the handshake.
764 struct monitor_binding *mb = get_monitor_binding();
765 err = mb->tx_vtbl.set_proc_mgmt_ep_request(mb, NOP_CONT, ep);
766 if (err_is_fail(err)) {
767 USER_PANIC_ERR(err, "failed to send set_proc_mgmt_ep_request to "
771 // Also register this iref with the name service, for arbitrary client
772 // domains to use for spawn-related ops.
773 err = nameservice_register(SERVICE_BASENAME, iref);
774 if (err_is_fail(err)) {
775 USER_PANIC_ERR(err, "nameservice_register failed");
779 static errval_t connect_cb(void *st, struct proc_mgmt_binding *b)
781 b->rx_vtbl = non_monitor_vtbl;
785 errval_t start_service(void)
788 #ifdef PROC_MGMT_BENCH
791 req_ctl_1 = calloc(1, sizeof(*req_ctl_1));
792 req_ctl_1->mode = BENCH_MODE_FIXEDRUNS;
793 req_ctl_1->result_dimensions = 1;
794 req_ctl_1->min_runs = PROC_MGMT_BENCH_MIN_RUNS;
795 req_ctl_1->data = calloc(req_ctl_1->min_runs * req_ctl_1->result_dimensions,
796 sizeof(*req_ctl_1->data));
798 req_ctl_2 = calloc(1, sizeof(*req_ctl_2));
799 req_ctl_2->mode = BENCH_MODE_FIXEDRUNS;
800 req_ctl_2->result_dimensions = 1;
801 req_ctl_2->min_runs = PROC_MGMT_BENCH_MIN_RUNS;
802 req_ctl_2->data = calloc(req_ctl_2->min_runs * req_ctl_2->result_dimensions,
803 sizeof(*req_ctl_2->data));
805 req_ctl_3 = calloc(1, sizeof(*req_ctl_3));
806 req_ctl_3->mode = BENCH_MODE_FIXEDRUNS;
807 req_ctl_3->result_dimensions = 1;
808 req_ctl_3->min_runs = PROC_MGMT_BENCH_MIN_RUNS;
809 req_ctl_3->data = calloc(req_ctl_3->min_runs * req_ctl_3->result_dimensions,
810 sizeof(*req_ctl_3->data));
812 req_ctl_4 = calloc(1, sizeof(*req_ctl_4));
813 req_ctl_4->mode = BENCH_MODE_FIXEDRUNS;
814 req_ctl_4->result_dimensions = 1;
815 req_ctl_4->min_runs = PROC_MGMT_BENCH_MIN_RUNS;
816 req_ctl_4->data = calloc(req_ctl_4->min_runs * req_ctl_4->result_dimensions,
817 sizeof(*req_ctl_4->data));
819 req_ctl_5 = calloc(1, sizeof(*req_ctl_5));
820 req_ctl_5->mode = BENCH_MODE_FIXEDRUNS;
821 req_ctl_5->result_dimensions = 1;
822 req_ctl_5->min_runs = PROC_MGMT_BENCH_MIN_RUNS;
823 req_ctl_5->data = calloc(req_ctl_5->min_runs * req_ctl_5->result_dimensions,
824 sizeof(*req_ctl_5->data));
826 resp_ctl = calloc(1, sizeof(*resp_ctl));
827 resp_ctl->mode = BENCH_MODE_FIXEDRUNS;
828 resp_ctl->result_dimensions = 1;
829 resp_ctl->min_runs = PROC_MGMT_BENCH_MIN_RUNS;
830 resp_ctl->data = calloc(resp_ctl->min_runs * resp_ctl->result_dimensions,
831 sizeof(*resp_ctl->data));
833 err = sys_debug_get_tsc_per_ms(&tscperus);
834 assert(err_is_ok(err));
838 err = domain_prealloc_caps();
839 if (err_is_fail(err)) {
840 USER_PANIC_ERR(err_push(err, PROC_MGMT_ERR_CREATE_DOMAIN_CAP),
841 "domain_prealloc_caps in start_service");
844 return proc_mgmt_export(NULL, export_cb, connect_cb, get_default_waitset(),
845 IDC_EXPORT_FLAGS_DEFAULT);