1/* Implement tasking-related runtime actions for CHILL. 2 Copyright (C) 1992,1993 Free Software Foundation, Inc. 3 Author: Wilfried Moser 4 5This file is part of GNU CC. 6 7GNU CC is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2, or (at your option) 10any later version. 11 12GNU CC is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with GNU CC; see the file COPYING. If not, write to 19the Free Software Foundation, 59 Temple Place - Suite 330, 20Boston, MA 02111-1307, USA. */ 21 22/* As a special exception, if you link this library with other files, 23 some of which are compiled with GCC, to produce an executable, 24 this library does not by itself cause the resulting executable 25 to be covered by the GNU General Public License. 26 This exception does not however invalidate any other reasons why 27 the executable file might be covered by the GNU General Public License. */ 28 29#include "rtltypes.h" 30#include "rts.h" 31 32extern void __cause_ex1 (char *ex, char *file, int lineno); 33 34EXCEPTION (bufferinconsistency) 35#define CAUSE_BUFFINCONS __cause_ex1 ("bufferinconsistency", filename, lineno) 36EXCEPTION (spacefail); 37#define CAUSE_SPACEFAIL __cause_ex1 ("spacefail", filename, lineno) 38 39/* 40 * function __wait_buffer 41 * 42 * parameters: 43 * buf_got pointer to location for writing the received buffer address 44 * nbuf number of buffers in RECEIVE CASE 45 * bufptr array of pointers to buffer descriptor 46 * datap pointer where to store data 47 * datalen length of data 48 * ins pointer to instance location or 0 49 * else_clause else specified or not 50 * to_loc pointer to timesupervision value 51 * filename source file name where function gets called 52 * lineno linenumber in source file 53 * 54 * returns: 55 * int 0 .. success 56 * 1 .. timed out 57 * 58 * exceptions: 59 * bufferinconsistency if something's wrong in the buffer queue's 60 * spacefail out of heap space of datalength of receiver 61 * less then data avilable. 62 * 63 * abstract: 64 * implement the CHILL RECEIVE buffer CASE action. 65 */ 66 67int 68__wait_buffer (buf_got, nbuf, bufptr, datap, datalen, ins, 69 else_clause, to, filename, lineno) 70 void **buf_got; 71 int nbuf; 72 Buffer_Descr *bufptr[]; 73 void *datap; 74 int datalen; 75 INSTANCE *ins; 76 int else_clause; 77 void *to; 78 char *filename; 79 int lineno; 80{ 81 int i; 82 Buffer_Wait_Queue *start_list; 83 Buffer_Queue **retval; 84 Buffer_Queue **highprio; 85 int timed_out; 86 87 /* look if there is a buffer already sent */ 88 highprio = 0; 89 for (i = 0; i < nbuf; i++) 90 { 91 Buffer_Queue *bq; 92 93 memcpy (&bq, bufptr[i]->buf, sizeof (Buffer_Queue *)); 94 if (bq != 0 && bq->sendqueue != 0) 95 { 96 if (highprio != 0) 97 { 98 Buffer_Queue *bsq = *highprio; 99 100 if (bq->sendqueue->priority > bsq->sendqueue->priority) 101 highprio = bufptr[i]->buf; 102 } 103 else 104 highprio = bufptr[i]->buf; 105 } 106 } 107 108 if (highprio != 0) 109 { 110 Buffer_Queue *bq; 111 112 memcpy (&bq, highprio, sizeof (Buffer_Queue *)); 113 if (bq != 0 && bq->sendqueue != 0) 114 { 115 Buffer_Send_Queue *bsq = bq->sendqueue; 116 Buffer_Send_Queue *tmp; 117 118 /* check data length */ 119 if (datalen < bsq->datalen) 120 /* something's totaly wrong. Raise exception */ 121 CAUSE_SPACEFAIL; 122 123 /* copy data out */ 124 memcpy (datap, bsq->dataptr, bsq->datalen); 125 126 /* update instance, if present */ 127 if (ins != 0) 128 memcpy (ins, &bsq->this, sizeof (INSTANCE)); 129 130 /* dequeue entry */ 131 tmp = bsq; 132 bq->sendqueue = tmp->forward; 133 134 if (tmp->is_delayed) 135 { 136 /* there is an instance delayed on a send, 137 continue it. */ 138 __continue_that (tmp->this, tmp->priority, filename, lineno); 139 FREE (tmp); 140 141 /* return the buffer we have received from */ 142 *buf_got = (void *)highprio; 143 return 0; 144 } 145 146 /* just decrease sendqueue length */ 147 bq->sendqueuelength--; 148 149 FREE (tmp); 150 151 /* as we got an entry free, we should continue 152 an INSTANCE which is delayed on a send at this 153 buffer */ 154 bsq = bq->sendqueue; 155 while (bsq != 0) 156 { 157 if (bsq->is_delayed) 158 { 159 bq->sendqueuelength++; 160 bsq->is_delayed = 0; 161 __continue_that (bsq->this, bsq->priority, filename, lineno); 162 break; 163 } 164 bsq = bsq->forward; 165 } 166 /* return the buffer we have received from */ 167 *buf_got = (void *)highprio; 168 return 0; 169 } 170 } 171 172 /* if we come here, there is no buffer already sent */ 173 if (else_clause != 0) 174 { 175 /* in that case we return immediately */ 176 *buf_got = 0; 177 return 0; 178 } 179 180 /* now we have to queue ourself to the wait queue(s) */ 181 start_list = 0; 182 for (i = 0; i < nbuf; i++) 183 { 184 Buffer_Queue *bq; 185 Buffer_Wait_Queue *wrk; 186 Buffer_Wait_Queue *bwq; 187 Buffer_Wait_Queue *prev_queue_entry = 0; 188 Buffer_Wait_Queue *prev_list_entry; 189 int j, have_done = 0; 190 191 for (j = 0; j < i; j++) 192 { 193 if (bufptr[i]->buf == bufptr[j]->buf) 194 { 195 have_done = 1; 196 break; 197 } 198 } 199 if (have_done) 200 continue; 201 202 memcpy (&bq, bufptr[i]->buf, sizeof (Buffer_Queue *)); 203 if (bq == 0) 204 { 205 MALLOC (bq, sizeof (Buffer_Queue)); 206 memset (bq, 0, sizeof (Buffer_Queue)); 207 /* *(bufptr[i]->buf) = bq; may be unaligned */ 208 memcpy (bufptr[i]->buf, &bq, sizeof (Buffer_Queue *)); 209 } 210 MALLOC (wrk, sizeof (Buffer_Wait_Queue)); 211 memset (wrk, 0, sizeof (Buffer_Wait_Queue)); 212 bwq = (Buffer_Wait_Queue *)&bq->waitqueue; 213 214 wrk->this = THIS; 215 wrk->datalen = datalen; 216 wrk->dataptr = datap; 217 wrk->bufferaddr = bufptr[i]->buf; 218 219 /* queue it at the end of buffer wait queue */ 220 while (bwq->forward != 0) 221 bwq = bwq->forward; 222 wrk->forward = bwq->forward; 223 bwq->forward = wrk; 224 225 /* queue it into list */ 226 wrk->startlist = start_list; 227 if (! start_list) 228 { 229 start_list = wrk; 230 prev_list_entry = wrk; 231 wrk->startlist = start_list; 232 } 233 else 234 { 235 prev_list_entry->chain = wrk; 236 prev_list_entry = wrk; 237 } 238 239 /* increment wait queue count */ 240 bq->waitqueuelength++; 241 } 242 243 /* tell runtime system to delay this process */ 244 timed_out = __delay_this (wait_buffer_receive, to, filename, lineno); 245 if (timed_out) 246 { 247 /* remove all entries from buffer queues */ 248 Buffer_Wait_Queue *listentry = start_list; 249 250 while (listentry != 0) 251 { 252 Buffer_Queue *bq = *(listentry->bufferaddr); 253 Buffer_Wait_Queue *prev_entry = (Buffer_Wait_Queue *)&bq->waitqueue; 254 Buffer_Wait_Queue *bwq = bq->waitqueue; 255 256 while (bwq != listentry) 257 { 258 prev_entry = bwq; 259 bwq = bwq->forward; 260 } 261 /* dequeue it */ 262 prev_entry->forward = bwq->forward; 263 bq->waitqueuelength--; 264 listentry = listentry->chain; 265 } 266 } 267 268 /* someone has continued us, find which buffer got ready */ 269 retval = 0; 270 271 while (start_list != 0) 272 { 273 Buffer_Wait_Queue *tmp = start_list->chain; 274 275 if (start_list->is_sent) 276 { 277 /* this one has been sent */ 278 /* save return value */ 279 if (retval == 0) 280 retval = start_list->bufferaddr; 281 else 282 /* more then one has been sent, that's wrong */ 283 CAUSE_BUFFINCONS; 284 285 /* update instance, if present */ 286 if (ins != 0) 287 memcpy (ins, &start_list->who_sent, sizeof (INSTANCE)); 288 } 289 FREE (start_list); 290 start_list = tmp; 291 } 292 293 /* now check if there was really a buffer got */ 294 if (retval == 0 && !timed_out) 295 /* something's totally wrong, raise an exception */ 296 CAUSE_BUFFINCONS; 297 298 if (!timed_out) 299 *buf_got = (void *)retval; 300 return timed_out; 301} 302 303/* force function __print_buffer to be linked */ 304extern void __print_buffer (); 305static EntryPoint pev = __print_buffer; 306