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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 10 */ 11 12#include <barrelfish/barrelfish.h> 13#include <collections/hash_table.h> 14#include <collections/list.h> 15#include <if/spawn_defs.h> 16 17#include "domain.h" 18#include "spawnd_state.h" 19 20#define HASH_INDEX_BUCKETS 6151 21static collections_hash_table* domain_table = NULL; 22 23#define DOMAIN_CAP_REFILL_COUNT L2_CNODE_SLOTS//1 24static struct domain_cap_node *domain_cap_list = NULL; 25static uint32_t free_domain_caps = 0; 26static domainid_t domain_alloc = 0; 27 28inline bool domain_should_refill_caps(void) { 29 return free_domain_caps == 0; 30} 31 32/** 33 * \brief Allocates a new L2 cnode and fills it with domain capabilities. 34 */ 35errval_t domain_prealloc_caps(void) 36{ 37 struct capref new_cnode_cap; 38 struct cnoderef new_cnode; 39 errval_t err = cnode_create_l2(&new_cnode_cap, &new_cnode); 40 if (err_is_fail(err)) { 41 DEBUG_ERR(err, "cnode_create_l2"); 42 return err_push(err, PROC_MGMT_ERR_CREATE_DOMAIN_CAP); 43 } 44 45 struct capref cap_iter = { 46 .cnode = new_cnode, 47 .slot = 0 48 }; 49 err = cap_retype(cap_iter, cap_procmng, 0, ObjType_Domain, 0, 50 DOMAIN_CAP_REFILL_COUNT); 51 if (err_is_fail(err)) { 52 DEBUG_ERR(err, "cap_retype"); 53 return err_push(err, PROC_MGMT_ERR_CREATE_DOMAIN_CAP); 54 } 55 56 for (cap_iter.slot = 0; cap_iter.slot < DOMAIN_CAP_REFILL_COUNT; ++cap_iter.slot) { 57 struct domain_cap_node *node = (struct domain_cap_node*) malloc( 58 sizeof(struct domain_cap_node)); 59 node->domain_cap = cap_iter; 60 61 err = domain_cap_hash(node->domain_cap, &node->hash); 62 if (err_is_fail(err)) { 63 DEBUG_ERR(err, "domain_cap_hash"); 64 return err_push(err, PROC_MGMT_ERR_CREATE_DOMAIN_CAP); 65 } 66 67 node->next = domain_cap_list; 68 domain_cap_list = node; 69 ++free_domain_caps; 70 } 71 72 return SYS_ERR_OK; 73} 74 75/** 76 * \brief Returns the next node in the list of available domain caps. 77 */ 78struct domain_cap_node *next_cap_node(void) 79{ 80 assert(domain_cap_list != NULL); 81 assert(free_domain_caps > 0); 82 83 struct domain_cap_node *tmp = domain_cap_list; 84 domain_cap_list = domain_cap_list->next; 85 --free_domain_caps; 86 87 return tmp; 88} 89 90/** 91 * \brief Creates and returns a new domain entry. 92 * 93 * \param cap_node preallocated domain cap node. 94 * \param ret_entry returned domain entry, must be passed in non-NULL. 95 */ 96errval_t domain_new(struct domain_cap_node *cap_node, const char* argbuf, 97 size_t argbytes, struct domain_entry **ret_entry) 98{ 99 assert(ret_entry != NULL); 100 101 struct domain_entry *entry = (struct domain_entry*) malloc( 102 sizeof(struct domain_entry)); 103 if (entry == NULL) { 104 return LIB_ERR_MALLOC_FAIL; 105 } 106 107 entry->cap_node = cap_node; 108 entry->status = DOMAIN_STATUS_NIL; 109 memset(entry->spawnds, 0, sizeof(entry->spawnds)); 110 entry->num_spawnds_running = 0; 111 entry->num_spawnds_resources = 0; 112 entry->waiters = NULL; 113 114 entry->domainid = domain_alloc; 115 domain_alloc++; 116 117 entry->argbuf = memdup(argbuf, argbytes); 118 entry->argbytes = argbytes; 119 120 if (domain_table == NULL) { 121 collections_hash_create_with_buckets(&domain_table, HASH_INDEX_BUCKETS, 122 NULL); 123 if (domain_table == NULL) { 124 return PROC_MGMT_ERR_CREATE_DOMAIN_TABLE; 125 } 126 } 127 128 collections_hash_insert(domain_table, cap_node->hash, entry); 129 130 *ret_entry = entry; 131 132 return SYS_ERR_OK; 133} 134 135/** 136 * \brief Returns the domain entry associated with the given domain cap. 137 * 138 * \param domain_cap identifying cap for which to look up the domain entry. 139 * \param returned domain entry, must be passed in non-NULL. 140 */ 141errval_t domain_get_by_cap(struct capref domain_cap, 142 struct domain_entry **ret_entry) 143{ 144 assert(ret_entry != NULL); 145 146 uint64_t key; 147 errval_t err = domain_cap_hash(domain_cap, &key); 148 if (err_is_fail(err)) { 149 return err; 150 } 151 152 void *table_entry = collections_hash_find(domain_table, key); 153 if (table_entry == NULL) { 154 return PROC_MGMT_ERR_DOMAIN_TABLE_FIND; 155 } 156 *ret_entry = (struct domain_entry*) table_entry; 157 158 return SYS_ERR_OK; 159} 160 161errval_t domain_get_by_id(domainid_t domain_id, 162 struct domain_entry **ret_entry) 163{ 164 // XXX slow since we traverse the whole hash map 165 collections_hash_traverse_start(domain_table); 166 167 uint64_t key; 168 void* ele = collections_hash_traverse_next(domain_table, &key); 169 170 // get all domain ids and store in list 171 // XXX traverse whole hash table since it seems to not 172 // reset the internal lists when resetting the traversal of the hash table 173 while (ele != NULL) { 174 struct domain_entry *entry = (struct domain_entry*) ele; 175 176 if (entry->domainid == domain_id) { 177 *ret_entry = entry; 178 } 179 180 ele = collections_hash_traverse_next(domain_table, &key); 181 } 182 183 collections_hash_traverse_end(domain_table); 184 if (ret_entry == NULL) { 185 return PROC_MGMT_ERR_DOMAIN_TABLE_FIND; 186 } else { 187 return SYS_ERR_OK; 188 } 189} 190 191/** 192 * \brief Adds a new core to the list of cores where the given domain runs. 193 * 194 * \param entry domain entry to add a new core for. 195 * \param core_id new core running a dispatcher for the domain. 196 */ 197void domain_run_on_core(struct domain_entry *entry, coreid_t core_id) 198{ 199 assert(entry != NULL); 200 assert(core_id < MAX_COREID); 201 assert(entry->status == DOMAIN_STATUS_NIL || 202 entry->status == DOMAIN_STATUS_RUNNING); 203 204 entry->status = DOMAIN_STATUS_RUNNING; 205 206 entry->spawnds[core_id] = spawnd_state_get(core_id); 207 ++entry->num_spawnds_running; 208 ++entry->num_spawnds_resources; 209} 210 211 212/** 213 * \brief Creates a new domain entry for the given cap node and core. 214 * 215 * \param cap_node preallocated capability node for the new domain. 216 * \param core_id core that runs the new domain. 217 */ 218errval_t domain_spawn(struct domain_cap_node *cap_node, coreid_t core_id, 219 const char* argbuf, size_t argbytes) 220{ 221 struct domain_entry *entry = NULL; 222 errval_t err = domain_new(cap_node, argbuf, argbytes, &entry); 223 if (err_is_fail(err)) { 224 if (entry != NULL) { 225 free(entry); 226 } 227 return err; 228 } 229 230 domain_run_on_core(entry, core_id); 231 232 return SYS_ERR_OK; 233} 234 235/** 236 * \brief Marks that the domain identified by the given cap spans a new core. 237 * 238 * \param domain_cap identifying capability for the spanning domain. 239 * \param core_id new core which the domain spans. 240 */ 241errval_t domain_span(struct capref domain_cap, coreid_t core_id) 242{ 243 struct domain_entry *entry = NULL; 244 errval_t err = domain_get_by_cap(domain_cap, &entry); 245 if (err_is_fail(err)) { 246 return err; 247 } 248 assert(entry != NULL); 249 250 domain_run_on_core(entry, core_id); 251 252 return SYS_ERR_OK; 253} 254 255void domain_get_all_ids(domainid_t** domains, size_t* len) 256{ 257 if (domain_table == NULL) { 258 *len = 0; 259 return; 260 } 261 262 collections_hash_traverse_start(domain_table); 263 264 collections_listnode* start; 265 collections_list_create(&start, NULL); 266 267 uint64_t key; 268 void* ele = collections_hash_traverse_next(domain_table, &key); 269 270 // get all domain ids and store in list 271 while (ele != NULL) { 272 struct domain_entry *entry = (struct domain_entry*) ele; 273 274 if (entry->status != DOMAIN_STATUS_CLEANED) { 275 collections_list_insert(start, &entry->domainid); 276 } 277 278 ele = collections_hash_traverse_next(domain_table, &key); 279 } 280 281 domainid_t* doms = (domainid_t*) calloc(1, sizeof(domainid_t)* 282 collections_list_size(start)); 283 284 *len = collections_list_size(start); 285 // copy domain ids 286 for (int i = 0; i < collections_list_size(start); i++) { 287 doms[i] = *((domainid_t*) collections_list_get_ith_item(start, i)); 288 } 289 290 collections_list_release(start); 291 *domains = doms; 292 collections_hash_traverse_end(domain_table); 293} 294