OSDN Git Service

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