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