Break the spawnd kill API into kill + cleanup.
[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 #include <if/spawn_defs.h>
15
16 #include "domain.h"
17 #include "spawnd_state.h"
18
19 #define HASH_INDEX_BUCKETS 6151
20 static collections_hash_table* domain_table = NULL;
21
22 errval_t domain_new(struct capref domain_cap, struct domain_entry **ret_entry)
23 {
24     assert(ret_entry != NULL);
25
26     struct domain_entry *entry = (struct domain_entry*) malloc(
27             sizeof(struct domain_entry));
28     if (entry == NULL) {
29         return LIB_ERR_MALLOC_FAIL;
30     }
31
32     entry->domain_cap = domain_cap;
33     entry->status = DOMAIN_STATUS_NIL;
34     memset(entry->spawnds, 0, sizeof(entry->spawnds));
35     entry->num_spawnds_running = 0;
36     entry->num_spawnds_resources = 0;
37     entry->waiters = NULL;
38
39     if (domain_table == NULL) {
40         collections_hash_create_with_buckets(&domain_table, HASH_INDEX_BUCKETS,
41                                              NULL);
42         if (domain_table == NULL) {
43             return PROC_MGMT_ERR_CREATE_DOMAIN_TABLE;
44         }
45     }
46
47     uint64_t key;
48     errval_t err = domain_cap_hash(entry->domain_cap, &key);
49     if (err_is_fail(err)) {
50         return err;
51     }
52
53     collections_hash_insert(domain_table, key, entry);
54
55     *ret_entry = entry;
56
57     return SYS_ERR_OK;
58 }
59
60 errval_t domain_get_by_cap(struct capref domain_cap,
61                            struct domain_entry **ret_entry)
62 {
63     assert(ret_entry != NULL);
64
65     uint64_t key;
66     errval_t err = domain_cap_hash(domain_cap, &key);
67     if (err_is_fail(err)) {
68         return err;
69     }
70
71     void *table_entry = collections_hash_find(domain_table, key);
72     if (table_entry == NULL) {
73         return PROC_MGMT_ERR_DOMAIN_TABLE_FIND;
74     }
75     *ret_entry = (struct domain_entry*) table_entry;
76
77     return SYS_ERR_OK;
78 }
79
80 void domain_run_on_core(struct domain_entry *entry, coreid_t core_id)
81 {
82     assert(entry != NULL);
83     assert(core_id < MAX_COREID);
84     assert(entry->status == DOMAIN_STATUS_NIL ||
85            entry->status == DOMAIN_STATUS_RUNNING);
86
87     entry->status = DOMAIN_STATUS_RUNNING;
88
89     entry->spawnds[core_id] = spawnd_state_get(core_id);
90     ++entry->num_spawnds_running;
91     ++entry->num_spawnds_resources;
92 }
93
94 errval_t domain_spawn(struct capref domain_cap, coreid_t core_id)
95 {
96     struct domain_entry *entry = NULL;
97     errval_t err = domain_new(domain_cap, &entry);
98     if (err_is_fail(err)) {
99         if (entry != NULL) {
100             free(entry);
101         }
102         return err;
103     }
104
105     domain_run_on_core(entry, core_id);
106
107     return SYS_ERR_OK;
108 }
109
110 errval_t domain_can_span(struct capref domain_cap, coreid_t core_id)
111 {
112     struct domain_entry *entry = NULL;
113     errval_t err = domain_get_by_cap(domain_cap, &entry);
114     if (err_is_fail(err)) {
115         return err;
116     }
117
118     assert(entry != NULL);
119     if (entry->status != DOMAIN_STATUS_RUNNING) {
120         return PROC_MGMT_ERR_DOMAIN_NOT_RUNNING;
121     }
122
123     if (entry->spawnds[core_id] != NULL) {
124         // TODO(razvan): Maybe we want to allow the same domain to span multiple
125         // dispatchers onto the same core?
126         return PROC_MGMT_ERR_ALREADY_SPANNED;
127     }
128
129     return SYS_ERR_OK;
130 }
131
132 errval_t domain_span(struct capref domain_cap, coreid_t core_id)
133 {
134     struct domain_entry *entry = NULL;
135     errval_t err = domain_get_by_cap(domain_cap, &entry);
136     if (err_is_fail(err)) {
137         return err;
138     }
139     assert(entry != NULL);
140
141     domain_run_on_core(entry, core_id);
142
143     return SYS_ERR_OK;
144 }