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