OSDN Git Service

* Add library exception clause to the copyright notice for all
[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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 /* As a special exception, if you link this library with other files,
22    some of which are compiled with GCC, to produce an executable,
23    this library does not by itself cause the resulting executable
24    to be covered by the GNU General Public License.
25    This exception does not however invalidate any other reasons why
26    the executable file might be covered by the GNU General Public License.  */
27
28 #include "rtltypes.h"
29 #include "rts.h"
30
31 extern void __cause_ex1 (char *ex, char *file, int lineno);
32
33 EXCEPTION (bufferinconsistency)
34 #define CAUSE_BUFFINCONS  __cause_ex1 ("bufferinconsistency", filename, lineno)
35 EXCEPTION (spacefail);
36 #define CAUSE_SPACEFAIL   __cause_ex1 ("spacefail", filename, lineno)
37     
38 /*
39  * function __wait_buffer
40  *
41  * parameters:
42  *     buf_got     pointer to location for writing the received buffer address
43  *     nbuf        number of buffers in RECEIVE CASE
44  *     bufptr      array of pointers to buffer descriptor
45  *     datap       pointer where to store data
46  *     datalen     length of data
47  *     ins         pointer to instance location or 0
48  *     else_clause else specified or not
49  *     to_loc      pointer to timesupervision value
50  *     filename    source file name where function gets called
51  *     lineno      linenumber in source file
52  *
53  * returns:
54  *     int         0 .. success
55  *                 1 .. timed out
56  *
57  * exceptions:
58  *     bufferinconsistency  if something's wrong in the buffer queue's
59  *     spacefail            out of heap space of datalength of receiver
60  *                          less then data avilable.
61  *
62  * abstract:
63  *     implement the CHILL RECEIVE buffer CASE action.
64  */
65
66 int
67 __wait_buffer (buf_got, nbuf, bufptr, datap, datalen, ins,
68                else_clause, to, filename, lineno)
69      void           **buf_got;
70      int              nbuf;
71      Buffer_Descr    *bufptr[];
72      void            *datap;
73      int              datalen;
74      INSTANCE        *ins;
75      int              else_clause;
76      void            *to;
77      char            *filename;
78      int              lineno;
79 {
80   int i;
81   Buffer_Wait_Queue     *start_list;
82   Buffer_Queue         **retval;
83   Buffer_Queue         **highprio;
84   int                    timed_out;
85   
86   /* look if there is a buffer already sent */
87   highprio = 0;
88   for (i = 0; i < nbuf; i++)
89     {
90       Buffer_Queue      *bq;
91
92       memcpy (&bq, bufptr[i]->buf, sizeof (Buffer_Queue *));
93       if (bq != 0 && bq->sendqueue != 0)
94         {
95           if (highprio != 0)
96             {
97               Buffer_Queue      *bsq = *highprio;
98               
99               if (bq->sendqueue->priority > bsq->sendqueue->priority)
100                 highprio = bufptr[i]->buf;
101             }
102           else
103             highprio = bufptr[i]->buf;
104         }
105     }
106   
107   if (highprio != 0)
108     {
109       Buffer_Queue      *bq;
110
111       memcpy (&bq, highprio, sizeof (Buffer_Queue *));
112       if (bq != 0 && bq->sendqueue != 0)
113         {
114           Buffer_Send_Queue *bsq = bq->sendqueue;
115           Buffer_Send_Queue *tmp;
116
117           /* check data length */
118           if (datalen < bsq->datalen)
119             /* something's totaly wrong. Raise exception */
120             CAUSE_SPACEFAIL;
121
122           /* copy data out */
123           memcpy (datap, bsq->dataptr, bsq->datalen);
124
125           /* update instance, if present */
126           if (ins != 0)
127             memcpy (ins, &bsq->this, sizeof (INSTANCE));
128
129           /* dequeue entry */
130           tmp = bsq;
131           bq->sendqueue = tmp->forward;
132
133           if (tmp->is_delayed)
134             {
135               /* there is an instance delayed on a send,
136                  continue it. */
137               __continue_that (tmp->this, tmp->priority, filename, lineno);
138               FREE (tmp);
139
140               /* return the buffer we have received from */
141               *buf_got = (void *)highprio;
142               return 0;
143             }
144
145           /* just decrease sendqueue length */
146           bq->sendqueuelength--;
147
148           FREE (tmp);
149
150           /* as we got an entry free, we should continue
151              an INSTANCE which is delayed on a send at this
152              buffer */
153           bsq = bq->sendqueue;
154           while (bsq != 0)
155             {
156               if (bsq->is_delayed)
157                 {
158                   bq->sendqueuelength++;
159                   bsq->is_delayed = 0;
160                   __continue_that (bsq->this, bsq->priority, filename, lineno);
161                   break;
162                 }
163               bsq = bsq->forward;
164             }
165           /* return the buffer we have received from */
166           *buf_got = (void *)highprio;
167           return 0;
168         }
169       }
170
171   /* if we come here, there is no buffer already sent */
172   if (else_clause != 0)
173     {
174       /* in that case we return immediately */
175       *buf_got = 0;
176       return 0;
177     }
178   
179   /* now we have to queue ourself to the wait queue(s) */
180   start_list = 0;
181   for (i = 0; i < nbuf; i++)
182     {
183       Buffer_Queue      *bq;
184       Buffer_Wait_Queue *wrk;
185       Buffer_Wait_Queue *bwq;
186       Buffer_Wait_Queue *prev_queue_entry = 0;
187       Buffer_Wait_Queue *prev_list_entry;
188       int                j, have_done = 0;
189       
190       for (j = 0; j < i; j++)
191         {
192           if (bufptr[i]->buf == bufptr[j]->buf)
193             {
194               have_done = 1;
195               break;
196             }
197         }
198       if (have_done)
199         continue;
200       
201       memcpy (&bq, bufptr[i]->buf, sizeof (Buffer_Queue *));
202       if (bq == 0)
203         {
204           MALLOC (bq, sizeof (Buffer_Queue));
205           memset (bq, 0, sizeof (Buffer_Queue));
206           /* *(bufptr[i]->buf) = bq; may be unaligned */
207           memcpy (bufptr[i]->buf, &bq, sizeof (Buffer_Queue *));
208         }
209       MALLOC (wrk, sizeof (Buffer_Wait_Queue));
210       memset (wrk, 0, sizeof (Buffer_Wait_Queue));
211       bwq = (Buffer_Wait_Queue *)&bq->waitqueue;
212       
213       wrk->this = THIS;
214       wrk->datalen = datalen;
215       wrk->dataptr = datap;
216       wrk->bufferaddr = bufptr[i]->buf;
217
218       /* queue it at the end of buffer wait queue */
219       while (bwq->forward != 0)
220           bwq = bwq->forward;
221       wrk->forward = bwq->forward;
222       bwq->forward = wrk;
223       
224       /* queue it into list */
225       wrk->startlist = start_list;
226       if (! start_list)
227         {
228           start_list = wrk;
229           prev_list_entry = wrk;
230           wrk->startlist = start_list;
231         }
232       else
233         {
234           prev_list_entry->chain = wrk;
235           prev_list_entry = wrk;
236         }
237       
238       /* increment wait queue count */
239       bq->waitqueuelength++;
240     }
241
242   /* tell runtime system to delay this process */
243   timed_out = __delay_this (wait_buffer_receive, to, filename, lineno);
244   if (timed_out)
245     {
246       /* remove all entries from buffer queues */
247       Buffer_Wait_Queue *listentry = start_list;
248       
249       while (listentry != 0)
250         {
251           Buffer_Queue *bq = *(listentry->bufferaddr);
252           Buffer_Wait_Queue *prev_entry = (Buffer_Wait_Queue *)&bq->waitqueue;
253           Buffer_Wait_Queue *bwq = bq->waitqueue;
254           
255           while (bwq != listentry)
256             {
257               prev_entry = bwq;
258               bwq = bwq->forward;
259             }
260           /* dequeue it */
261           prev_entry->forward = bwq->forward;
262           bq->waitqueuelength--;
263           listentry = listentry->chain;
264         }
265     }
266   
267   /* someone has continued us, find which buffer got ready */
268   retval = 0;
269
270   while (start_list != 0)
271     {
272       Buffer_Wait_Queue *tmp = start_list->chain;
273       
274       if (start_list->is_sent)
275         {
276           /* this one has been sent */
277           /* save return value */
278           if (retval == 0)
279               retval = start_list->bufferaddr;
280           else
281               /* more then one has been sent, that's wrong */
282               CAUSE_BUFFINCONS;
283           
284           /* update instance, if present */
285           if (ins != 0)
286             memcpy (ins, &start_list->who_sent, sizeof (INSTANCE));
287         }
288       FREE (start_list);
289       start_list = tmp;
290     }
291
292   /* now check if there was really a buffer got */
293   if (retval == 0 && !timed_out)
294     /* something's totally wrong, raise an exception  */
295     CAUSE_BUFFINCONS;
296
297   if (!timed_out)
298     *buf_got = (void *)retval;
299   return timed_out;
300 }
301
302 /* force function __print_buffer to be linked */
303 extern void __print_buffer ();
304 static EntryPoint pev = __print_buffer;