1/* Implement tasking-related runtime actions for CHILL.
2   Copyright (C) 1992,1993 Free Software Foundation, Inc.
3   Author: Wilfried Moser
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING.  If not, write to
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA.  */
21
22/* As a special exception, if you link this library with other files,
23   some of which are compiled with GCC, to produce an executable,
24   this library does not by itself cause the resulting executable
25   to be covered by the GNU General Public License.
26   This exception does not however invalidate any other reasons why
27   the executable file might be covered by the GNU General Public License.  */
28
29#include "rtltypes.h"
30#include "rts.h"
31
32extern void __cause_ex1 (char *ex, char *file, int lineno);
33
34EXCEPTION (delayfail);
35#define CAUSE_DELAYFAIL     __cause_ex1 ("delayfail", filename, lineno)
36
37EXCEPTION (notyetimplemented);
38#define CAUSE_NOTIMPLEMENTED   __cause_ex1 ("notyetimplemeyed", filename, lineno)
39
40/*
41 * function __delay_event
42 *
43 * parameters:
44 *     ev_got      pointer to location where to write the event got.
45 *     nevents     number of events in list
46 *     evptrs      array of event descriptors
47 *     priority    specified priority
48 *     insloc      pointer to resulting instance location
49 *     to          timeout value
50 *     filename    filename of caller
51 *     lineno      linenumber of caller
52 *
53 * returns:
54 *     int         0 .. success
55 *                 1 .. timed out
56 *
57 * exceptions:
58 *     delayfail
59 *
60 * abstract:
61 *     implement the CHILL DELAY and DELAY CASE actions.
62 *
63 */
64
65int
66__delay_event (ev_got, nevents, evptrs, priority, to, insloc, filename, lineno)
67     void         **ev_got;
68     int            nevents;
69     Event_Descr   *evptrs;
70     int            priority;
71     void          *to;
72     INSTANCE      *insloc;
73     char          *filename;
74     int            lineno;
75{
76  int             i, already_done = 0;
77  Event_Queue    *start_list = 0;
78  Event_Queue   **retval = 0;
79  Event_Queue    *wrk;
80  int		  timed_out = 0;
81
82  /* check if all specified event queues have enough space left
83     to perform the delay */
84  for (i = 0; i < nevents; i++)
85    {
86      Event_Queue  *e;
87      unsigned long cnt = 0;
88      int j, have_done = 0;
89
90      if (evptrs[i].maxqueuelength == 0)
91	CAUSE_DELAYFAIL;
92      else if (evptrs[i].maxqueuelength == (unsigned long)-1L)
93	/* infinite length */
94	continue;
95
96      /* check if we already have processed this one, that means, this
97         event is mentioned more then once */
98      for (j = 0; j < i; j++)
99        {
100          if (evptrs[i].ev == evptrs[j].ev)
101	    {
102              have_done = 1;
103              break;
104	    }
105        }
106      if (have_done)
107	continue;
108
109      memcpy (&e, evptrs[i].ev, sizeof (Event_Queue *));
110      while (e)
111	{
112	  cnt++;
113	  e = e->forward;
114	}
115      if (cnt >= evptrs[i].maxqueuelength)
116	CAUSE_DELAYFAIL;
117    }
118
119  for (i = 0; i < nevents; i++)
120    {
121      /* queue that stuff on each event */
122      Event_Queue      *wrk;
123      Event_Queue      *ev;
124      Event_Queue      *prev_queue_entry = 0;
125      Event_Queue      *prev_list_entry;
126      int               j, have_done = 0;
127
128      /* check for this event already processed */
129      for (j = 0; j < i; j++)
130	{
131          if (evptrs[i].ev == evptrs[j].ev)
132	    {
133              have_done = 1;
134              break;
135	    }
136	}
137      if (have_done)
138	continue;
139
140      memcpy (&ev, &evptrs[i].ev, sizeof (Event_Queue *));
141      MALLOC (wrk, sizeof (Event_Queue));
142      memset (wrk, 0, sizeof (Event_Queue));
143
144      wrk->priority = priority;
145      wrk->this = THIS;
146      wrk->listhead = evptrs[i].ev;
147
148      /* search for the place to queue this entry in */
149      while (ev->forward != 0 && ev->priority >= priority)
150	{
151	  prev_queue_entry = ev;
152	  ev = ev->forward;
153	}
154
155      /* ready to put entry into queue */
156      if (ev->forward == 0 || prev_queue_entry == 0)
157	{
158	  /* beginning or end of the list */
159	  wrk->forward = ev->forward;
160	  ev->forward = wrk;
161	}
162      else
163	{
164	  /* this is somewhere in the middle */
165	  wrk->forward = prev_queue_entry->forward;
166	  prev_queue_entry->forward = wrk;
167	}
168
169      /* queue it into list */
170      wrk->startlist = start_list;
171      if (! start_list)
172	{
173	  /* we are the first in the list */
174	  start_list = wrk;
175	  prev_list_entry = wrk;
176	  wrk->startlist = start_list;
177	}
178      else
179	{
180	  prev_list_entry->chain = wrk;
181	  prev_list_entry = wrk;
182	}
183    }
184
185  /* tell runtime system to delay that process */
186  timed_out = __delay_this (wait_event_delay, to, filename, lineno);
187  if (timed_out)
188    {
189      /* we have to remove the entries from the queue's */
190      wrk = start_list;
191      while (wrk)
192        {
193	  Event_Queue *tmp = (Event_Queue *)wrk->listhead;
194
195	  while (tmp->forward != wrk)
196	    tmp = tmp->forward;
197	  tmp->forward = wrk->forward;
198	  wrk = wrk->chain;
199        }
200    }
201
202  wrk = start_list;
203  while (wrk)
204    {
205      Event_Queue  *tmp;
206
207      if (wrk->is_continued && ! already_done)
208	{
209	  already_done = 1;
210	  retval = wrk->listhead;
211	  if (insloc && !timed_out)
212	    {
213	      insloc->ptype = wrk->who_continued.ptype;
214	      insloc->pcopy = wrk->who_continued.pcopy;
215	    }
216	}
217      tmp = wrk->chain;
218      FREE (wrk);
219      wrk = tmp;
220    }
221  if (!timed_out && ev_got)
222    *ev_got = (void *)retval;
223  return timed_out;
224}
225
226/* force function print_event to be linked */
227extern void __print_event ();
228static EntryPoint pev = __print_event;
229