1/** 2 * \file 3 * \brief Queue for stack-ripped inter-monitor code 4 */ 5 6/* 7 * Copyright (c) 2009, 2010, 2011, ETH Zurich. 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 <monitor.h> 16 17/** 18 * \brief Enqueue on a waitset queue. 19 * 20 * \param qs Pointer to queue to enqueue on 21 * \param ms Pointer to element to enqueue 22 * 23 * \return true if queue was empty, false if not. 24 */ 25static bool enqueue_send(struct msg_queue *q, struct msg_queue_elem *m) 26{ 27 assert(m->next == NULL); 28 29 // Enqueue on the queue 30 if(q->tail != NULL) { 31 q->tail->next = m; 32 } else { 33 assert(q->head == NULL); 34 q->head = m; 35 } 36 q->tail = m; 37 38 return q->head == q->tail ? true : false; 39} 40 41/** 42 * \brief Enqueue an element on a waitset queue IN FRONT. 43 * 44 * \param qs Pointer to queue to enqueue on 45 * \param ms Pointer to element to enqueue 46 * 47 * \return true if queue was empty, false if not. 48 */ 49static bool enqueue_send_at_front(struct msg_queue *q, struct msg_queue_elem *m) 50{ 51 assert(m->next == NULL); 52 if(q->tail == NULL) { 53 assert(q->head == NULL); 54 q->head = m; 55 q->tail = m; 56 } else { 57 m->next = q->head; 58 q->head = m; 59 } 60 return q->head == q->tail ? true : false; 61} 62 63static struct msg_queue_elem *dequeue_send(struct msg_queue *q) 64{ 65 // Queue should have at least one element 66 assert(q->head != NULL && q->tail != NULL); 67 68 struct msg_queue_elem *e = q->head; 69 q->head = e->next; 70 if(q->head == NULL) { 71 q->tail = NULL; 72 } 73 74 return e; 75} 76 77static void intermon_send_handler(void *arg) 78{ 79 struct intermon_binding *b = arg; 80 struct intermon_state *is = b->st; 81 struct msg_queue *mq = &is->queue; 82 83 // Dequeue next element from the queue 84 struct intermon_msg_queue_elem *e = 85 (struct intermon_msg_queue_elem *)dequeue_send(mq); 86 87 // If the queue is non-empty, re-register 88 if (!msg_queue_is_empty(mq)) { 89 struct waitset *ws = get_default_waitset(); // XXX: store this on the q? 90 errval_t err = b->register_send(b, ws, MKCONT(intermon_send_handler,b)); 91 assert(err_is_ok(err)); 92 } 93 94 assert(e->cont != NULL); 95 e->cont(b, e); 96} 97 98errval_t intermon_enqueue_send(struct intermon_binding *b, struct msg_queue *q, 99 struct waitset *ws, struct msg_queue_elem *ms) 100{ 101 ms->next = NULL; 102 103 // If queue was empty, enqueue on waitset 104 if(enqueue_send(q, ms)) { 105 return b->register_send(b, ws, MKCONT(intermon_send_handler,b)); 106 } else { 107 return SYS_ERR_OK; 108 } 109} 110 111errval_t intermon_enqueue_send_at_front(struct intermon_binding *b, struct msg_queue *q, 112 struct waitset *ws, struct msg_queue_elem *ms) 113{ 114 ms->next = NULL; 115 116 // If queue was empty, enqueue on waitset 117 if(enqueue_send_at_front(q, ms)) { 118 return b->register_send(b, ws, MKCONT(intermon_send_handler,b)); 119 } else { 120 return SYS_ERR_OK; 121 } 122} 123 124static void monitor_send_handler(void *arg) 125{ 126 struct monitor_binding *b = arg; 127 struct monitor_state *is = b->st; 128 struct msg_queue *mq = &is->queue; 129 130 // Dequeue next element from the queue 131 struct monitor_msg_queue_elem *e = 132 (struct monitor_msg_queue_elem *)dequeue_send(mq); 133 134 // If the queue is non-empty, re-register 135 if (!msg_queue_is_empty(mq)) { 136 struct waitset *ws = get_default_waitset(); // XXX: store this on the q? 137 errval_t err = b->register_send(b, ws, MKCONT(monitor_send_handler,b)); 138 assert(err_is_ok(err)); 139 } 140 141 assert(e->cont != NULL); 142 e->cont(b, e); 143} 144 145errval_t monitor_enqueue_send(struct monitor_binding *b, struct msg_queue *q, 146 struct waitset *ws, struct msg_queue_elem *ms) 147{ 148 ms->next = NULL; 149 150 // If queue was empty, enqueue on waitset 151 if(enqueue_send(q, ms)) { 152 return b->register_send(b, ws, MKCONT(monitor_send_handler,b)); 153 } else { 154 return SYS_ERR_OK; 155 } 156} 157 158errval_t monitor_enqueue_send_at_front(struct monitor_binding *b, struct msg_queue *q, 159 struct waitset *ws, struct msg_queue_elem *ms) 160{ 161 ms->next = NULL; 162 163 // If queue was empty, enqueue on waitset 164 if(enqueue_send_at_front(q, ms)) { 165 return b->register_send(b, ws, MKCONT(monitor_send_handler,b)); 166 } else { 167 return SYS_ERR_OK; 168 } 169} 170 171/// Common send continuation function to destroy a cap that has been sent 172/// NB: Not part of the queue functionality 173void destroy_outgoing_cap(void *arg) 174{ 175 DEBUG_CAPOPS("cleaning up outgoing cap\n"); 176 struct capref *cap = arg; 177 assert(cap != NULL); 178 assert(!capref_is_null(*cap)); 179 180 DEBUG_CAPOPS("cleaning up outgoing cap: cap_destroy\n"); 181 errval_t err = cap_destroy(*cap); 182 if (err_is_fail(err)) { 183 if(err_no(err) != SYS_ERR_CAP_NOT_FOUND) { 184 DEBUG_ERR(err, "cap_destroy failed"); 185 } 186 } 187 188 DEBUG_CAPOPS("cleaning up outgoing cap: free\n"); 189 free(cap); 190} 191 192/// Returns a copy of the given capref in a malloc'ed buffer 193struct capref *caprefdup(struct capref cap) 194{ 195 struct capref *p = malloc(sizeof(struct capref)); 196 assert(p != NULL); 197 *p = cap; 198 return p; 199} 200