xref: /openbmc/qemu/replay/replay-events.c (revision 8eda206e)
1 /*
2  * replay-events.c
3  *
4  * Copyright (c) 2010-2015 Institute for System Programming
5  *                         of the Russian Academy of Sciences.
6  *
7  * This work is licensed under the terms of the GNU GPL, version 2 or later.
8  * See the COPYING file in the top-level directory.
9  *
10  */
11 
12 #include "qemu-common.h"
13 #include "qemu/error-report.h"
14 #include "sysemu/replay.h"
15 #include "replay-internal.h"
16 
17 typedef struct Event {
18     ReplayAsyncEventKind event_kind;
19     void *opaque;
20     void *opaque2;
21     uint64_t id;
22 
23     QTAILQ_ENTRY(Event) events;
24 } Event;
25 
26 static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list);
27 static unsigned int read_event_kind = -1;
28 static uint64_t read_id = -1;
29 static int read_checkpoint = -1;
30 
31 static bool events_enabled;
32 
33 /* Functions */
34 
35 static void replay_run_event(Event *event)
36 {
37     switch (event->event_kind) {
38     default:
39         error_report("Replay: invalid async event ID (%d) in the queue",
40                     event->event_kind);
41         exit(1);
42         break;
43     }
44 }
45 
46 void replay_enable_events(void)
47 {
48     events_enabled = true;
49 }
50 
51 bool replay_has_events(void)
52 {
53     return !QTAILQ_EMPTY(&events_list);
54 }
55 
56 void replay_flush_events(void)
57 {
58     replay_mutex_lock();
59     while (!QTAILQ_EMPTY(&events_list)) {
60         Event *event = QTAILQ_FIRST(&events_list);
61         replay_mutex_unlock();
62         replay_run_event(event);
63         replay_mutex_lock();
64         QTAILQ_REMOVE(&events_list, event, events);
65         g_free(event);
66     }
67     replay_mutex_unlock();
68 }
69 
70 void replay_disable_events(void)
71 {
72     if (replay_mode != REPLAY_MODE_NONE) {
73         events_enabled = false;
74         /* Flush events queue before waiting of completion */
75         replay_flush_events();
76     }
77 }
78 
79 void replay_clear_events(void)
80 {
81     replay_mutex_lock();
82     while (!QTAILQ_EMPTY(&events_list)) {
83         Event *event = QTAILQ_FIRST(&events_list);
84         QTAILQ_REMOVE(&events_list, event, events);
85 
86         g_free(event);
87     }
88     replay_mutex_unlock();
89 }
90 
91 /*! Adds specified async event to the queue */
92 #if 0
93 static void replay_add_event(ReplayAsyncEventKind event_kind,
94                              void *opaque,
95                              void *opaque2, uint64_t id)
96 {
97     assert(event_kind < REPLAY_ASYNC_COUNT);
98 
99     if (!replay_file || replay_mode == REPLAY_MODE_NONE
100         || !events_enabled) {
101         Event e;
102         e.event_kind = event_kind;
103         e.opaque = opaque;
104         e.opaque2 = opaque2;
105         e.id = id;
106         replay_run_event(&e);
107         return;
108     }
109 
110     Event *event = g_malloc0(sizeof(Event));
111     event->event_kind = event_kind;
112     event->opaque = opaque;
113     event->opaque2 = opaque2;
114     event->id = id;
115 
116     replay_mutex_lock();
117     QTAILQ_INSERT_TAIL(&events_list, event, events);
118     replay_mutex_unlock();
119 }
120 #endif
121 
122 static void replay_save_event(Event *event, int checkpoint)
123 {
124     if (replay_mode != REPLAY_MODE_PLAY) {
125         /* put the event into the file */
126         replay_put_event(EVENT_ASYNC);
127         replay_put_byte(checkpoint);
128         replay_put_byte(event->event_kind);
129 
130         /* save event-specific data */
131         switch (event->event_kind) {
132         default:
133             error_report("Unknown ID %d of replay event", read_event_kind);
134             exit(1);
135             break;
136         }
137     }
138 }
139 
140 /* Called with replay mutex locked */
141 void replay_save_events(int checkpoint)
142 {
143     while (!QTAILQ_EMPTY(&events_list)) {
144         Event *event = QTAILQ_FIRST(&events_list);
145         replay_save_event(event, checkpoint);
146 
147         replay_mutex_unlock();
148         replay_run_event(event);
149         replay_mutex_lock();
150         QTAILQ_REMOVE(&events_list, event, events);
151         g_free(event);
152     }
153 }
154 
155 static Event *replay_read_event(int checkpoint)
156 {
157     Event *event;
158     if (read_event_kind == -1) {
159         read_checkpoint = replay_get_byte();
160         read_event_kind = replay_get_byte();
161         read_id = -1;
162         replay_check_error();
163     }
164 
165     if (checkpoint != read_checkpoint) {
166         return NULL;
167     }
168 
169     /* Events that has not to be in the queue */
170     switch (read_event_kind) {
171     default:
172         error_report("Unknown ID %d of replay event", read_event_kind);
173         exit(1);
174         break;
175     }
176 
177     QTAILQ_FOREACH(event, &events_list, events) {
178         if (event->event_kind == read_event_kind
179             && (read_id == -1 || read_id == event->id)) {
180             break;
181         }
182     }
183 
184     if (event) {
185         QTAILQ_REMOVE(&events_list, event, events);
186     } else {
187         return NULL;
188     }
189 
190     /* Read event-specific data */
191 
192     return event;
193 }
194 
195 /* Called with replay mutex locked */
196 void replay_read_events(int checkpoint)
197 {
198     while (replay_data_kind == EVENT_ASYNC) {
199         Event *event = replay_read_event(checkpoint);
200         if (!event) {
201             break;
202         }
203         replay_mutex_unlock();
204         replay_run_event(event);
205         replay_mutex_lock();
206 
207         g_free(event);
208         replay_finish_event();
209         read_event_kind = -1;
210     }
211 }
212 
213 void replay_init_events(void)
214 {
215     read_event_kind = -1;
216 }
217 
218 void replay_finish_events(void)
219 {
220     events_enabled = false;
221     replay_clear_events();
222 }
223 
224 bool replay_events_enabled(void)
225 {
226     return events_enabled;
227 }
228