37 |
37 |
#include "sysemu/qtest.h"
|
38 |
38 |
#include "qemu/main-loop.h"
|
39 |
39 |
#include "qemu/bitmap.h"
|
|
40 |
#include "qemu/seqlock.h"
|
40 |
41 |
|
41 |
42 |
#ifndef _WIN32
|
42 |
43 |
#include "qemu/compatfd.h"
|
... | ... | |
110 |
111 |
static int64_t qemu_icount;
|
111 |
112 |
|
112 |
113 |
typedef struct TimersState {
|
|
114 |
/* Protected by BQL. */
|
113 |
115 |
int64_t cpu_ticks_prev;
|
114 |
116 |
int64_t cpu_ticks_offset;
|
|
117 |
|
|
118 |
/* cpu_clock_offset can be read out of BQL, so protect it with
|
|
119 |
* this lock.
|
|
120 |
*/
|
|
121 |
QemuSeqLock vm_clock_seqlock;
|
115 |
122 |
int64_t cpu_clock_offset;
|
116 |
123 |
int32_t cpu_ticks_enabled;
|
117 |
124 |
int64_t dummy;
|
... | ... | |
137 |
144 |
}
|
138 |
145 |
|
139 |
146 |
/* return the host CPU cycle counter and handle stop/restart */
|
|
147 |
/* Caller must hold the BQL */
|
140 |
148 |
int64_t cpu_get_ticks(void)
|
141 |
149 |
{
|
142 |
150 |
if (use_icount) {
|
... | ... | |
157 |
165 |
}
|
158 |
166 |
}
|
159 |
167 |
|
160 |
|
/* return the host CPU monotonic timer and handle stop/restart */
|
161 |
|
int64_t cpu_get_clock(void)
|
|
168 |
static int64_t cpu_get_clock_locked(void)
|
162 |
169 |
{
|
163 |
170 |
int64_t ti;
|
|
171 |
|
164 |
172 |
if (!timers_state.cpu_ticks_enabled) {
|
165 |
|
return timers_state.cpu_clock_offset;
|
|
173 |
ti = timers_state.cpu_clock_offset;
|
166 |
174 |
} else {
|
167 |
175 |
ti = get_clock();
|
168 |
|
return ti + timers_state.cpu_clock_offset;
|
|
176 |
ti += timers_state.cpu_clock_offset;
|
169 |
177 |
}
|
|
178 |
|
|
179 |
return ti;
|
170 |
180 |
}
|
171 |
181 |
|
172 |
|
/* enable cpu_get_ticks() */
|
|
182 |
/* return the host CPU monotonic timer and handle stop/restart */
|
|
183 |
int64_t cpu_get_clock(void)
|
|
184 |
{
|
|
185 |
int64_t ti;
|
|
186 |
unsigned start;
|
|
187 |
|
|
188 |
do {
|
|
189 |
start = seqlock_read_begin(&timers_state.vm_clock_seqlock);
|
|
190 |
ti = cpu_get_clock_locked();
|
|
191 |
} while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start));
|
|
192 |
|
|
193 |
return ti;
|
|
194 |
}
|
|
195 |
|
|
196 |
/* enable cpu_get_ticks()
|
|
197 |
* Caller must hold BQL which server as mutex for vm_clock_seqlock.
|
|
198 |
*/
|
173 |
199 |
void cpu_enable_ticks(void)
|
174 |
200 |
{
|
|
201 |
/* Here, the really thing protected by seqlock is cpu_clock_offset. */
|
|
202 |
seqlock_write_lock(&timers_state.vm_clock_seqlock);
|
175 |
203 |
if (!timers_state.cpu_ticks_enabled) {
|
176 |
204 |
timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
|
177 |
205 |
timers_state.cpu_clock_offset -= get_clock();
|
178 |
206 |
timers_state.cpu_ticks_enabled = 1;
|
179 |
207 |
}
|
|
208 |
seqlock_write_unlock(&timers_state.vm_clock_seqlock);
|
180 |
209 |
}
|
181 |
210 |
|
182 |
211 |
/* disable cpu_get_ticks() : the clock is stopped. You must not call
|
183 |
|
cpu_get_ticks() after that. */
|
|
212 |
* cpu_get_ticks() after that.
|
|
213 |
* Caller must hold BQL which server as mutex for vm_clock_seqlock.
|
|
214 |
*/
|
184 |
215 |
void cpu_disable_ticks(void)
|
185 |
216 |
{
|
|
217 |
/* Here, the really thing protected by seqlock is cpu_clock_offset. */
|
|
218 |
seqlock_write_lock(&timers_state.vm_clock_seqlock);
|
186 |
219 |
if (timers_state.cpu_ticks_enabled) {
|
187 |
220 |
timers_state.cpu_ticks_offset = cpu_get_ticks();
|
188 |
|
timers_state.cpu_clock_offset = cpu_get_clock();
|
|
221 |
timers_state.cpu_clock_offset = cpu_get_clock_locked();
|
189 |
222 |
timers_state.cpu_ticks_enabled = 0;
|
190 |
223 |
}
|
|
224 |
seqlock_write_unlock(&timers_state.vm_clock_seqlock);
|
191 |
225 |
}
|
192 |
226 |
|
193 |
227 |
/* Correlation between real and virtual time is always going to be
|
... | ... | |
371 |
405 |
|
372 |
406 |
void configure_icount(const char *option)
|
373 |
407 |
{
|
|
408 |
seqlock_init(&timers_state.vm_clock_seqlock, NULL);
|
374 |
409 |
vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
|
375 |
410 |
if (!option) {
|
376 |
411 |
return;
|