1/* 2 * \brief Spawnd state 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 14#include "spawnd_state.h" 15 16static struct spawnd_state *spawnds[MAX_COREID]; 17 18/** 19 * \brief Allocates a state structure for a new spawnd binding. 20 * 21 * \param core_id core where the spawnd newly bound with runs. 22 * \param spawn_binding Flounder binding structure for the spawnd. 23 */ 24errval_t spawnd_state_alloc(coreid_t core_id, struct spawn_binding *b) 25{ 26 spawnds[core_id] = (struct spawnd_state*) malloc( 27 sizeof(struct spawnd_state)); 28 if (spawnds[core_id] == NULL) { 29 return LIB_ERR_MALLOC_FAIL; 30 } 31 32 spawnds[core_id]->b = b; 33 spawnds[core_id]->core_id = core_id; 34 spawnds[core_id]->sendq.head = NULL; 35 spawnds[core_id]->sendq.tail = NULL; 36 spawnds[core_id]->recvq.head = NULL; 37 spawnds[core_id]->recvq.tail = NULL; 38 39 b->st = spawnds[core_id]; 40 41 return SYS_ERR_OK; 42} 43 44/** 45 * \brief Returns whether connected to spawnd on the given core. 46 */ 47inline bool spawnd_state_exists(coreid_t core_id) 48{ 49 return spawnds[core_id] != NULL; 50} 51 52/** 53 * \brief Returns the state element for the spawnd on the given core. 54 */ 55inline struct spawnd_state *spawnd_state_get(coreid_t core_id) 56{ 57 return spawnds[core_id]; 58} 59 60/** 61 * \brief Enqueue on a waitset queue. 62 * 63 * \param q Pointer to queue to enqueue on 64 * \param m Pointer to element to enqueue 65 * 66 * \return true if queue was empty, false if not. 67 */ 68static bool enqueue(struct msg_queue *q, struct msg_queue_elem *m) 69{ 70 assert(m->next == NULL); 71 72 // Enqueue on the queue 73 if(q->tail != NULL) { 74 q->tail->next = m; 75 } else { 76 assert(q->head == NULL); 77 q->head = m; 78 } 79 q->tail = m; 80 81 return q->head == q->tail ? true : false; 82} 83 84/** 85 * \brief Dequeues from a waitset queue. 86 * 87 * \param q Pointer to queue to dequeue from 88 * 89 * \return the newly dequeued element. 90 */ 91static struct msg_queue_elem *dequeue(struct msg_queue *q) 92{ 93 // Queue should have at least one element 94 assert(q->head != NULL && q->tail != NULL); 95 96 struct msg_queue_elem *e = q->head; 97 q->head = e->next; 98 if(q->head == NULL) { 99 q->tail = NULL; 100 } 101 102 return e; 103} 104 105/** 106 * \brief Enqueue an element on a waitset queue IN FRONT. 107 * 108 * \param q Pointer to queue to enqueue on 109 * \param m Pointer to element to enqueue 110 * 111 * \return true if queue was empty, false if not. 112 */ 113static bool enqueue_at_front(struct msg_queue *q, struct msg_queue_elem *m) 114{ 115 assert(m->next == NULL); 116 if(q->tail == NULL) { 117 assert(q->head == NULL); 118 q->head = m; 119 q->tail = m; 120 } else { 121 m->next = q->head; 122 q->head = m; 123 } 124 return q->head == q->tail ? true : false; 125} 126 127/** 128 * \brief Event-based handler for sending requests to spawnd. 129 * 130 * This function pops the next request from the send queue of the targeted 131 * spawnd (wrapped inside arg). It attempts to send the request, re-enqueuing 132 * it at front if sending fails. It then re-registers a new send if the queue 133 * still has pending requests. 134 * 135 * \param arg Wrapper over the spawnd_state structure for the target spawnd. 136 */ 137static void spawnd_send_handler(void *arg) 138{ 139 struct spawnd_state *spawnd = (struct spawnd_state*) arg; 140 struct msg_queue *q = &spawnd->sendq; 141 142 // Dequeue next element from the queue 143 struct msg_queue_elem *m = (struct msg_queue_elem*) dequeue(q); 144 145 assert(m->cont != NULL); 146 if (m->cont(m)) { 147 // Send continuation succeeded, need to enqueue a receive. 148 struct msg_queue_elem *recvm = (struct msg_queue_elem*) malloc( 149 sizeof(struct msg_queue_elem)); 150 recvm->st = m->st; 151 recvm->next = NULL; 152 enqueue(&spawnd->recvq, recvm); 153 } else { 154 // Send continuation failed, need to re-enqueue message. 155 enqueue_at_front(q, m); 156 } 157 158 if (q->head != NULL) { 159 // Queue is non-empty, therefore re-register. 160 errval_t err = spawnd->b->register_send(spawnd->b, spawnd->b->waitset, 161 MKCONT(spawnd_send_handler, 162 arg)); 163 if (err_is_fail(err)) { 164 DEBUG_ERR(err, "regitering for spawnd send"); 165 return; 166 } 167 } 168} 169 170/** 171 * \brief Enqueues a new send request event. 172 * 173 * \param spawnd target spawnd to send the request to. 174 * \param msg request to enqueue. 175 */ 176errval_t spawnd_state_enqueue_send(struct spawnd_state *spawnd, 177 struct msg_queue_elem *msg) 178{ 179 msg->next = NULL; 180 181 // If queue was empty, enqueue on waitset 182 if(enqueue(&spawnd->sendq, msg)) { 183 return spawnd->b->register_send(spawnd->b, spawnd->b->waitset, 184 MKCONT(spawnd_send_handler, spawnd)); 185 } else { 186 return SYS_ERR_OK; 187 } 188} 189 190/** 191 * \brief Dequeues and returns the next message in a receive queue. 192 * 193 * \param spawnd spawnd instance whose receive queue to pop. 194 */ 195void *spawnd_state_dequeue_recv(struct spawnd_state *spawnd) 196{ 197 struct msg_queue_elem *m = dequeue(&spawnd->recvq); 198 assert(m != NULL); 199 return m->st; 200}