1/** 2 * \file 3 * \brief 4 */ 5 6/* 7 * Copyright (c) 2010, ETH Zurich and Mircosoft Corporation. 8 * All rights reserved. 9 * 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <ctype.h> 16#include "internal.h" 17#include <barrelfish/nameservice_client.h> 18 19struct bind_state { 20 coreid_t id; 21}; 22 23struct coreset *set; 24struct relations *rel; 25static callback retcb; 26 27static void done_reply(struct boot_perfmon_binding *b) 28{ 29 retcb(); 30} 31 32static errval_t done_msging(void *st, coreid_t id, 33 struct boot_perfmon_binding *b) 34{ 35 return b->tx_vtbl.done_reply(b, NOP_CONT); 36} 37 38static void done_request(struct boot_perfmon_binding *b) 39{ 40 errval_t err; 41 static coreid_t count = 0; 42 count++; 43 44 if (count == (coreset_count(set) - 1)) { 45 err = relations_iterate(rel, NULL, done_msging); 46 if (err_is_fail(err)) { 47 USER_PANIC_ERR(err, "relations_iterate failed"); 48 } 49 50 retcb(); 51 } 52} 53 54static void init(struct boot_perfmon_binding *b, coreid_t id) 55{ 56 errval_t err; 57 58 err = relations_add(rel, id, b); 59 if (err_is_fail(err)) { 60 USER_PANIC_ERR(err, "relations_add failed"); 61 } 62 63 // Check if done connecting 64 if (relations_count(rel) == (coreset_count(set) - 1)) { 65 66 if (!check_leader()) { // Message leader that connect is done 67 struct boot_perfmon_binding *lb; 68 err = relations_get(rel, get_leader_id(), &lb); 69 if (err_is_fail(err)) { 70 USER_PANIC_ERR(err, "relations_get failed"); 71 } 72 err = lb->tx_vtbl.done_request(lb, NOP_CONT); 73 if (err_is_fail(err)) { 74 USER_PANIC_ERR(err, "sending done failed"); 75 } 76 } 77 } 78} 79 80static struct boot_perfmon_rx_vtbl vtbl = { 81 .init = init, 82 .done_reply = done_reply, 83 .done_request = done_request, 84 .ping = ping, 85 .pong = pong, 86 .exit = exit_msg, 87}; 88 89static void bind_cb(void *st, errval_t err, struct boot_perfmon_binding *b) 90{ 91 if (err_is_fail(err)) { 92 USER_PANIC_ERR(err, "failure in bind_cb"); 93 } 94 b->rx_vtbl = vtbl; 95 96 struct bind_state *bs = st; 97 err = relations_add(rel, bs->id, b); 98 if (err_is_fail(err)) { 99 USER_PANIC_ERR(err, "relations_add failed"); 100 } 101 free(bs); 102 103 err = b->tx_vtbl.init(b, NOP_CONT, my_core_id); 104 if (err_is_fail(err)) { 105 USER_PANIC_ERR(err, "sending init failed"); 106 } 107 108 // Check if done connecting 109 if (relations_count(rel) == (coreset_count(set) - 1)) { 110 111 if (!check_leader()) { // Message leader that connect is done 112 struct boot_perfmon_binding *lb; 113 err = relations_get(rel, get_leader_id(), &lb); 114 if (err_is_fail(err)) { 115 USER_PANIC_ERR(err, "relations_get failed"); 116 } 117 err = lb->tx_vtbl.done_request(lb, NOP_CONT); 118 if (err_is_fail(err)) { 119 USER_PANIC_ERR(err, "sending done failed"); 120 } 121 } 122 } 123} 124 125/** 126 * \brief Connect to every core with id bigger than mine 127 */ 128static errval_t iter_connect(void *st, coreid_t id) 129{ 130 errval_t err; 131 132 if (my_core_id > id) { 133 iref_t iref; 134 char name[128]; 135 snprintf(name, 128, "boot_perfmon:%d", id); 136 err = nameservice_blocking_lookup(name, &iref); 137 if (err_is_fail(err)) { 138 DEBUG_ERR(err, "nameservice_blocking_lookup failed"); 139 abort(); 140 } 141 142 struct bind_state *bs = malloc(sizeof(struct bind_state)); 143 if (!bs) { 144 USER_PANIC("malloc failed"); 145 } 146 bs->id = id; 147 err = boot_perfmon_bind(iref, bind_cb, bs, get_default_waitset(), 148 IDC_BIND_FLAGS_DEFAULT); 149 if (err_is_fail(err)) { 150 USER_PANIC_ERR(err, "boot_perfmon_bind failed"); 151 } 152 } 153 154 return SYS_ERR_OK; 155} 156 157static void export_cb(void *st, errval_t err, iref_t iref) 158{ 159 if (err_is_fail(err)) { 160 USER_PANIC_ERR(err, "export failed"); 161 } 162 163 char name[128]; 164 snprintf(name, 128, "boot_perfmon:%d", my_core_id); 165 err = nameservice_register(name, iref); 166 if (err_is_fail(err)) { 167 USER_PANIC_ERR(err, "nameservice_register failed"); 168 } 169} 170 171static errval_t connect_cb(void *st, struct boot_perfmon_binding *b) 172{ 173 b->rx_vtbl = vtbl; 174 return SYS_ERR_OK; 175} 176 177/** 178 * \brief Find and add all coreids to coreset 179 */ 180static void set_skb_present(char *str) 181{ 182 errval_t err; 183 184 while (*str != '\0') { 185 if (!isdigit((int)*str)) { 186 str++; 187 continue; 188 } 189 190 coreid_t id = strtol(str, &str, 10); 191 err = coreset_add(set, id); 192 if (err_is_fail(err)) { 193 USER_PANIC_ERR(err, "coreset_add failed"); 194 } 195 } 196} 197 198errval_t connect(callback cb) 199{ 200 errval_t err; 201 retcb = cb; 202 203 /* Initialize the coreset */ 204 err = coreset_new(&set); 205 if (err_is_fail(err)) { 206 return err_push(err, LIB_ERR_CORESET_NEW); 207 } 208 209 /* Initialize the relations */ 210 err = relations_new(&rel); 211 if (err_is_fail(err)) { 212 USER_PANIC_ERR(err, "export failed"); 213 } 214 215 /* Get the list of coreids in the system and add them to the coreset */ 216 char *result, *str_err; 217 int32_t int_err; 218 err = skb_evaluate("get_core_id_list(L),write(L).", 219 &result, &str_err, &int_err); 220 if (err_is_fail(err)) { 221 return err_push(err, SKB_ERR_EVALUATE); 222 } 223 set_skb_present(result); 224 free(result); 225 free(str_err); 226 227 /* Export service */ 228 err = boot_perfmon_export(NULL, export_cb, connect_cb, 229 get_default_waitset(), 230 IDC_EXPORT_FLAGS_DEFAULT); 231 if (err_is_fail(err)) { 232 USER_PANIC_ERR(err, "export failed"); 233 } 234 235 /* Connect */ 236 err = coreset_iterate(set, NULL, iter_connect); 237 if (err_is_fail(err)) { 238 USER_PANIC_ERR(err, "coreset_add failed"); 239 } 240 241 return SYS_ERR_OK; 242} 243