1/** 2 * \file 3 * \brief e1000 continuation management 4 * 5 * This file provides a generic way of managing continuation for messages 6 * of different types 7 */ 8 9/* 10 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich. 11 * All rights reserved. 12 * 13 * This file is distributed under the terms in the attached LICENSE file. 14 * If you do not find this file, copies can be found by writing to: 15 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 16 */ 17 18#ifndef CONTMNG_C_ 19#define CONTMNG_C_ 20 21#include <string.h> 22#include <barrelfish/barrelfish.h> 23 24#include <contmng/contmng.h> 25 26/* QUEUE_DEBUG enables the debug statements 27 * NOTE: This option does not compile for all architecture/machine due to 28 * dependance on disp_name and dispatch.h 29 */ 30//#define QUEUE_DEBUG 1 31 32static void cont_queue_send_next_message(struct cont_queue *q); 33 34 35#ifdef QUEUE_DEBUG 36#include <dispatch.h> 37static void qprintf_mac(struct cont_queue *q, char *msg) 38{ 39 if (q->debug) { 40 printf("CQ: %s [%d:%.*s] [%d] [%d] [%d] qqqqqq\n", 41 msg, disp_get_core_id(), 42 64, q->name, q->head, q->tail, q->running); 43 } 44} 45#define qprintf(x...) qprintf_mac(x) 46 47#else 48#define qprintf(x...) ((void)0) 49#endif /* QUEUE_DEBUG */ 50 51 52//**************************************************************************** 53/************** Generic continuation queue implementation *******************/ 54/* WARN: use only when your responses contains only integers */ 55 56 57/* allocates the memory for continuation queue 58 It includes the memory for MAX_QUEUE_SIZE of elements also */ 59struct cont_queue *create_cont_q(char *name) 60{ 61 struct cont_queue *ptr = NULL; 62 ptr = (struct cont_queue *) malloc(sizeof(struct cont_queue)); 63 if (ptr == NULL) { 64 printf("ERROR: malloc failed in create_cont_q\n"); 65 abort(); 66 /* FIXME: introduce new error and return the error */ 67 } 68 memset(ptr, 0, sizeof(struct cont_queue)); 69 if (name != NULL) { 70 strncpy(ptr->name, name, 63); 71 } 72 return ptr; 73}/* end function: create_cont_q */ 74 75 76 77// Tells how many slots are actually used 78int queue_used_slots(struct cont_queue *q) 79{ 80 uint64_t nhead = q->head % MAX_QUEUE_SIZE; 81 uint64_t ntail = q->tail % MAX_QUEUE_SIZE; 82 if ( nhead >= ntail) { 83 return (nhead - ntail); 84 } else { 85 return (ntail + (MAX_QUEUE_SIZE - nhead)); 86 } 87} // end function: queue_used_slots 88 89 90 91/* Tells if queue has enough space to add more events, 92 * or if the producer should pause for a while */ 93int queue_free_slots(struct cont_queue *q) 94{ 95 96 if (((q->head + 1) % MAX_QUEUE_SIZE) > q->tail) { 97 return (MAX_QUEUE_SIZE - 98 (((q->head + 1) % MAX_QUEUE_SIZE) - q->tail) 99 ); 100 } else { 101 return q->tail - ((q->head + 1) % MAX_QUEUE_SIZE); 102 } 103} // end function 104 105 106int is_enough_space_in_queue(struct cont_queue *q) 107{ 108 if (queue_free_slots(q) > (MAX_QUEUE_SIZE/10)) { 109 return true; 110 } else { 111 return false; 112 } 113} // end function: is_enough_space_in_queue 114 115 116bool can_enqueue_cont_q(struct cont_queue *q) 117{ 118 if (((q->head + 1) % MAX_QUEUE_SIZE) == q->tail) { 119 return false; 120 } else { 121 return true; 122 } 123} // end function: can_enqueue_cont_q 124 125/* Adds element to the queue */ 126void enqueue_cont_q(struct cont_queue *q, struct q_entry *entry) 127{ 128 129 if (((q->head + 1) % MAX_QUEUE_SIZE) == q->tail) 130 { 131 qprintf(q, "ERROR: Queue full"); 132 printf("ERROR: Queue [%s] is full\n", q->name); 133 printf("ERROR: %.*s\n", 64, q->name); 134 printf("ERROR: CQ: head [%d], tail [%d] qqqqqq\n", q->head, q->tail); 135 /* __builtin_return_address is not supported in ARM toolchain */ 136 137#ifdef QUEUE_DEBUG 138 printf("callstack: %p %p %p %p\n", 139 __builtin_return_address(0), 140 __builtin_return_address(1), 141 __builtin_return_address(2), 142 __builtin_return_address(3)); 143#endif // QUEUE_DEBUG 144 145 // Following two lines are there to force the seg-fault of the domain 146 // as abort was showing some strange behaviour 147// int *p = NULL; 148// *p = 43; 149 abort(); 150// return CONT_ERR_NO_MORE_SLOTS; 151 } 152 153 /* Copying the structure */ 154 q->qelist[q->head].binding_ptr = entry->binding_ptr; 155 q->qelist[q->head].cap = entry->cap; 156 q->qelist[q->head].handler = entry->handler; 157 q->qelist[q->head].state = 0; 158 q->qelist[q->head].fname = entry->fname; 159 160 for(int i = 0; i < MAX_PARAMS; ++i) { 161 q->qelist[q->head].plist[i] = entry->plist[i]; 162 } 163 164 q->head = (q->head + 1) % MAX_QUEUE_SIZE; 165 166 // If no continuations are running, then execute this one directly 167 if (((q->tail + 1) % MAX_QUEUE_SIZE) == q->head) { 168// if (q->running == 0) { 169 q->running = 1; 170 qprintf(q, "directly-sending"); 171 cont_queue_send_next_message(q); 172 } 173 174 //otherwise continuation function will trigger sending next queue element 175} // end function: enqueue_cont_q 176 177 178// called from continuation registered with flounder 179// WARN: should not be called directly 180void cont_queue_callback(void *arg) 181{ 182 struct cont_queue *q = (struct cont_queue *)arg; 183 184 q->tail = (q->tail + 1) % MAX_QUEUE_SIZE; 185 qprintf(q, "from-continuation"); 186 cont_queue_send_next_message(q); 187} /* end function: cont_queue_callback */ 188 189 190/* Sends the top of queue msg 191 NOTE: this function does not increment the tail. It calls handler, 192 which registers "cont_queue_callback" as callback with flounder, 193 and that callback function increments the tail!!! 194 complicated? huh.. :-P */ 195void cont_queue_send_next_message(struct cont_queue *q) 196{ 197// qprintf(q, "sending-msg"); 198 199 if(q->head == q->tail){ 200 q->running = 0; 201 qprintf(q, "Queue-empty-Recursion-End!!"); 202 return; 203 } 204 errval_t err = q->qelist[q->tail].handler(q->qelist[q->tail]); 205 if (err_is_fail(err)) { 206 if (err == FLOUNDER_ERR_TX_BUSY ) { 207 qprintf(q, "sending:FLO-BUSY"); 208 } else { 209 qprintf(q, "sending:FLO FAIL"); 210 USER_PANIC_ERR(err, "cont_queue_send_next_message "); 211 } 212 } 213 qprintf(q, "sending-msg done: "); 214} /* end function: cont_queue_send_next_message */ 215 216void cont_queue_show_queue(struct cont_queue *q) 217{ 218 219 int len = 0; 220 len = q->head - q->tail; 221 printf("queue [%s] len [%d]==> head [%d] - tail [%d]\n", 222 q->name, len, q->head, q->tail); 223 224 /* 225 int i = 0; 226 int idx = 0; 227 idx = q->tail; 228 while (idx != q->head){ 229 printf("elem %d: [%s], state %u\n", idx, q->qelist[idx].fname, 230 q->qelist[idx].history); 231 idx = (idx + 1) % MAX_QUEUE_SIZE; 232 } 233 234 printf("Showing elements which are already sent!!\n"); 235 idx = q->tail; 236 for (i = 0; i < 10; ++i){ 237 idx = (idx - 1); 238 if (idx < 0) { 239 idx = MAX_QUEUE_SIZE - 1; 240 } 241 printf("elem %d: [%s], state %d\n", idx, q->qelist[idx].fname, 242 q->qelist[idx].history); 243 } 244 */ 245 246} // end function: cont_queue_show_queue 247 248 249/* Following function has nothing to do with cont_queue_management, 250 * and is to be used for debugging. Ideally this function should not exist. */ 251void show_binary_blob (void *data, int len) 252{ 253 printf("\nBlob_%d[", len); 254 uint8_t *ptr = data; 255 for (int i = 0 ; i < len; ++i){ 256 printf("0x%x,", ptr[i]); 257 } 258 printf("]\n"); 259} 260 261#endif // CONTMNG_C_ 262