| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 17:50:05 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:54 +03:00
										 |  |  | #include "sysemu/replay.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:59 +02:00
										 |  |  | #include "sysemu/runstate.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  | #include "replay-internal.h"
 | 
					
						
							|  |  |  | #include "qemu/error-report.h"
 | 
					
						
							| 
									
										
										
											
												Include qemu/main-loop.h less
In my "build everything" tree, changing qemu/main-loop.h triggers a
recompile of some 5600 out of 6600 objects (not counting tests and
objects that don't depend on qemu/osdep.h).  It includes block/aio.h,
which in turn includes qemu/event_notifier.h, qemu/notify.h,
qemu/processor.h, qemu/qsp.h, qemu/queue.h, qemu/thread-posix.h,
qemu/thread.h, qemu/timer.h, and a few more.
Include qemu/main-loop.h only where it's needed.  Touching it now
recompiles only some 1700 objects.  For block/aio.h and
qemu/event_notifier.h, these numbers drop from 5600 to 2800.  For the
others, they shrink only slightly.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20190812052359.30071-21-armbru@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
											
										 
											2019-08-12 07:23:50 +02:00
										 |  |  | #include "qemu/main-loop.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:48 +03:00
										 |  |  | /* Mutex to protect reading and writing events to the log.
 | 
					
						
							| 
									
										
										
										
											2016-09-26 11:08:04 +03:00
										 |  |  |    data_kind and has_unread_data are also protected | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:48 +03:00
										 |  |  |    by this mutex. | 
					
						
							|  |  |  |    It also protects replay events queue which stores events to be | 
					
						
							|  |  |  |    written or read to the log. */ | 
					
						
							|  |  |  | static QemuMutex lock; | 
					
						
							| 
									
										
										
										
											2020-04-30 12:13:49 +03:00
										 |  |  | /* Condition and queue for fair ordering of mutex lock requests. */ | 
					
						
							|  |  |  | static QemuCond mutex_cond; | 
					
						
							|  |  |  | static unsigned long mutex_head, mutex_tail; | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:48 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  | /* File for replay writing */ | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:59 +03:00
										 |  |  | static bool write_error; | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  | FILE *replay_file; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:59 +03:00
										 |  |  | static void replay_write_error(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!write_error) { | 
					
						
							|  |  |  |         error_report("replay write error"); | 
					
						
							|  |  |  |         write_error = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 15:33:30 +00:00
										 |  |  | static void replay_read_error(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     error_report("error reading the replay data"); | 
					
						
							|  |  |  |     exit(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  | void replay_put_byte(uint8_t byte) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (replay_file) { | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:59 +03:00
										 |  |  |         if (putc(byte, replay_file) == EOF) { | 
					
						
							|  |  |  |             replay_write_error(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void replay_put_event(uint8_t event) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:54 +03:00
										 |  |  |     assert(event < EVENT_COUNT); | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  |     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); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:59 +03:00
										 |  |  |         if (fwrite(buf, 1, size, replay_file) != size) { | 
					
						
							|  |  |  |             replay_write_error(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint8_t replay_get_byte(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint8_t byte = 0; | 
					
						
							|  |  |  |     if (replay_file) { | 
					
						
							| 
									
										
										
										
											2018-11-06 15:33:30 +00:00
										 |  |  |         int r = getc(replay_file); | 
					
						
							|  |  |  |         if (r == EOF) { | 
					
						
							|  |  |  |             replay_read_error(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         byte = r; | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  |     } | 
					
						
							|  |  |  |     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) { | 
					
						
							| 
									
										
										
										
											2018-11-06 15:33:30 +00:00
										 |  |  |             replay_read_error(); | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) { | 
					
						
							| 
									
										
										
										
											2018-11-06 15:33:30 +00:00
										 |  |  |             replay_read_error(); | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) { | 
					
						
							| 
									
										
										
										
											2016-09-26 11:08:04 +03:00
										 |  |  |         if (!replay_state.has_unread_data) { | 
					
						
							|  |  |  |             replay_state.data_kind = replay_get_byte(); | 
					
						
							| 
									
										
										
										
											2023-12-11 09:13:38 +00:00
										 |  |  |             replay_state.current_event++; | 
					
						
							| 
									
										
										
										
											2016-09-26 11:08:04 +03:00
										 |  |  |             if (replay_state.data_kind == EVENT_INSTRUCTION) { | 
					
						
							| 
									
										
										
										
											2019-07-25 11:44:43 +03:00
										 |  |  |                 replay_state.instruction_count = replay_get_dword(); | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:54 +03:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  |             replay_check_error(); | 
					
						
							| 
									
										
										
										
											2023-12-11 09:13:37 +00:00
										 |  |  |             replay_state.has_unread_data = true; | 
					
						
							| 
									
										
										
										
											2016-09-26 11:08:04 +03:00
										 |  |  |             if (replay_state.data_kind >= EVENT_COUNT) { | 
					
						
							|  |  |  |                 error_report("Replay: unknown event kind %d", | 
					
						
							|  |  |  |                              replay_state.data_kind); | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:54 +03:00
										 |  |  |                 exit(1); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void replay_finish_event(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-12-11 09:13:37 +00:00
										 |  |  |     replay_state.has_unread_data = false; | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:43 +03:00
										 |  |  |     replay_fetch_data_kind(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:48 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:37 +03:00
										 |  |  | static __thread bool replay_locked; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:48 +03:00
										 |  |  | void replay_mutex_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qemu_mutex_init(&lock); | 
					
						
							| 
									
										
										
										
											2020-04-30 12:13:49 +03:00
										 |  |  |     qemu_cond_init(&mutex_cond); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:48 +03:00
										 |  |  |     /* Hold the mutex while we start-up */ | 
					
						
							|  |  |  |     replay_locked = true; | 
					
						
							| 
									
										
										
										
											2020-04-30 12:13:49 +03:00
										 |  |  |     ++mutex_tail; | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:48 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:42 +03:00
										 |  |  | bool replay_mutex_locked(void) | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:37 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     return replay_locked; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:48 +03:00
										 |  |  | /* Ordering constraints, replay_lock must be taken before BQL */ | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:48 +03:00
										 |  |  | void replay_mutex_lock(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:48 +03:00
										 |  |  |     if (replay_mode != REPLAY_MODE_NONE) { | 
					
						
							| 
									
										
										
										
											2020-04-30 12:13:49 +03:00
										 |  |  |         unsigned long id; | 
					
						
							| 
									
										
										
										
											2024-01-02 10:35:25 -05:00
										 |  |  |         g_assert(!bql_locked()); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:48 +03:00
										 |  |  |         g_assert(!replay_mutex_locked()); | 
					
						
							|  |  |  |         qemu_mutex_lock(&lock); | 
					
						
							| 
									
										
										
										
											2020-04-30 12:13:49 +03:00
										 |  |  |         id = mutex_tail++; | 
					
						
							|  |  |  |         while (id != mutex_head) { | 
					
						
							|  |  |  |             qemu_cond_wait(&mutex_cond, &lock); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:48 +03:00
										 |  |  |         replay_locked = true; | 
					
						
							| 
									
										
										
										
											2020-04-30 12:13:49 +03:00
										 |  |  |         qemu_mutex_unlock(&lock); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:48 +03:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:48 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void replay_mutex_unlock(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:48 +03:00
										 |  |  |     if (replay_mode != REPLAY_MODE_NONE) { | 
					
						
							|  |  |  |         g_assert(replay_mutex_locked()); | 
					
						
							| 
									
										
										
										
											2020-04-30 12:13:49 +03:00
										 |  |  |         qemu_mutex_lock(&lock); | 
					
						
							|  |  |  |         ++mutex_head; | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:48 +03:00
										 |  |  |         replay_locked = false; | 
					
						
							| 
									
										
										
										
											2020-04-30 12:13:49 +03:00
										 |  |  |         qemu_cond_broadcast(&mutex_cond); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:48 +03:00
										 |  |  |         qemu_mutex_unlock(&lock); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:48 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-25 11:44:43 +03:00
										 |  |  | void replay_advance_current_icount(uint64_t current_icount) | 
					
						
							| 
									
										
										
										
											2018-10-08 13:24:14 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-25 11:44:43 +03:00
										 |  |  |     int diff = (int)(current_icount - replay_state.current_icount); | 
					
						
							| 
									
										
										
										
											2018-10-08 13:24:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Time can only go forward */ | 
					
						
							|  |  |  |     assert(diff >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-16 15:51:44 +03:00
										 |  |  |     if (replay_mode == REPLAY_MODE_RECORD) { | 
					
						
							|  |  |  |         if (diff > 0) { | 
					
						
							|  |  |  |             replay_put_event(EVENT_INSTRUCTION); | 
					
						
							|  |  |  |             replay_put_dword(diff); | 
					
						
							|  |  |  |             replay_state.current_icount += diff; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if (replay_mode == REPLAY_MODE_PLAY) { | 
					
						
							|  |  |  |         if (diff > 0) { | 
					
						
							|  |  |  |             replay_state.instruction_count -= diff; | 
					
						
							|  |  |  |             replay_state.current_icount += diff; | 
					
						
							|  |  |  |             if (replay_state.instruction_count == 0) { | 
					
						
							|  |  |  |                 assert(replay_state.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(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         /* Execution reached the break step */ | 
					
						
							|  |  |  |         if (replay_break_icount == replay_state.current_icount) { | 
					
						
							|  |  |  |             /* Cannot make callback directly from the vCPU thread */ | 
					
						
							|  |  |  |             timer_mod_ns(replay_break_timer, | 
					
						
							|  |  |  |                 qemu_clock_get_ns(QEMU_CLOCK_REALTIME)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-10-08 13:24:14 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:54 +03:00
										 |  |  | /*! Saves cached instructions. */ | 
					
						
							|  |  |  | void replay_save_instructions(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (replay_file && replay_mode == REPLAY_MODE_RECORD) { | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:48 +03:00
										 |  |  |         g_assert(replay_mutex_locked()); | 
					
						
							| 
									
										
										
										
											2019-07-25 11:44:43 +03:00
										 |  |  |         replay_advance_current_icount(replay_get_current_icount()); | 
					
						
							| 
									
										
										
										
											2015-09-17 19:23:54 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | } |