gcc/libchill/waitbuffer.c

298 lines
8.4 KiB
C
Raw Normal View History

/* 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;