/* Hardware event manager.
- Copyright (C) 1998 Free Software Foundation, Inc.
+ Copyright (C) 1998, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#include "sim-main.h"
+#include "hw-main.h"
#include "hw-base.h"
#include "sim-events.h"
/* The hw-events object is implemented using sim-events */
-struct hw_event {
+struct hw_event
+{
void *data;
struct hw *me;
hw_event_callback *callback;
struct hw_event_data *entry;
};
-struct hw_event_data {
+struct hw_event_data
+{
struct hw_event event;
struct hw_event_data *next;
- struct hw_event_data **prev;
};
void
create_hw_event_data (struct hw *me)
{
+ if (me->events_of_hw != NULL)
+ hw_abort (me, "stray events");
/* NOP */
}
void
delete_hw_event_data (struct hw *me)
{
- if (me->events_of_hw != NULL)
- hw_abort (me, "stray events");
-}
-
-
-static void
-delete_hw_event (struct hw *me,
- struct hw_event **event)
-{
- struct hw_event_data *entry = (*event)->entry;
- *(entry->prev) = entry->next;
- entry->next->prev = entry->prev;
- (*event) = NULL;
-}
-
-
-static void
-create_hw_event (struct hw *me,
- struct hw_event **event)
-{
- struct hw_event_data *entry = HW_ZALLOC (me, struct hw_event_data);
- entry->next = me->events_of_hw;
- entry->prev = &me->events_of_hw;
- me->events_of_hw->prev = &entry->next;
- me->events_of_hw = entry;
- (*event) = &entry->event;
+ /* Remove the scheduled event. */
+ while (me->events_of_hw)
+ hw_event_queue_deschedule (me, &me->events_of_hw->event);
}
-
/* Pass the H/W event onto the real callback */
static void
void *data)
{
/* save the data */
- struct hw_event *event = (struct hw_event*)data;
- struct hw *me = event->me;
- void *event_data = event->data;
- hw_event_callback *callback = event->callback;
- hw_free (me, data);
- event = NULL;
- callback (me, event_data);
+ struct hw_event_data *entry = (struct hw_event_data *) data;
+ struct hw *me = entry->event.me;
+ void *event_data = entry->event.data;
+ hw_event_callback *callback = entry->event.callback;
+ struct hw_event_data **prev = &me->events_of_hw;
+ while ((*prev) != entry)
+ prev = &(*prev)->next;
+ (*prev) = entry->next;
+ hw_free (me, entry);
+ callback (me, event_data); /* may not return */
}
void *data)
{
struct hw_event *event;
- create_hw_event (me, &event);
- /* fill it in */
- event->data = data;
- event->callback = callback;
- event->me = me;
- event->real = sim_events_schedule (hw_system (me),
- delta_time,
- bounce_hw_event,
- event);
+ va_list dummy;
+ memset (&dummy, 0, sizeof dummy);
+ event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data,
+ NULL, dummy);
return event;
}
+struct hw_event *
+hw_event_queue_schedule_tracef (struct hw *me,
+ signed64 delta_time,
+ hw_event_callback *callback,
+ void *data,
+ const char *fmt,
+ ...)
+{
+ struct hw_event *event;
+ va_list ap;
+ va_start (ap, fmt);
+ event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data, fmt, ap);
+ va_end (ap);
+ return event;
+}
+
+struct hw_event *
+hw_event_queue_schedule_vtracef (struct hw *me,
+ signed64 delta_time,
+ hw_event_callback *callback,
+ void *data,
+ const char *fmt,
+ va_list ap)
+{
+ struct hw_event_data *entry = HW_ZALLOC (me, struct hw_event_data);
+ entry->next = me->events_of_hw;
+ me->events_of_hw = entry;
+ /* fill it in */
+ entry->event.entry = entry;
+ entry->event.data = data;
+ entry->event.callback = callback;
+ entry->event.me = me;
+ entry->event.real = sim_events_schedule_vtracef (hw_system (me),
+ delta_time,
+ bounce_hw_event,
+ entry,
+ fmt, ap);
+ return &entry->event;
+}
+
void
hw_event_queue_deschedule (struct hw *me,
struct hw_event *event_to_remove)
{
- /* remove it from the event queue */
- sim_events_deschedule (hw_system (me),
- event_to_remove->real);
- delete_hw_event (me, &event_to_remove);
+/* ZAP the event but only if it is still in the event queue. Note
+ that event_to_remove is only de-referenced after its validity has
+ been confirmed. */
+ struct hw_event_data **prev;
+ for (prev = &me->events_of_hw;
+ (*prev) != NULL;
+ prev = &(*prev)->next)
+ {
+ struct hw_event_data *entry = (*prev);
+ if (&entry->event == event_to_remove)
+ {
+ sim_events_deschedule (hw_system (me),
+ entry->event.real);
+ (*prev) = entry->next;
+ hw_free (me, entry);
+ return;
+ }
+ }
}
return sim_events_time (hw_system (me));
}
+/* Returns the time that remains before the event is raised. */
+signed64
+hw_event_remain_time (struct hw *me, struct hw_event *event)
+{
+ signed64 t;
+
+ t = sim_events_remain_time (hw_system (me), event->real);
+ return t;
+}
+/* Only worry about this compling on ANSI systems.
+ Build with `make test-hw-events' in sim/<cpu> directory*/
+
+#if defined (MAIN)
+#include "sim-main.h"
+#include <string.h>
+#include <stdio.h>
+
+static void
+test_handler (struct hw *me,
+ void *data)
+{
+ int *n = data;
+ if (*n != hw_event_queue_time (me))
+ abort ();
+ *n = -(*n);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ host_callback *cb = ZALLOC (host_callback);
+ struct sim_state *sd = sim_state_alloc (0, cb);
+ struct hw *me = ZALLOC (struct hw);
+ sim_pre_argv_init (sd, "test-hw-events");
+ sim_post_argv_init (sd);
+ me->system_of_hw = sd;
+
+ printf ("Create hw-event-data\n");
+ {
+ create_hw_alloc_data (me);
+ create_hw_event_data (me);
+ delete_hw_event_data (me);
+ delete_hw_alloc_data (me);
+ }
+
+ printf ("Create hw-events\n");
+ {
+ struct hw_event *a;
+ struct hw_event *b;
+ struct hw_event *c;
+ struct hw_event *d;
+ create_hw_alloc_data (me);
+ create_hw_event_data (me);
+ a = hw_event_queue_schedule (me, 0, NULL, NULL);
+ b = hw_event_queue_schedule (me, 1, NULL, NULL);
+ c = hw_event_queue_schedule (me, 2, NULL, NULL);
+ d = hw_event_queue_schedule (me, 1, NULL, NULL);
+ hw_event_queue_deschedule (me, c);
+ hw_event_queue_deschedule (me, b);
+ hw_event_queue_deschedule (me, a);
+ hw_event_queue_deschedule (me, d);
+ c = HW_ZALLOC (me, struct hw_event);
+ hw_event_queue_deschedule (me, b); /* OOPS! */
+ hw_free (me, c);
+ delete_hw_event_data (me);
+ delete_hw_alloc_data (me);
+ }
+
+ printf ("Schedule hw-events\n");
+ {
+ struct hw_event **e;
+ int *n;
+ int i;
+ int nr = 4;
+ e = HW_NZALLOC (me, struct hw_event *, nr);
+ n = HW_NZALLOC (me, int, nr);
+ create_hw_alloc_data (me);
+ create_hw_event_data (me);
+ for (i = 0; i < nr; i++)
+ {
+ n[i] = i;
+ e[i] = hw_event_queue_schedule (me, i, test_handler, &n[i]);
+ }
+ sim_events_preprocess (sd, 1, 1);
+ for (i = 0; i < nr; i++)
+ {
+ if (sim_events_tick (sd))
+ sim_events_process (sd);
+ }
+ for (i = 0; i < nr; i++)
+ {
+ if (n[i] != -i)
+ abort ();
+ hw_event_queue_deschedule (me, e[i]);
+ }
+ hw_free (me, n);
+ hw_free (me, e);
+ delete_hw_event_data (me);
+ delete_hw_alloc_data (me);
+ }
+
+ return 0;
+}
+#endif