]>
Commit | Line | Data |
---|---|---|
b79f73df JL |
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 | |
201853b4 JL |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, |
20 | Boston, MA 02111-1307, USA. */ | |
b79f73df | 21 | |
502b941f JL |
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 | ||
b79f73df JL |
29 | #include "rtltypes.h" |
30 | #include "rts.h" | |
31 | ||
32 | extern void __cause_ex1 (char *ex, char *file, int lineno); | |
33 | ||
34 | EXCEPTION (bufferinconsistency) | |
35 | #define CAUSE_BUFFINCONS __cause_ex1 ("bufferinconsistency", filename, lineno) | |
36 | EXCEPTION (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 | ||
67 | int | |
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 */ | |
304 | extern void __print_buffer (); | |
305 | static EntryPoint pev = __print_buffer; |