/* Implement tasking-related runtime actions for CHILL. Copyright (C) 1992,1993 Free Software Foundation, Inc. Author: Wilfried Moser This file is part of GNU CC. GNU CC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "rtltypes.h" #include "rts.h" extern void __cause_ex1 (char *ex, char *file, int lineno); EXCEPTION (bufferinconsistency) #define CAUSE_BUFFINCONS __cause_ex1 ("bufferinconsistency", filename, lineno) EXCEPTION (spacefail); #define CAUSE_SPACEFAIL __cause_ex1 ("spacefail", filename, lineno) /* * function __wait_buffer * * parameters: * buf_got pointer to location for writing the received buffer address * nbuf number of buffers in RECEIVE CASE * bufptr array of pointers to buffer descriptor * datap pointer where to store data * datalen length of data * ins pointer to instance location or 0 * else_clause else specified or not * to_loc pointer to timesupervision value * filename source file name where function gets called * lineno linenumber in source file * * returns: * int 0 .. success * 1 .. timed out * * exceptions: * bufferinconsistency if something's wrong in the buffer queue's * spacefail out of heap space of datalength of receiver * less then data avilable. * * abstract: * implement the CHILL RECEIVE buffer CASE action. */ int __wait_buffer (buf_got, nbuf, bufptr, datap, datalen, ins, else_clause, to, filename, lineno) void **buf_got; int nbuf; Buffer_Descr *bufptr[]; void *datap; int datalen; INSTANCE *ins; int else_clause; void *to; char *filename; int lineno; { int i; Buffer_Wait_Queue *start_list; Buffer_Queue **retval; Buffer_Queue **highprio; int timed_out; /* look if there is a buffer already sent */ highprio = 0; for (i = 0; i < nbuf; i++) { Buffer_Queue *bq; memcpy (&bq, bufptr[i]->buf, sizeof (Buffer_Queue *)); if (bq != 0 && bq->sendqueue != 0) { if (highprio != 0) { Buffer_Queue *bsq = *highprio; if (bq->sendqueue->priority > bsq->sendqueue->priority) highprio = bufptr[i]->buf; } else highprio = bufptr[i]->buf; } } if (highprio != 0) { Buffer_Queue *bq; memcpy (&bq, highprio, sizeof (Buffer_Queue *)); if (bq != 0 && bq->sendqueue != 0) { Buffer_Send_Queue *bsq = bq->sendqueue; Buffer_Send_Queue *tmp; /* check data length */ if (datalen < bsq->datalen) /* something's totaly wrong. Raise exception */ CAUSE_SPACEFAIL; /* copy data out */ memcpy (datap, bsq->dataptr, bsq->datalen); /* update instance, if present */ if (ins != 0) memcpy (ins, &bsq->this, sizeof (INSTANCE)); /* dequeue entry */ tmp = bsq; bq->sendqueue = tmp->forward; if (tmp->is_delayed) { /* there is an instance delayed on a send, continue it. */ __continue_that (tmp->this, tmp->priority, filename, lineno); FREE (tmp); /* return the buffer we have received from */ *buf_got = (void *)highprio; return 0; } /* just decrease sendqueue length */ bq->sendqueuelength--; FREE (tmp); /* as we got an entry free, we should continue an INSTANCE which is delayed on a send at this buffer */ bsq = bq->sendqueue; while (bsq != 0) { if (bsq->is_delayed) { bq->sendqueuelength++; bsq->is_delayed = 0; __continue_that (bsq->this, bsq->priority, filename, lineno); break; } bsq = bsq->forward; } /* return the buffer we have received from */ *buf_got = (void *)highprio; return 0; } } /* if we come here, there is no buffer already sent */ if (else_clause != 0) { /* in that case we return immediately */ *buf_got = 0; return 0; } /* now we have to queue ourself to the wait queue(s) */ start_list = 0; for (i = 0; i < nbuf; i++) { Buffer_Queue *bq; Buffer_Wait_Queue *wrk; Buffer_Wait_Queue *bwq; Buffer_Wait_Queue *prev_queue_entry = 0; Buffer_Wait_Queue *prev_list_entry; int j, have_done = 0; for (j = 0; j < i; j++) { if (bufptr[i]->buf == bufptr[j]->buf) { have_done = 1; break; } } if (have_done) continue; memcpy (&bq, bufptr[i]->buf, sizeof (Buffer_Queue *)); if (bq == 0) { MALLOC (bq, sizeof (Buffer_Queue)); memset (bq, 0, sizeof (Buffer_Queue)); /* *(bufptr[i]->buf) = bq; may be unaligned */ memcpy (bufptr[i]->buf, &bq, sizeof (Buffer_Queue *)); } MALLOC (wrk, sizeof (Buffer_Wait_Queue)); memset (wrk, 0, sizeof (Buffer_Wait_Queue)); bwq = (Buffer_Wait_Queue *)&bq->waitqueue; wrk->this = THIS; wrk->datalen = datalen; wrk->dataptr = datap; wrk->bufferaddr = bufptr[i]->buf; /* queue it at the end of buffer wait queue */ while (bwq->forward != 0) bwq = bwq->forward; wrk->forward = bwq->forward; bwq->forward = wrk; /* queue it into list */ wrk->startlist = start_list; if (! start_list) { start_list = wrk; prev_list_entry = wrk; wrk->startlist = start_list; } else { prev_list_entry->chain = wrk; prev_list_entry = wrk; } /* increment wait queue count */ bq->waitqueuelength++; } /* tell runtime system to delay this process */ timed_out = __delay_this (wait_buffer_receive, to, filename, lineno); if (timed_out) { /* remove all entries from buffer queues */ Buffer_Wait_Queue *listentry = start_list; while (listentry != 0) { Buffer_Queue *bq = *(listentry->bufferaddr); Buffer_Wait_Queue *prev_entry = (Buffer_Wait_Queue *)&bq->waitqueue; Buffer_Wait_Queue *bwq = bq->waitqueue; while (bwq != listentry) { prev_entry = bwq; bwq = bwq->forward; } /* dequeue it */ prev_entry->forward = bwq->forward; bq->waitqueuelength--; listentry = listentry->chain; } } /* someone has continued us, find which buffer got ready */ retval = 0; while (start_list != 0) { Buffer_Wait_Queue *tmp = start_list->chain; if (start_list->is_sent) { /* this one has been sent */ /* save return value */ if (retval == 0) retval = start_list->bufferaddr; else /* more then one has been sent, that's wrong */ CAUSE_BUFFINCONS; /* update instance, if present */ if (ins != 0) memcpy (ins, &start_list->who_sent, sizeof (INSTANCE)); } FREE (start_list); start_list = tmp; } /* now check if there was really a buffer got */ if (retval == 0 && !timed_out) /* something's totally wrong, raise an exception */ CAUSE_BUFFINCONS; if (!timed_out) *buf_got = (void *)retval; return timed_out; } /* force function __print_buffer to be linked */ extern void __print_buffer (); static EntryPoint pev = __print_buffer;