OSDN Git Service

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