summaryrefslogtreecommitdiffstats
path: root/replay
diff options
context:
space:
mode:
authorPavel Dovgalyuk2015-09-17 18:23:54 +0200
committerPaolo Bonzini2015-11-05 12:19:09 +0100
commit26bc60ac82f88d14e65be5387eb4a136edf94f1b (patch)
tree978afbc06fc76ae179e5a1fceab66439bc5eef05 /replay
parentreplay: introduce mutex to protect the replay log (diff)
downloadqemu-26bc60ac82f88d14e65be5387eb4a136edf94f1b.tar.gz
qemu-26bc60ac82f88d14e65be5387eb4a136edf94f1b.tar.xz
qemu-26bc60ac82f88d14e65be5387eb4a136edf94f1b.zip
replay: introduce icount event
This patch adds icount event to the replay subsystem. This event corresponds to execution of several instructions and used to synchronize input events in the replay phase. Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> Message-Id: <20150917162354.8676.31351.stgit@PASHA-ISP.def.inno> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'replay')
-rw-r--r--replay/replay-internal.c24
-rw-r--r--replay/replay-internal.h21
-rw-r--r--replay/replay.c33
3 files changed, 78 insertions, 0 deletions
diff --git a/replay/replay-internal.c b/replay/replay-internal.c
index efae672dfa..35cff44a36 100644
--- a/replay/replay-internal.c
+++ b/replay/replay-internal.c
@@ -10,6 +10,7 @@
*/
#include "qemu-common.h"
+#include "sysemu/replay.h"
#include "replay-internal.h"
#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
@@ -36,6 +37,7 @@ void replay_put_byte(uint8_t byte)
void replay_put_event(uint8_t event)
{
+ assert(event < EVENT_COUNT);
replay_put_byte(event);
}
@@ -149,8 +151,15 @@ void replay_fetch_data_kind(void)
if (replay_file) {
if (!replay_has_unread_data) {
replay_data_kind = replay_get_byte();
+ if (replay_data_kind == EVENT_INSTRUCTION) {
+ replay_state.instructions_count = replay_get_dword();
+ }
replay_check_error();
replay_has_unread_data = 1;
+ if (replay_data_kind >= EVENT_COUNT) {
+ error_report("Replay: unknown event kind %d", replay_data_kind);
+ exit(1);
+ }
}
}
}
@@ -180,3 +189,18 @@ void replay_mutex_unlock(void)
{
qemu_mutex_unlock(&lock);
}
+
+/*! Saves cached instructions. */
+void replay_save_instructions(void)
+{
+ if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
+ replay_mutex_lock();
+ int diff = (int)(replay_get_current_step() - replay_state.current_step);
+ if (diff > 0) {
+ replay_put_event(EVENT_INSTRUCTION);
+ replay_put_dword(diff);
+ replay_state.current_step += diff;
+ }
+ replay_mutex_unlock();
+ }
+}
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 8a0de0d8d8..ff4fabc326 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -14,6 +14,20 @@
#include <stdio.h>
+enum ReplayEvents {
+ /* for instruction event */
+ EVENT_INSTRUCTION,
+ EVENT_COUNT
+};
+
+typedef struct ReplayState {
+ /*! Current step - number of processed instructions and timer events. */
+ uint64_t current_step;
+ /*! Number of instructions to be executed before other events happen. */
+ int instructions_count;
+} ReplayState;
+extern ReplayState replay_state;
+
extern unsigned int replay_data_kind;
/* File for replay writing */
@@ -50,4 +64,11 @@ void replay_finish_event(void);
replay_data_kind variable. */
void replay_fetch_data_kind(void);
+/*! Saves queued events (like instructions and sound). */
+void replay_save_instructions(void);
+
+/*! Skips async events until some sync event will be found.
+ \return true, if event was found */
+bool replay_next_event_is(int event);
+
#endif
diff --git a/replay/replay.c b/replay/replay.c
index a0ef04f822..62e8abaadf 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -9,6 +9,39 @@
*
*/
+#include "qemu-common.h"
#include "sysemu/replay.h"
+#include "replay-internal.h"
+#include "qemu/timer.h"
ReplayMode replay_mode = REPLAY_MODE_NONE;
+
+ReplayState replay_state;
+
+bool replay_next_event_is(int event)
+{
+ bool res = false;
+
+ /* nothing to skip - not all instructions used */
+ if (replay_state.instructions_count != 0) {
+ assert(replay_data_kind == EVENT_INSTRUCTION);
+ return event == EVENT_INSTRUCTION;
+ }
+
+ while (true) {
+ if (event == replay_data_kind) {
+ res = true;
+ }
+ switch (replay_data_kind) {
+ default:
+ /* clock, time_t, checkpoint and other events */
+ return res;
+ }
+ }
+ return res;
+}
+
+uint64_t replay_get_current_step(void)
+{
+ return cpu_get_icount_raw();
+}