events.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /* This file is part of the program psim.
  2. Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #ifndef _EVENTS_C_
  15. #define _EVENTS_C_
  16. #include "basics.h"
  17. #include "events.h"
  18. #include <signal.h>
  19. #include <stdlib.h>
  20. #if !defined (SIM_EVENTS_POLL_RATE)
  21. #define SIM_EVENTS_POLL_RATE 0x1000
  22. #endif
  23. /* The event queue maintains a single absolute time using two
  24. variables.
  25. TIME_OF_EVENT: this holds the time at which the next event is ment
  26. to occure. If no next event it will hold the time of the last
  27. event.
  28. TIME_FROM_EVENT: The current distance from TIME_OF_EVENT. If an
  29. event is pending, this will be positive. If no future event is
  30. pending this will be negative. This variable is decremented once
  31. for each iteration of a clock cycle.
  32. Initially, the clock is started at time one (1) with TIME_OF_EVENT
  33. == 0 and TIME_FROM_EVENT == -1.
  34. Clearly there is a bug in that this code assumes that the absolute
  35. time counter will never become greater than 2^62. */
  36. typedef struct _event_entry event_entry;
  37. struct _event_entry {
  38. void *data;
  39. event_handler *handler;
  40. int64_t time_of_event;
  41. event_entry *next;
  42. };
  43. struct _event_queue {
  44. int processing;
  45. event_entry *queue;
  46. event_entry *volatile held;
  47. event_entry *volatile *volatile held_end;
  48. int64_t time_of_event;
  49. int64_t time_from_event;
  50. };
  51. STATIC_INLINE_EVENTS\
  52. (void)
  53. sim_events_poll (void *data)
  54. {
  55. event_queue *queue = data;
  56. /* just re-schedule in 1000 million ticks time */
  57. event_queue_schedule (queue, SIM_EVENTS_POLL_RATE, sim_events_poll, queue);
  58. sim_io_poll_quit ();
  59. }
  60. INLINE_EVENTS\
  61. (event_queue *)
  62. event_queue_create(void)
  63. {
  64. event_queue *new_event_queue = ZALLOC(event_queue);
  65. new_event_queue->processing = 0;
  66. new_event_queue->queue = NULL;
  67. new_event_queue->held = NULL;
  68. new_event_queue->held_end = &new_event_queue->held;
  69. /* both times are already zero */
  70. return new_event_queue;
  71. }
  72. INLINE_EVENTS\
  73. (void)
  74. event_queue_init(event_queue *queue)
  75. {
  76. event_entry *event;
  77. /* drain the interrupt queue */
  78. {
  79. #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
  80. sigset_t old_mask;
  81. sigset_t new_mask;
  82. sigfillset(&new_mask);
  83. /*-LOCK-*/ sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
  84. #endif
  85. event = queue->held;
  86. while (event != NULL) {
  87. event_entry *dead = event;
  88. event = event->next;
  89. free(dead);
  90. }
  91. queue->held = NULL;
  92. queue->held_end = &queue->held;
  93. #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
  94. /*-UNLOCK-*/ sigprocmask(SIG_SETMASK, &old_mask, NULL);
  95. #endif
  96. }
  97. /* drain the normal queue */
  98. event = queue->queue;
  99. while (event != NULL) {
  100. event_entry *dead = event;
  101. event = event->next;
  102. free(dead);
  103. }
  104. queue->queue = NULL;
  105. /* wind time back to one */
  106. queue->processing = 0;
  107. queue->time_of_event = 0;
  108. queue->time_from_event = -1;
  109. /* schedule our initial counter event */
  110. event_queue_schedule (queue, 0, sim_events_poll, queue);
  111. }
  112. INLINE_EVENTS\
  113. (int64_t)
  114. event_queue_time(event_queue *queue)
  115. {
  116. return queue->time_of_event - queue->time_from_event;
  117. }
  118. STATIC_INLINE_EVENTS\
  119. (void)
  120. update_time_from_event(event_queue *events)
  121. {
  122. int64_t current_time = event_queue_time(events);
  123. if (events->queue != NULL) {
  124. events->time_from_event = (events->queue->time_of_event - current_time);
  125. events->time_of_event = events->queue->time_of_event;
  126. }
  127. else {
  128. events->time_of_event = current_time - 1;
  129. events->time_from_event = -1;
  130. }
  131. if (WITH_TRACE && ppc_trace[trace_events])
  132. {
  133. event_entry *event;
  134. int i;
  135. for (event = events->queue, i = 0;
  136. event != NULL;
  137. event = event->next, i++)
  138. {
  139. TRACE(trace_events, ("event time-from-event - time %" PRIi64 ", delta %" PRIi64 " - event %d, tag %p, time %" PRIi64 ", handler %p, data %p\n",
  140. current_time,
  141. events->time_from_event,
  142. i,
  143. event,
  144. event->time_of_event,
  145. event->handler,
  146. event->data));
  147. }
  148. }
  149. ASSERT(current_time == event_queue_time(events));
  150. }
  151. STATIC_INLINE_EVENTS\
  152. (void)
  153. insert_event_entry(event_queue *events,
  154. event_entry *new_event,
  155. int64_t delta)
  156. {
  157. event_entry *curr;
  158. event_entry **prev;
  159. int64_t time_of_event;
  160. if (delta < 0)
  161. error("what is past is past!\n");
  162. /* compute when the event should occure */
  163. time_of_event = event_queue_time(events) + delta;
  164. /* find the queue insertion point - things are time ordered */
  165. prev = &events->queue;
  166. curr = events->queue;
  167. while (curr != NULL && time_of_event >= curr->time_of_event) {
  168. ASSERT(curr->next == NULL
  169. || curr->time_of_event <= curr->next->time_of_event);
  170. prev = &curr->next;
  171. curr = curr->next;
  172. }
  173. ASSERT(curr == NULL || time_of_event < curr->time_of_event);
  174. /* insert it */
  175. new_event->next = curr;
  176. *prev = new_event;
  177. new_event->time_of_event = time_of_event;
  178. /* adjust the time until the first event */
  179. update_time_from_event(events);
  180. }
  181. INLINE_EVENTS\
  182. (event_entry_tag)
  183. event_queue_schedule(event_queue *events,
  184. int64_t delta_time,
  185. event_handler *handler,
  186. void *data)
  187. {
  188. event_entry *new_event = ZALLOC(event_entry);
  189. new_event->data = data;
  190. new_event->handler = handler;
  191. insert_event_entry(events, new_event, delta_time);
  192. TRACE(trace_events, ("event scheduled at %" PRIi64 " - tag %p - time %" PRIi64 ", handler %p, data %p\n",
  193. event_queue_time(events),
  194. new_event,
  195. new_event->time_of_event,
  196. new_event->handler,
  197. new_event->data));
  198. return (event_entry_tag)new_event;
  199. }
  200. INLINE_EVENTS\
  201. (event_entry_tag)
  202. event_queue_schedule_after_signal(event_queue *events,
  203. int64_t delta_time,
  204. event_handler *handler,
  205. void *data)
  206. {
  207. event_entry *new_event = ZALLOC(event_entry);
  208. new_event->data = data;
  209. new_event->handler = handler;
  210. new_event->time_of_event = delta_time; /* work it out later */
  211. new_event->next = NULL;
  212. {
  213. #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
  214. sigset_t old_mask;
  215. sigset_t new_mask;
  216. sigfillset(&new_mask);
  217. /*-LOCK-*/ sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
  218. #endif
  219. if (events->held == NULL) {
  220. events->held = new_event;
  221. }
  222. else {
  223. *events->held_end = new_event;
  224. }
  225. events->held_end = &new_event->next;
  226. #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
  227. /*-UNLOCK-*/ sigprocmask(SIG_SETMASK, &old_mask, NULL);
  228. #endif
  229. }
  230. TRACE(trace_events, ("event scheduled at %" PRIi64 " - tag %p - time %" PRIi64 ", handler %p, data %p\n",
  231. event_queue_time(events),
  232. new_event,
  233. new_event->time_of_event,
  234. new_event->handler,
  235. new_event->data));
  236. return (event_entry_tag)new_event;
  237. }
  238. INLINE_EVENTS\
  239. (void)
  240. event_queue_deschedule(event_queue *events,
  241. event_entry_tag event_to_remove)
  242. {
  243. event_entry *to_remove = (event_entry*)event_to_remove;
  244. ASSERT((events->time_from_event >= 0) == (events->queue != NULL));
  245. if (event_to_remove != NULL) {
  246. event_entry *current;
  247. event_entry **ptr_to_current;
  248. for (ptr_to_current = &events->queue, current = *ptr_to_current;
  249. current != NULL && current != to_remove;
  250. ptr_to_current = &current->next, current = *ptr_to_current);
  251. if (current == to_remove) {
  252. *ptr_to_current = current->next;
  253. TRACE(trace_events, ("event descheduled at %" PRIi64 " - tag %p - time %" PRIi64 ", handler %p, data %p\n",
  254. event_queue_time(events),
  255. event_to_remove,
  256. current->time_of_event,
  257. current->handler,
  258. current->data));
  259. free(current);
  260. update_time_from_event(events);
  261. }
  262. else {
  263. TRACE(trace_events, ("event descheduled at %" PRIi64 " - tag %p - not found\n",
  264. event_queue_time(events),
  265. event_to_remove));
  266. }
  267. }
  268. ASSERT((events->time_from_event >= 0) == (events->queue != NULL));
  269. }
  270. INLINE_EVENTS\
  271. (int)
  272. event_queue_tick(event_queue *events)
  273. {
  274. int64_t time_from_event;
  275. /* we should only be here when the previous tick has been fully processed */
  276. ASSERT(!events->processing);
  277. /* move any events that were queued by any signal handlers onto the
  278. real event queue. BTW: When inlining, having this code here,
  279. instead of in event_queue_process() causes GCC to put greater
  280. weight on keeping the pointer EVENTS in a register. This, in
  281. turn results in better code being output. */
  282. if (events->held != NULL) {
  283. event_entry *held_events;
  284. event_entry *curr_event;
  285. {
  286. #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
  287. sigset_t old_mask;
  288. sigset_t new_mask;
  289. sigfillset(&new_mask);
  290. /*-LOCK-*/ sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
  291. #endif
  292. held_events = events->held;
  293. events->held = NULL;
  294. events->held_end = &events->held;
  295. #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
  296. /*-UNLOCK-*/ sigprocmask(SIG_SETMASK, &old_mask, NULL);
  297. #endif
  298. }
  299. do {
  300. curr_event = held_events;
  301. held_events = curr_event->next;
  302. insert_event_entry(events, curr_event, curr_event->time_of_event);
  303. } while (held_events != NULL);
  304. }
  305. /* advance time, checking to see if we've reached time zero which
  306. would indicate the time for the next event has arrived */
  307. time_from_event = events->time_from_event;
  308. events->time_from_event = time_from_event - 1;
  309. return time_from_event == 0;
  310. }
  311. INLINE_EVENTS\
  312. (void)
  313. event_queue_process(event_queue *events)
  314. {
  315. int64_t event_time = event_queue_time(events);
  316. ASSERT((events->time_from_event == -1 && events->queue != NULL)
  317. || events->processing); /* something to do */
  318. /* consume all events for this or earlier times. Be careful to
  319. allow a new event to appear under our feet */
  320. events->processing = 1;
  321. while (events->queue != NULL
  322. && events->queue->time_of_event <= event_time) {
  323. event_entry *to_do = events->queue;
  324. event_handler *handler = to_do->handler;
  325. void *data = to_do->data;
  326. events->queue = to_do->next;
  327. TRACE(trace_events, ("event issued at %" PRIi64 " - tag %p - time %" PRIi64 ", handler %p, data %p\n",
  328. event_time,
  329. to_do,
  330. to_do->time_of_event,
  331. handler,
  332. data));
  333. free(to_do);
  334. /* Always re-compute the time to the next event so that HANDLER()
  335. can safely insert new events into the queue. */
  336. update_time_from_event(events);
  337. handler(data);
  338. }
  339. events->processing = 0;
  340. ASSERT(events->time_from_event > 0);
  341. ASSERT(events->queue != NULL); /* always poll event */
  342. }
  343. #endif /* _EVENTS_C_ */