This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / sim / ppc / events.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14  
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  
19     */
20
21
22 #ifndef _EVENTS_C_
23 #define _EVENTS_C_
24
25 #ifndef STATIC_INLINE_EVENTS
26 #define STATIC_INLINE_EVENTS STATIC_INLINE
27 #endif
28
29
30 #include "basics.h"
31 #include "events.h"
32
33
34 /* The event queue maintains a single absolute time using two
35    variables.
36    
37    TIME_OF_EVENT: this holds the time at which the next event is ment
38    to occure.  If no next event it will hold the time of the last
39    event.  The first event occures at time 0 - system start.
40
41    TIME_FROM_EVENT: The current distance from TIME_OF_EVENT.  If an
42    event is pending, this will be positive.  If no future event is
43    pending this will be negative.  This variable is decremented once
44    for each iteration of a clock cycle.
45
46    Clearly there is a bug in that this code assumes that the absolute
47    time counter will never become greater than 2^62. */
48
49 typedef struct _event_entry event_entry;
50 struct _event_entry {
51   void *data;
52   event_handler *handler;
53   signed64 time_of_event;  
54   event_entry *next;
55 };
56
57 struct _event_queue {
58   event_entry *queue;
59   event_entry *volatile held;
60   event_entry *volatile *volatile held_end;
61   signed64 time_of_event;
62   signed64 time_from_event;
63 };
64
65
66 INLINE_EVENTS event_queue *
67 event_queue_create(void)
68 {
69   event_queue *new_event_queue = ZALLOC(event_queue);
70
71   new_event_queue->queue = NULL;
72   new_event_queue->held = NULL;
73   new_event_queue->held_end = &new_event_queue->held;
74   /* both times are already zero */
75   return new_event_queue;
76 }
77
78
79
80 STATIC_INLINE_EVENTS void
81 insert_event_entry(event_queue *events,
82                    event_entry *new_event,
83                    signed64 delta)
84 {
85   event_entry *curr;
86   event_entry **last;
87   signed64 time_of_event;
88
89   if (delta <= 0)
90     error("can not schedule event for current time\n");
91
92   /* compute when the event should occure */
93   time_of_event = (events->time_of_event
94                    - events->time_from_event
95                    + delta);
96
97   /* find the queue insertion point - things are time ordered */
98   last = &events->queue;
99   curr = events->queue;
100   while (curr != NULL && time_of_event >= curr->time_of_event) {
101     last = &curr->next;
102     curr = curr->next;
103   }
104
105   /* insert it */
106   new_event->next = curr;
107   *last = new_event;
108   new_event->time_of_event = time_of_event;
109
110   /* adjust the time until the first event */
111   events->time_from_event = (events->queue->time_of_event
112                              - (events->time_of_event
113                                 - events->time_from_event));
114   events->time_of_event = events->queue->time_of_event;
115 }
116
117 INLINE_EVENTS event_entry_tag
118 event_queue_schedule(event_queue *events,
119                      signed64 delta_time,
120                      event_handler *handler,
121                      void *data)
122 {
123   event_entry *new_event = ZALLOC(event_entry);
124   new_event->data = data;
125   new_event->handler = handler;
126   insert_event_entry(events, new_event, delta_time);
127   return new_event;
128 }
129
130
131 INLINE_EVENTS event_entry_tag
132 event_queue_schedule_after_signal(event_queue *events,
133                                   signed64 delta_time,
134                                   event_handler *handler,
135                                   void *data)
136 {
137   event_entry *new_event = ZALLOC(event_entry);
138
139   new_event->data = data;
140   new_event->handler = handler;
141   new_event->time_of_event = delta_time; /* work it out later */
142   new_event->next = NULL;
143
144   /*-LOCK-*/
145   if (events->held == NULL) {
146     events->held = new_event;
147   }
148   else {
149     *events->held_end = new_event;
150   }
151   events->held_end = &new_event->next;
152   /*-UNLOCK-*/
153
154   return new_event;
155 }
156
157
158 INLINE_EVENTS void
159 event_queue_deschedule(event_queue *events,
160                        event_entry_tag event_to_remove)
161 {
162   if (event_to_remove != NULL) {
163     event_entry *current;
164     event_entry **ptr_to_current;
165     for (ptr_to_current = &events->queue, current = *ptr_to_current;
166          current != NULL && current != event_to_remove;
167          ptr_to_current = &current->next, current = *ptr_to_current);
168     if (current == event_to_remove) {
169       *ptr_to_current = current->next;
170       zfree(current);
171       /* Just forget to recompute the delay to the next event */
172     }
173   }
174 }
175
176
177
178
179 INLINE_EVENTS int
180 event_queue_tick(event_queue *events)
181 {
182   /* remove things from the asynchronous event queue onto the real one */
183   if (events->held != NULL) {
184     event_entry *held_events;
185     event_entry *curr_event;
186
187     /*-LOCK-*/
188     held_events = events->held;
189     events->held = NULL;
190     events->held_end = &events->held;
191     /*-UNLOCK-*/
192
193     do {
194       curr_event = held_events;
195       held_events = curr_event->next;
196       insert_event_entry(events, curr_event, curr_event->time_of_event);
197     } while (held_events != NULL);
198   }
199
200   /* advance time, checking to see if we've reached time zero which
201      would indicate the time for the next event has arrived */
202   events->time_from_event -= 1;
203   return events->time_from_event == 0;
204 }
205
206 INLINE_EVENTS void
207 event_queue_process(event_queue *events)
208 {
209   if (events->time_from_event == 0) {
210     /* consume all events for this or earlier times */
211     do {
212       event_entry *to_do = events->queue;
213       events->queue = to_do->next;
214       to_do->handler(events,
215                      to_do->data);
216       zfree(to_do);
217     } while (events->queue != NULL
218              && events->queue->time_of_event <= events->time_of_event);
219     /* re-caculate time for new events */
220     if (events->queue != NULL) {
221       events->time_from_event = (events->queue->time_of_event
222                                  - events->time_of_event);
223       events->time_of_event = events->queue->time_of_event;
224     }
225     else {
226       /* nothing to do, time_from_event will go negative */
227     }
228   }
229 }
230
231 INLINE_EVENTS signed64
232 event_queue_time(event_queue *queue)
233 {
234   return queue->time_of_event - queue->time_from_event;
235 }
236
237
238 #endif /* _EVENTS_C_ */