]>
Commit | Line | Data |
---|---|---|
b79f73df JL |
1 | /* GNU CHILL compiler regression test file |
2 | Copyright (C) 1992, 1993 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GNU CC. | |
5 | ||
6 | GNU CC is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GNU CC is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU CC; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | ||
502b941f JL |
20 | /* As a special exception, if you link this library with other files, |
21 | some of which are compiled with GCC, to produce an executable, | |
22 | this library does not by itself cause the resulting executable | |
23 | to be covered by the GNU General Public License. | |
24 | This exception does not however invalidate any other reasons why | |
25 | the executable file might be covered by the GNU General Public License. */ | |
26 | ||
b79f73df JL |
27 | #include <stdio.h> |
28 | #include <string.h> | |
29 | #include <stdlib.h> | |
30 | #include <setjmp.h> | |
31 | #include <signal.h> | |
32 | ||
33 | #include "rts.h" | |
34 | ||
35 | ||
36 | /* some allocation/reallocation functions */ | |
37 | ||
38 | static void * | |
39 | xmalloc (size) | |
40 | int size; | |
41 | { | |
42 | void *tmp = malloc (size); | |
43 | ||
44 | if (!tmp) | |
45 | { | |
46 | fprintf (stderr, "Out of heap space.\n"); | |
47 | exit (1); | |
48 | } | |
49 | return (tmp); | |
50 | } | |
51 | ||
52 | static void * | |
53 | xrealloc (ptr, size) | |
54 | void *ptr; | |
55 | int size; | |
56 | { | |
57 | void *tmp = realloc (ptr, size); | |
58 | ||
59 | if (!tmp) | |
60 | { | |
61 | fprintf (stderr, "Out of heap space.\n"); | |
62 | exit (1); | |
63 | } | |
64 | return (tmp); | |
65 | } | |
66 | ||
67 | /* the necessary data */ | |
68 | #define MAX_NUMBER 100 | |
69 | typedef char UsedValues[MAX_NUMBER]; | |
70 | ||
71 | #define MAX_COPIES 100 | |
72 | ||
73 | #define MAX_PER_ITEM 20 | |
74 | typedef struct TASKINGSTRUCTLIST | |
75 | { | |
76 | struct TASKINGSTRUCTLIST *forward; | |
77 | int num; | |
78 | TaskingStruct *data[MAX_PER_ITEM]; | |
79 | char copies[MAX_COPIES]; | |
80 | jmp_buf where; | |
81 | } TaskingStructList; | |
82 | ||
83 | static TaskingStructList *task_array[LAST_AND_UNUSED]; | |
84 | static UsedValues used_values[LAST_AND_UNUSED]; | |
85 | ||
86 | static short | |
87 | get_next_free_number (vals) | |
88 | UsedValues vals; | |
89 | { | |
90 | short i; | |
91 | for (i = 1; i < MAX_NUMBER; i++) | |
92 | { | |
93 | if (!vals[i]) | |
94 | { | |
95 | vals[i] = 1; | |
96 | return (i); | |
97 | } | |
98 | } | |
99 | fprintf (stderr, "There are no more free numbers.\n"); | |
100 | exit (1); | |
101 | } | |
102 | ||
103 | /* function search for the next available copy number */ | |
104 | static short | |
105 | get_next_copy_number (p) | |
106 | TaskingStructList *p; | |
107 | { | |
108 | short i; | |
109 | ||
110 | for (i = 0; i < MAX_COPIES; i++) | |
111 | { | |
112 | if (!p->copies[i]) | |
113 | { | |
114 | p->copies[i] = 1; | |
115 | return (i); | |
116 | } | |
117 | } | |
118 | fprintf (stderr, "No more copies available for \"%s\".\n", | |
119 | p->data[0]->name); | |
120 | exit (1); | |
121 | } | |
122 | ||
123 | /* function registers a tasking entry from a module and assign | |
124 | a value to the type */ | |
125 | ||
126 | void | |
127 | __register_tasking (t) | |
128 | TaskingStruct *t; | |
129 | { | |
130 | TaskingStructList *p; | |
131 | ||
132 | /* check first if a value was provided and if it is in range */ | |
133 | if (t->value_defined && *t->value >= MAX_NUMBER) | |
134 | { | |
135 | fprintf (stderr, "Value %d out of range.\n", *t->value); | |
136 | exit (1); | |
137 | } | |
138 | ||
139 | /* look for item defined */ | |
140 | p = task_array[t->type]; | |
141 | while (p) | |
142 | { | |
143 | if (!strcmp (p->data[0]->name, t->name)) | |
144 | /* have found it */ | |
145 | break; | |
146 | p = p->forward; | |
147 | } | |
148 | ||
149 | if (!p) | |
150 | { | |
151 | TaskingStructList *wrk = (TaskingStructList *)&task_array[t->type]; | |
152 | ||
153 | /* this is a new one -- allocate space */ | |
154 | p = xmalloc (sizeof (TaskingStructList)); | |
155 | memset (p->copies, 0, sizeof (p->copies)); | |
156 | p->forward = 0; | |
157 | p->num = 1; | |
158 | p->data[0] = t; | |
159 | ||
160 | /* queue it in */ | |
161 | while (wrk->forward) | |
162 | wrk = wrk->forward; | |
163 | wrk->forward = p; | |
164 | } | |
165 | else | |
166 | { | |
167 | if (p->num >= MAX_PER_ITEM) | |
168 | { | |
169 | fprintf (stderr, "Too many registrations of \"%s\".\n", t->name); | |
170 | exit (1); | |
171 | } | |
172 | p->data[p->num++] = t; | |
173 | } | |
174 | } | |
175 | \f | |
176 | /* define all the entries for the runtime system. They will be | |
177 | needed by chillrt0.o */ | |
178 | ||
179 | typedef char *(*fetch_names) (); | |
180 | typedef int (*fetch_numbers) (); | |
181 | ||
182 | static char tmp_for_fetch_name[100]; | |
183 | ||
184 | char * | |
185 | __fetch_name (number) | |
186 | int number; | |
187 | { | |
188 | TaskingStructList *p = task_array[Process]; | |
189 | ||
190 | while (p) | |
191 | { | |
192 | if (*(p->data[0]->value) == number) | |
193 | return (p->data[0]->name); | |
194 | p = p->forward; | |
195 | } | |
196 | sprintf (tmp_for_fetch_name, "%d", number); | |
197 | return (tmp_for_fetch_name); | |
198 | } | |
199 | fetch_names __RTS_FETCH_NAMES__ = __fetch_name; | |
200 | ||
201 | static int | |
202 | __fetch_number (name) | |
203 | char *name; | |
204 | { | |
205 | TaskingStructList *p = task_array[Process]; | |
206 | ||
207 | while (p) | |
208 | { | |
209 | if (!strcmp (p->data[0]->name, name)) | |
210 | return (*(p->data[0]->value)); | |
211 | p = p->forward; | |
212 | } | |
213 | return (-1); | |
214 | } | |
215 | fetch_numbers __RTS_FETCH_NUMBERS__ = __fetch_number; | |
216 | ||
217 | ||
218 | /* here we go to check all registered items */ | |
219 | static void | |
220 | __rts_init () | |
221 | { | |
222 | int i; | |
223 | TaskingStructList *p; | |
224 | ||
225 | for (i = Process; i <= Event; i++) | |
226 | { | |
227 | p = task_array[i]; | |
228 | while (p) | |
229 | { | |
230 | TaskingStruct *t = 0; | |
231 | int j; | |
232 | short val; | |
233 | ||
234 | for (j = 0; j < p->num; j++) | |
235 | { | |
236 | if (p->data[j]->value_defined) | |
237 | { | |
238 | if (t) | |
239 | { | |
240 | if (*(t->value) != *(p->data[j]->value)) | |
241 | { | |
242 | fprintf (stderr, "Different values (%d & %d) for \"%s\".", | |
243 | *(t->value), *(p->data[j]->value), t->name); | |
244 | exit (1); | |
245 | } | |
246 | } | |
247 | else | |
248 | t = p->data[j]; | |
249 | } | |
250 | } | |
251 | ||
252 | if (t) | |
253 | { | |
254 | ||
255 | val = *(t->value); | |
256 | ||
257 | if (used_values[t->type][val]) | |
258 | { | |
259 | fprintf (stderr, "Value %d for \"%s\" is already used.\n", | |
260 | val, t->name); | |
261 | exit (1); | |
262 | } | |
263 | used_values[t->type][val] = 1; | |
264 | } | |
265 | else | |
266 | { | |
267 | /* we have to create a new value */ | |
268 | val = get_next_free_number (used_values[p->data[0]->type]); | |
269 | } | |
270 | ||
271 | for (j = 0; j < p->num; j++) | |
272 | { | |
273 | p->data[j]->value_defined = 1; | |
274 | *(p->data[j]->value) = val; | |
275 | } | |
276 | ||
277 | p = p->forward; | |
278 | } | |
279 | } | |
280 | } | |
281 | EntryPoint __RTS_INIT__ = __rts_init; | |
282 | \f | |
283 | /* define the start process queue */ | |
284 | typedef struct STARTENTRY | |
285 | { | |
286 | struct STARTENTRY *forward; | |
287 | INSTANCE whoami; | |
288 | EntryPoint entry; | |
289 | void *data; | |
290 | int datalen; | |
291 | } StartEntry; | |
292 | ||
293 | static StartEntry *start_queue = 0; | |
294 | static StartEntry *current_process = 0; | |
295 | ||
296 | /* the jump buffer for the main loop */ | |
297 | static jmp_buf jump_buffer; | |
298 | static int jump_buffer_initialized = 0; | |
299 | ||
300 | /* look for entries in start_queue and start the process */ | |
301 | static void | |
302 | __rts_main_loop () | |
303 | { | |
304 | StartEntry *s; | |
305 | ||
306 | while (1) | |
307 | { | |
308 | if (setjmp (jump_buffer) == 0) | |
309 | { | |
310 | jump_buffer_initialized = 1; | |
311 | s = start_queue; | |
312 | while (s) | |
313 | { | |
314 | current_process = s; | |
315 | start_queue = s->forward; | |
316 | ||
317 | /* call the process */ | |
318 | (*s->entry) (s->data); | |
319 | s = start_queue; | |
320 | } | |
321 | /* when queue empty we have finished */ | |
322 | return; | |
323 | } | |
324 | else | |
325 | { | |
326 | /* stop executed */ | |
327 | if (current_process->data) | |
328 | free (current_process->data); | |
329 | free (current_process); | |
330 | current_process = 0; | |
331 | } | |
332 | } | |
333 | } | |
334 | EntryPoint __RTS_MAIN_LOOP__ = __rts_main_loop; | |
335 | ||
336 | ||
337 | void | |
338 | __start_process (ptype, pcopy, arg_size, args, ins) | |
339 | short ptype; | |
340 | short pcopy; | |
341 | int arg_size; | |
342 | void *args; | |
343 | INSTANCE *ins; | |
344 | { | |
345 | TaskingStructList *p = task_array[Process]; | |
346 | EntryPoint pc = 0; | |
347 | int i; | |
348 | short this_copy = pcopy; | |
349 | StartEntry *s, *wrk; | |
350 | ||
351 | /* search for the process */ | |
352 | while (p) | |
353 | { | |
354 | if (*(p->data[0]->value) == ptype) | |
355 | break; | |
356 | p = p->forward; | |
357 | } | |
358 | if (!p) | |
359 | { | |
360 | fprintf (stderr, "Cannot find a process with type %d.\n", ptype); | |
361 | exit (1); | |
362 | } | |
363 | ||
364 | /* search for the entry point */ | |
365 | for (i = 0; i < p->num; i++) | |
366 | { | |
367 | if (p->data[i]->entry) | |
368 | { | |
369 | pc = p->data[i]->entry; | |
370 | break; | |
371 | } | |
372 | } | |
373 | if (!pc) | |
374 | { | |
375 | fprintf (stderr, "Process \"%s\" doesn't have an entry point.\n", | |
376 | p->data[0]->name); | |
377 | exit (1); | |
378 | } | |
379 | ||
380 | /* check the copy */ | |
381 | if (pcopy >= MAX_COPIES) | |
382 | { | |
383 | fprintf (stderr, "Copy number (%d) out of range.\n", pcopy); | |
384 | exit (1); | |
385 | } | |
386 | if (pcopy == -1) | |
387 | { | |
388 | /* search for a copy number */ | |
389 | this_copy = get_next_copy_number (p); | |
390 | } | |
391 | else | |
392 | { | |
393 | if (p->copies[pcopy]) | |
394 | { | |
395 | /* FIXME: should be exception 'startfail' */ | |
396 | fprintf (stderr, "Copy number %d already in use for \"%s\".\n", | |
397 | pcopy, p->data[0]->name); | |
398 | exit (1); | |
399 | } | |
400 | p->copies[this_copy = pcopy] = 1; | |
401 | } | |
402 | ||
403 | /* ready to build start_queue entry */ | |
404 | s = xmalloc (sizeof (StartEntry)); | |
405 | s->forward = 0; | |
406 | s->whoami.pcopy = this_copy; | |
407 | s->whoami.ptype = ptype; | |
408 | s->entry = pc; | |
409 | s->datalen = arg_size; | |
410 | if (args) | |
411 | { | |
412 | s->data = xmalloc (arg_size); | |
413 | memcpy (s->data, args, arg_size); | |
414 | } | |
415 | else | |
416 | s->data = 0; | |
417 | ||
418 | /* queue that stuff in */ | |
419 | wrk = (StartEntry *)&start_queue; | |
420 | while (wrk->forward) | |
421 | wrk = wrk->forward; | |
422 | wrk->forward = s; | |
423 | ||
424 | /* if we have a pointer to ins -- set it */ | |
425 | if (ins) | |
426 | { | |
427 | ins->ptype = ptype; | |
428 | ins->pcopy = this_copy; | |
429 | } | |
430 | } | |
431 | \f | |
432 | void | |
433 | __stop_process () | |
434 | { | |
435 | if (!jump_buffer_initialized) | |
436 | { | |
437 | fprintf (stderr, "STOP called before START.\n"); | |
438 | exit (1); | |
439 | } | |
440 | longjmp (jump_buffer, 1); | |
441 | } | |
442 | ||
443 | ||
444 | /* function returns INSTANCE of current process */ | |
445 | INSTANCE | |
446 | __whoami () | |
447 | { | |
448 | INSTANCE whoami; | |
449 | if (current_process) | |
450 | whoami = current_process->whoami; | |
451 | else | |
452 | { | |
453 | whoami.ptype = 0; | |
454 | whoami.pcopy = 0; | |
455 | } | |
456 | return (whoami); | |
457 | } | |
458 | ||
459 | typedef struct | |
460 | { | |
461 | short *sc; | |
462 | int data_len; | |
463 | void *data; | |
464 | } SignalDescr; | |
465 | ||
466 | typedef struct SIGNALQUEUE | |
467 | { | |
468 | struct SIGNALQUEUE *forward; | |
469 | short sc; | |
470 | int data_len; | |
471 | void *data; | |
472 | INSTANCE to; | |
473 | INSTANCE from; | |
474 | } SignalQueue; | |
475 | ||
476 | /* define the signal queue */ | |
477 | static SignalQueue *msg_queue = 0; | |
478 | \f | |
479 | /* send a signal */ | |
480 | void | |
481 | __send_signal (s, to, prio, with_len, with) | |
482 | SignalDescr *s; | |
483 | INSTANCE to; | |
484 | int prio; | |
485 | int with_len; | |
486 | void *with; | |
487 | { | |
488 | SignalQueue *wrk = (SignalQueue *)&msg_queue; | |
489 | SignalQueue *p; | |
490 | TaskingStructList *t = task_array[Process]; | |
491 | ||
492 | /* search for process is defined and running */ | |
493 | while (t) | |
494 | { | |
495 | if (*(t->data[0]->value) == to.ptype) | |
496 | break; | |
497 | t = t->forward; | |
498 | } | |
499 | if (!t || !t->copies[to.pcopy]) | |
500 | { | |
501 | fprintf (stderr, "Can't find instance [%d,%d].\n", | |
502 | to.ptype, to.pcopy); | |
503 | exit (1); | |
504 | } | |
505 | ||
506 | /* go to the end of the msg_queue */ | |
507 | while (wrk->forward) | |
508 | wrk = wrk->forward; | |
509 | ||
510 | p = xmalloc (sizeof (SignalQueue)); | |
511 | p->sc = *(s->sc); | |
512 | if (p->data_len = s->data_len) | |
513 | { | |
514 | p->data = xmalloc (s->data_len); | |
515 | memcpy (p->data, s->data, s->data_len); | |
516 | } | |
517 | else | |
518 | p->data = 0; | |
519 | p->to = to; | |
520 | p->from = __whoami (); | |
521 | p->forward = 0; | |
522 | wrk->forward = p; | |
523 | } | |
524 | \f | |
525 | void | |
526 | start_signal_timeout (i, s, j) | |
527 | int i; | |
528 | SignalDescr *s; | |
529 | int j; | |
530 | { | |
531 | __send_signal (s, __whoami (), 0, 0, 0); | |
532 | } | |
533 | ||
534 | ||
535 | /* receive a signal */ | |
536 | int | |
537 | __wait_signal_timed (sig_got, nsigs, sigptr, datap, | |
538 | datalen, ins, else_branche, | |
539 | to, filename, lineno) | |
540 | short *sig_got; | |
541 | int nsigs; | |
542 | short *sigptr[]; | |
543 | void *datap; | |
544 | int datalen; | |
545 | INSTANCE *ins; | |
546 | int else_branche; | |
547 | void *to; | |
548 | char *filename; | |
549 | int lineno; | |
550 | { | |
551 | INSTANCE me = __whoami (); | |
552 | SignalQueue *wrk, *p = msg_queue; | |
553 | int i; | |
554 | short sc; | |
555 | ||
556 | /* search for a signal to `me' */ | |
557 | wrk = (SignalQueue *)&msg_queue; | |
558 | ||
559 | while (p) | |
560 | { | |
561 | if (p->to.ptype == me.ptype | |
562 | && p->to.pcopy == me.pcopy) | |
563 | break; | |
564 | wrk = p; | |
565 | p = p->forward; | |
566 | } | |
567 | ||
568 | if (!p) | |
569 | { | |
570 | fprintf (stderr, "No signal for [%d,%d].\n", | |
571 | me.ptype, me.pcopy); | |
572 | exit (1); | |
573 | } | |
574 | ||
575 | /* queue the message out */ | |
576 | wrk->forward = p->forward; | |
577 | ||
578 | /* now look for signal in list */ | |
579 | for (i = 0; i < nsigs; i++) | |
580 | if (*(sigptr[i]) == p->sc) | |
581 | break; | |
582 | ||
583 | if (i >= nsigs && ! else_branche) | |
584 | /* signal not in list and no ELSE in code */ | |
585 | __cause_exception ("signalfail", __FILE__, __LINE__); | |
586 | ||
587 | if (i >= nsigs) | |
588 | { | |
589 | /* signal not in list */ | |
590 | sc = p->sc; | |
591 | if (ins) | |
592 | *ins = p->from; | |
593 | if (p->data) | |
594 | free (p->data); | |
595 | free (p); | |
596 | *sig_got = sc; | |
597 | return (0); | |
598 | } | |
599 | ||
600 | /* we have found a signal in the list */ | |
601 | if (p->data_len) | |
602 | { | |
603 | if (datalen >= p->data_len | |
604 | && datap) | |
605 | memcpy (datap, p->data, p->data_len); | |
606 | else | |
607 | __cause_exception ("spacefail", __FILE__, __LINE__); | |
608 | } | |
609 | ||
610 | sc = p->sc; | |
611 | if (ins) | |
612 | *ins = p->from; | |
613 | if (p->data) | |
614 | free (p->data); | |
615 | free (p); | |
616 | *sig_got = sc; | |
617 | return (0); | |
618 | } | |
619 | \f | |
620 | /* wait a certain amount of seconds */ | |
621 | int | |
622 | __sleep_till (abstime, reltime, fname, lineno) | |
623 | time_t abstime; | |
624 | int reltime; | |
625 | char *fname; | |
626 | int lineno; | |
627 | { | |
628 | sleep (reltime); | |
629 | return 0; | |
630 | } | |
631 | \f | |
632 | /* set up an alarm */ | |
633 | static int timeout_flag = 0; | |
634 | ||
635 | static void alarm_handler () | |
636 | { | |
637 | timeout_flag = 1; | |
638 | } | |
639 | ||
640 | int * | |
641 | __define_timeout (howlong, filename, lineno) | |
642 | unsigned long howlong; /* comes in millisecs */ | |
643 | char *filename; | |
644 | int lineno; | |
645 | { | |
646 | unsigned int prev_alarm_value; | |
647 | ||
648 | signal (SIGALRM, alarm_handler); | |
649 | prev_alarm_value = alarm ((unsigned int)(howlong / 1000)); | |
650 | return &timeout_flag; | |
651 | } | |
652 | \f | |
653 | /* wait till timeout expires */ | |
654 | void | |
655 | __wait_timeout (toid, filename, lineno) | |
656 | volatile int *toid; | |
657 | char *filename; | |
658 | int lineno; | |
659 | { | |
660 | while (! *toid) ; | |
661 | *toid = 0; | |
662 | } |