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