mirror of
https://github.com/qemu/qemu.git
synced 2024-11-30 07:13:38 +08:00
b60c48a701
This patch records and replays simulator shutdown event. Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> Message-Id: <20150917162433.8676.32262.stgit@PASHA-ISP.def.inno> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
163 lines
4.0 KiB
C
163 lines
4.0 KiB
C
/*
|
|
* replay.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/timer.h"
|
|
#include "qemu/main-loop.h"
|
|
#include "sysemu/sysemu.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) {
|
|
case EVENT_SHUTDOWN:
|
|
replay_finish_event();
|
|
qemu_system_shutdown_request();
|
|
break;
|
|
default:
|
|
/* clock, time_t, checkpoint and other events */
|
|
return res;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
uint64_t replay_get_current_step(void)
|
|
{
|
|
return cpu_get_icount_raw();
|
|
}
|
|
|
|
int replay_get_instructions(void)
|
|
{
|
|
int res = 0;
|
|
replay_mutex_lock();
|
|
if (replay_next_event_is(EVENT_INSTRUCTION)) {
|
|
res = replay_state.instructions_count;
|
|
}
|
|
replay_mutex_unlock();
|
|
return res;
|
|
}
|
|
|
|
void replay_account_executed_instructions(void)
|
|
{
|
|
if (replay_mode == REPLAY_MODE_PLAY) {
|
|
replay_mutex_lock();
|
|
if (replay_state.instructions_count > 0) {
|
|
int count = (int)(replay_get_current_step()
|
|
- replay_state.current_step);
|
|
replay_state.instructions_count -= count;
|
|
replay_state.current_step += count;
|
|
if (replay_state.instructions_count == 0) {
|
|
assert(replay_data_kind == EVENT_INSTRUCTION);
|
|
replay_finish_event();
|
|
/* Wake up iothread. This is required because
|
|
timers will not expire until clock counters
|
|
will be read from the log. */
|
|
qemu_notify_event();
|
|
}
|
|
}
|
|
replay_mutex_unlock();
|
|
}
|
|
}
|
|
|
|
bool replay_exception(void)
|
|
{
|
|
if (replay_mode == REPLAY_MODE_RECORD) {
|
|
replay_save_instructions();
|
|
replay_mutex_lock();
|
|
replay_put_event(EVENT_EXCEPTION);
|
|
replay_mutex_unlock();
|
|
return true;
|
|
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
|
bool res = replay_has_exception();
|
|
if (res) {
|
|
replay_mutex_lock();
|
|
replay_finish_event();
|
|
replay_mutex_unlock();
|
|
}
|
|
return res;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool replay_has_exception(void)
|
|
{
|
|
bool res = false;
|
|
if (replay_mode == REPLAY_MODE_PLAY) {
|
|
replay_account_executed_instructions();
|
|
replay_mutex_lock();
|
|
res = replay_next_event_is(EVENT_EXCEPTION);
|
|
replay_mutex_unlock();
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
bool replay_interrupt(void)
|
|
{
|
|
if (replay_mode == REPLAY_MODE_RECORD) {
|
|
replay_save_instructions();
|
|
replay_mutex_lock();
|
|
replay_put_event(EVENT_INTERRUPT);
|
|
replay_mutex_unlock();
|
|
return true;
|
|
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
|
bool res = replay_has_interrupt();
|
|
if (res) {
|
|
replay_mutex_lock();
|
|
replay_finish_event();
|
|
replay_mutex_unlock();
|
|
}
|
|
return res;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool replay_has_interrupt(void)
|
|
{
|
|
bool res = false;
|
|
if (replay_mode == REPLAY_MODE_PLAY) {
|
|
replay_account_executed_instructions();
|
|
replay_mutex_lock();
|
|
res = replay_next_event_is(EVENT_INTERRUPT);
|
|
replay_mutex_unlock();
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void replay_shutdown_request(void)
|
|
{
|
|
if (replay_mode == REPLAY_MODE_RECORD) {
|
|
replay_mutex_lock();
|
|
replay_put_event(EVENT_SHUTDOWN);
|
|
replay_mutex_unlock();
|
|
}
|
|
}
|