qemu/replay/replay-internal.c
Pavel Dovgalyuk 26bc60ac82 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>
2015-11-05 12:19:09 +01:00

207 lines
4.5 KiB
C

/*
* replay-internal.c
*
* Copyright (c) 2010-2015 Institute for System Programming
* of the Russian Academy of Sciences.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#include "qemu-common.h"
#include "sysemu/replay.h"
#include "replay-internal.h"
#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
unsigned int replay_data_kind = -1;
static unsigned int replay_has_unread_data;
/* Mutex to protect reading and writing events to the log.
replay_data_kind and replay_has_unread_data are also protected
by this mutex.
It also protects replay events queue which stores events to be
written or read to the log. */
static QemuMutex lock;
/* File for replay writing */
FILE *replay_file;
void replay_put_byte(uint8_t byte)
{
if (replay_file) {
putc(byte, replay_file);
}
}
void replay_put_event(uint8_t event)
{
assert(event < EVENT_COUNT);
replay_put_byte(event);
}
void replay_put_word(uint16_t word)
{
replay_put_byte(word >> 8);
replay_put_byte(word);
}
void replay_put_dword(uint32_t dword)
{
replay_put_word(dword >> 16);
replay_put_word(dword);
}
void replay_put_qword(int64_t qword)
{
replay_put_dword(qword >> 32);
replay_put_dword(qword);
}
void replay_put_array(const uint8_t *buf, size_t size)
{
if (replay_file) {
replay_put_dword(size);
fwrite(buf, 1, size, replay_file);
}
}
uint8_t replay_get_byte(void)
{
uint8_t byte = 0;
if (replay_file) {
byte = getc(replay_file);
}
return byte;
}
uint16_t replay_get_word(void)
{
uint16_t word = 0;
if (replay_file) {
word = replay_get_byte();
word = (word << 8) + replay_get_byte();
}
return word;
}
uint32_t replay_get_dword(void)
{
uint32_t dword = 0;
if (replay_file) {
dword = replay_get_word();
dword = (dword << 16) + replay_get_word();
}
return dword;
}
int64_t replay_get_qword(void)
{
int64_t qword = 0;
if (replay_file) {
qword = replay_get_dword();
qword = (qword << 32) + replay_get_dword();
}
return qword;
}
void replay_get_array(uint8_t *buf, size_t *size)
{
if (replay_file) {
*size = replay_get_dword();
if (fread(buf, 1, *size, replay_file) != *size) {
error_report("replay read error");
}
}
}
void replay_get_array_alloc(uint8_t **buf, size_t *size)
{
if (replay_file) {
*size = replay_get_dword();
*buf = g_malloc(*size);
if (fread(*buf, 1, *size, replay_file) != *size) {
error_report("replay read error");
}
}
}
void replay_check_error(void)
{
if (replay_file) {
if (feof(replay_file)) {
error_report("replay file is over");
qemu_system_vmstop_request_prepare();
qemu_system_vmstop_request(RUN_STATE_PAUSED);
} else if (ferror(replay_file)) {
error_report("replay file is over or something goes wrong");
qemu_system_vmstop_request_prepare();
qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
}
}
}
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);
}
}
}
}
void replay_finish_event(void)
{
replay_has_unread_data = 0;
replay_fetch_data_kind();
}
void replay_mutex_init(void)
{
qemu_mutex_init(&lock);
}
void replay_mutex_destroy(void)
{
qemu_mutex_destroy(&lock);
}
void replay_mutex_lock(void)
{
qemu_mutex_lock(&lock);
}
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();
}
}