1 /* 2 * replay.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 "sysemu/replay.h" 14 #include "replay-internal.h" 15 #include "qemu/timer.h" 16 #include "qemu/main-loop.h" 17 #include "sysemu/sysemu.h" 18 19 ReplayMode replay_mode = REPLAY_MODE_NONE; 20 21 ReplayState replay_state; 22 23 bool replay_next_event_is(int event) 24 { 25 bool res = false; 26 27 /* nothing to skip - not all instructions used */ 28 if (replay_state.instructions_count != 0) { 29 assert(replay_data_kind == EVENT_INSTRUCTION); 30 return event == EVENT_INSTRUCTION; 31 } 32 33 while (true) { 34 if (event == replay_data_kind) { 35 res = true; 36 } 37 switch (replay_data_kind) { 38 case EVENT_SHUTDOWN: 39 replay_finish_event(); 40 qemu_system_shutdown_request(); 41 break; 42 default: 43 /* clock, time_t, checkpoint and other events */ 44 return res; 45 } 46 } 47 return res; 48 } 49 50 uint64_t replay_get_current_step(void) 51 { 52 return cpu_get_icount_raw(); 53 } 54 55 int replay_get_instructions(void) 56 { 57 int res = 0; 58 replay_mutex_lock(); 59 if (replay_next_event_is(EVENT_INSTRUCTION)) { 60 res = replay_state.instructions_count; 61 } 62 replay_mutex_unlock(); 63 return res; 64 } 65 66 void replay_account_executed_instructions(void) 67 { 68 if (replay_mode == REPLAY_MODE_PLAY) { 69 replay_mutex_lock(); 70 if (replay_state.instructions_count > 0) { 71 int count = (int)(replay_get_current_step() 72 - replay_state.current_step); 73 replay_state.instructions_count -= count; 74 replay_state.current_step += count; 75 if (replay_state.instructions_count == 0) { 76 assert(replay_data_kind == EVENT_INSTRUCTION); 77 replay_finish_event(); 78 /* Wake up iothread. This is required because 79 timers will not expire until clock counters 80 will be read from the log. */ 81 qemu_notify_event(); 82 } 83 } 84 replay_mutex_unlock(); 85 } 86 } 87 88 bool replay_exception(void) 89 { 90 if (replay_mode == REPLAY_MODE_RECORD) { 91 replay_save_instructions(); 92 replay_mutex_lock(); 93 replay_put_event(EVENT_EXCEPTION); 94 replay_mutex_unlock(); 95 return true; 96 } else if (replay_mode == REPLAY_MODE_PLAY) { 97 bool res = replay_has_exception(); 98 if (res) { 99 replay_mutex_lock(); 100 replay_finish_event(); 101 replay_mutex_unlock(); 102 } 103 return res; 104 } 105 106 return true; 107 } 108 109 bool replay_has_exception(void) 110 { 111 bool res = false; 112 if (replay_mode == REPLAY_MODE_PLAY) { 113 replay_account_executed_instructions(); 114 replay_mutex_lock(); 115 res = replay_next_event_is(EVENT_EXCEPTION); 116 replay_mutex_unlock(); 117 } 118 119 return res; 120 } 121 122 bool replay_interrupt(void) 123 { 124 if (replay_mode == REPLAY_MODE_RECORD) { 125 replay_save_instructions(); 126 replay_mutex_lock(); 127 replay_put_event(EVENT_INTERRUPT); 128 replay_mutex_unlock(); 129 return true; 130 } else if (replay_mode == REPLAY_MODE_PLAY) { 131 bool res = replay_has_interrupt(); 132 if (res) { 133 replay_mutex_lock(); 134 replay_finish_event(); 135 replay_mutex_unlock(); 136 } 137 return res; 138 } 139 140 return true; 141 } 142 143 bool replay_has_interrupt(void) 144 { 145 bool res = false; 146 if (replay_mode == REPLAY_MODE_PLAY) { 147 replay_account_executed_instructions(); 148 replay_mutex_lock(); 149 res = replay_next_event_is(EVENT_INTERRUPT); 150 replay_mutex_unlock(); 151 } 152 return res; 153 } 154 155 void replay_shutdown_request(void) 156 { 157 if (replay_mode == REPLAY_MODE_RECORD) { 158 replay_mutex_lock(); 159 replay_put_event(EVENT_SHUTDOWN); 160 replay_mutex_unlock(); 161 } 162 } 163 164 bool replay_checkpoint(ReplayCheckpoint checkpoint) 165 { 166 bool res = false; 167 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST); 168 replay_save_instructions(); 169 170 if (!replay_file) { 171 return true; 172 } 173 174 replay_mutex_lock(); 175 176 if (replay_mode == REPLAY_MODE_PLAY) { 177 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { 178 replay_finish_event(); 179 } else if (replay_data_kind != EVENT_ASYNC) { 180 res = false; 181 goto out; 182 } 183 replay_read_events(checkpoint); 184 /* replay_read_events may leave some unread events. 185 Return false if not all of the events associated with 186 checkpoint were processed */ 187 res = replay_data_kind != EVENT_ASYNC; 188 } else if (replay_mode == REPLAY_MODE_RECORD) { 189 replay_put_event(EVENT_CHECKPOINT + checkpoint); 190 replay_save_events(checkpoint); 191 res = true; 192 } 193 out: 194 replay_mutex_unlock(); 195 return res; 196 } 197