298 lines
8.4 KiB
C
298 lines
8.4 KiB
C
|
/* 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;
|