* Add library exception clause to the copyright notice for all
[gcc.git] / libchill / rts.c
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
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
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 }