Add spawn, spawn_with_caps and span calls to the Process Manager API.
[barrelfish] / usr / proc_mgmt / domain.c
1 /*
2  * \brief Domain internals for the process manager.
3  *
4  * Copyright (c) 2017, ETH Zurich.
5  * All rights reserved.
6  *
7  * This file is distributed under the terms in the attached LICENSE file.
8  * If you do not find this file, copies can be found by writing to:
9  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
10  */
11
12 #include <barrelfish/barrelfish.h>
13 #include <collections/hash_table.h>
14
15 #include "domain.h"
16
17 #define HASH_INDEX_BUCKETS 6151
18 static collections_hash_table* domain_table = NULL;
19
20 errval_t domain_cap_hash(struct capref domain_cap, uint64_t *ret_hash)
21 {
22     assert(ret_hash != NULL);
23
24     struct capability ret_cap;
25     errval_t err = debug_cap_identify(domain_cap, &ret_cap);
26     if (err_is_fail(err)) {
27         return err_push(err, PROC_MGMT_ERR_DOMAIN_CAP_HASH);
28     }
29     assert(ret_cap.type == ObjType_Domain);
30
31     static uint64_t base = 1 + (uint64_t) MAX_COREID;
32     *ret_hash = base * ret_cap.u.domain.coreid + ret_cap.u.domain.core_local_id;
33
34     return SYS_ERR_OK;
35 }
36
37 errval_t domain_new(struct capref domain_cap, struct domain_entry **ret_entry)
38 {
39     assert(ret_entry != NULL);
40
41     struct domain_entry *entry = (struct domain_entry*) malloc(
42             sizeof(struct domain_entry));
43     if (entry == NULL) {
44         return LIB_ERR_MALLOC_FAIL;
45     }
46
47     entry->domain_cap = domain_cap;
48     entry->status = DOMAIN_STATUS_NIL;
49     entry->spawnds = NULL;
50     entry->waiters = NULL;
51
52     if (domain_table == NULL) {
53         collections_hash_create_with_buckets(&domain_table, HASH_INDEX_BUCKETS,
54                                              NULL);
55         if (domain_table == NULL) {
56             return PROC_MGMT_ERR_CREATE_DOMAIN_TABLE;
57         }
58     }
59
60     uint64_t key;
61     errval_t err = domain_cap_hash(entry->domain_cap, &key);
62     if (err_is_fail(err)) {
63         return err;
64     }
65
66     collections_hash_insert(domain_table, key, entry);
67
68     *ret_entry = entry;
69
70     return SYS_ERR_OK;
71 }
72
73 errval_t domain_get_by_cap(struct capref domain_cap,
74                            struct domain_entry **ret_entry)
75 {
76     assert(ret_entry != NULL);
77
78     uint64_t key;
79     errval_t err = domain_cap_hash(domain_cap, &key);
80     if (err_is_fail(err)) {
81         return err;
82     }
83
84     void *table_entry = collections_hash_find(domain_table, key);
85     if (table_entry == NULL) {
86         return PROC_MGMT_ERR_DOMAIN_TABLE_FIND;
87     }
88     *ret_entry = (struct domain_entry*) table_entry;
89
90     return SYS_ERR_OK;
91 }
92
93 void domain_run_on_spawnd(struct domain_entry *entry,
94                           struct spawnd_state *spawnd)
95 {
96     assert(entry != NULL);
97     assert(spawnd != NULL);
98     assert(entry->status == DOMAIN_STATUS_NIL ||
99            entry->status == DOMAIN_STATUS_RUNNING);
100
101     entry->status = DOMAIN_STATUS_RUNNING;
102
103     struct domain_spawnd_state *st = (struct domain_spawnd_state*) malloc(
104             sizeof(struct domain_spawnd_state));
105     st->spawnd_state = spawnd;
106     st->next = entry->spawnds;
107     entry->spawnds = st;
108 }
109
110 errval_t domain_spawn(struct capref domain_cap, coreid_t core_id)
111 {
112     struct domain_entry *entry = NULL;
113     errval_t err = domain_new(domain_cap, &entry);
114     if (err_is_fail(err)) {
115         if (entry != NULL) {
116             free(entry);
117         }
118         return err;
119     }
120
121     domain_run_on_spawnd(entry, spawnd_state_get(core_id));
122
123     return SYS_ERR_OK;
124 }
125
126 errval_t domain_can_span(struct capref domain_cap, coreid_t core_id)
127 {
128     struct domain_entry *entry = NULL;
129     errval_t err = domain_get_by_cap(domain_cap, &entry);
130     if (err_is_fail(err)) {
131         return err;
132     }
133
134     assert(entry != NULL);
135     if (entry->status != DOMAIN_STATUS_RUNNING) {
136         return PROC_MGMT_ERR_DOMAIN_NOT_RUNNING;
137     }
138
139     struct domain_spawnd_state *st = entry->spawnds;
140     while (st != NULL) {
141         if (st->spawnd_state->core_id == core_id) {
142             // TODO(razvan): Maybe we want to allow the same domain to span
143             // multiple dispatcher onto the same core?
144             return PROC_MGMT_ERR_ALREADY_SPANNED;
145         }
146         st = st->next;
147     }
148
149     return SYS_ERR_OK;
150 }
151
152 errval_t domain_span(struct capref domain_cap, coreid_t core_id)
153 {
154     struct domain_entry *entry = NULL;
155     errval_t err = domain_get_by_cap(domain_cap, &entry);
156     if (err_is_fail(err)) {
157         return err;
158     }
159     assert(entry != NULL);
160
161     domain_run_on_spawnd(entry, spawnd_state_get(core_id));
162
163     return SYS_ERR_OK;
164 }
165
166 void domain_send_stop(struct domain_entry *entry)
167 {
168     assert(entry != NULL);
169
170     struct domain_spawnd_state *st = entry->spawnds;
171     while (st != NULL) {
172         debug_printf("Simulating STOP message to spawnd at binding %p\n",
173                      st->spawnd_state->b);
174         st = st->next;
175     }
176 }