From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53569) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YGmD6-0000bU-Pm for qemu-devel@nongnu.org; Thu, 29 Jan 2015 05:20:30 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YGmD1-0001i9-Dw for qemu-devel@nongnu.org; Thu, 29 Jan 2015 05:20:28 -0500 Received: from mx1.redhat.com ([209.132.183.28]:59664) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YGmD1-0001i5-7O for qemu-devel@nongnu.org; Thu, 29 Jan 2015 05:20:23 -0500 Message-ID: <54CA095B.8040100@redhat.com> Date: Thu, 29 Jan 2015 11:20:11 +0100 From: Paolo Bonzini MIME-Version: 1.0 References: <20150122085127.5276.53895.stgit@PASHA-ISP.def.inno> <20150122085238.5276.4455.stgit@PASHA-ISP.def.inno> In-Reply-To: <20150122085238.5276.4455.stgit@PASHA-ISP.def.inno> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [RFC PATCH v8 12/21] replay: recording and replaying different timers List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Pavel Dovgalyuk , qemu-devel@nongnu.org Cc: peter.maydell@linaro.org, peter.crosthwaite@xilinx.com, alex.bennee@linaro.org, mark.burton@greensocs.com, real@ispras.ru, batuzovk@ispras.ru, maria.klimushenkova@ispras.ru, afaerber@suse.de, fred.konrad@greensocs.com On 22/01/2015 09:52, Pavel Dovgalyuk wrote: > This patch introduces functions for recording and replaying realtime sources, > that do not use qemu-clock interface. These include return value of time() > function in time_t and struct tm forms. Patch also adds warning to > get_timedate function to prevent its usage in recording mode, because it may > lead to non-determinism. > > Signed-off-by: Pavel Dovgalyuk > --- > hw/timer/mc146818rtc.c | 3 + > hw/timer/pl031.c | 3 + > include/qemu-common.h | 1 > replay/replay-internal.h | 4 + > replay/replay-time.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++ > replay/replay.h | 8 +++ > vl.c | 17 +++++- > 7 files changed, 163 insertions(+), 5 deletions(-) > > diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c > index f18d128..92295fb 100644 > --- a/hw/timer/mc146818rtc.c > +++ b/hw/timer/mc146818rtc.c > @@ -28,6 +28,7 @@ > #include "qapi/visitor.h" > #include "qapi-event.h" > #include "qmp-commands.h" > +#include "replay/replay.h" > > #ifdef TARGET_I386 > #include "hw/i386/apic.h" > @@ -703,7 +704,7 @@ static void rtc_set_date_from_host(ISADevice *dev) > RTCState *s = MC146818_RTC(dev); > struct tm tm; > > - qemu_get_timedate(&tm, 0); What about just making qemu_get_timedate use qemu_clock_get_ns(QEMU_CLOCK_HOST) instead of time()? This would just work using the infrastructure of the previous patch. Paolo > + replay_get_timedate(&tm); > > s->base_rtc = mktimegm(&tm); > s->last_update = qemu_clock_get_ns(rtc_clock); > diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c > index 34d9b44..b02d288 100644 > --- a/hw/timer/pl031.c > +++ b/hw/timer/pl031.c > @@ -14,6 +14,7 @@ > #include "hw/sysbus.h" > #include "qemu/timer.h" > #include "sysemu/sysemu.h" > +#include "replay/replay.h" > > //#define DEBUG_PL031 > > @@ -200,7 +201,7 @@ static int pl031_init(SysBusDevice *dev) > sysbus_init_mmio(dev, &s->iomem); > > sysbus_init_irq(dev, &s->irq); > - qemu_get_timedate(&tm, 0); > + replay_get_timedate(&tm); > s->tick_offset = mktimegm(&tm) - > qemu_clock_get_ns(rtc_clock) / get_ticks_per_sec(); > > diff --git a/include/qemu-common.h b/include/qemu-common.h > index 644b46d..8c9957e 100644 > --- a/include/qemu-common.h > +++ b/include/qemu-common.h > @@ -129,6 +129,7 @@ void dump_drift_info(FILE *f, fprintf_function cpu_fprintf); > int qemu_main(int argc, char **argv, char **envp); > #endif > > +void qemu_get_timedate_no_warning(struct tm *tm, int offset); > void qemu_get_timedate(struct tm *tm, int offset); > int qemu_timedate_diff(struct tm *tm); > > diff --git a/replay/replay-internal.h b/replay/replay-internal.h > index e906ec3..be71e6f 100755 > --- a/replay/replay-internal.h > +++ b/replay/replay-internal.h > @@ -23,6 +23,10 @@ enum ReplayEvents { > EVENT_EXCEPTION, > /* for async events */ > EVENT_ASYNC, > + /* for time_t event */ > + EVENT_TIME_T, > + /* for tm event */ > + EVENT_TM, > /* for clock read/writes */ > /* some of grteater codes are reserved for clocks */ > EVENT_CLOCK > diff --git a/replay/replay-time.c b/replay/replay-time.c > index 5f5bc6a..282d00e 100755 > --- a/replay/replay-time.c > +++ b/replay/replay-time.c > @@ -82,3 +82,135 @@ int64_t replay_read_clock(ReplayClockKind kind) > fprintf(stderr, "REPLAY INTERNAL ERROR %d\n", __LINE__); > exit(1); > } > + > +/*! Saves time_t value to the log */ > +static void replay_save_time_t(time_t tm) > +{ > + replay_save_instructions(); > + > + if (replay_file) { > + replay_mutex_lock(); > + replay_put_event(EVENT_TIME_T); > + if (sizeof(tm) == 4) { > + replay_put_dword(tm); > + } else if (sizeof(tm) == 8) { > + replay_put_qword(tm); > + } else { > + fprintf(stderr, "invalid time_t sizeof: %u\n", > + (unsigned)sizeof(tm)); > + exit(1); > + } > + replay_mutex_unlock(); > + } > +} > + > +/*! Reads time_t value from the log. Stops execution in case of error */ > +static time_t replay_read_time_t(void) > +{ > + replay_exec_instructions(); > + > + if (replay_file) { > + time_t tm; > + > + replay_mutex_lock(); > + skip_async_events_until(EVENT_TIME_T); > + > + if (sizeof(tm) == 4) { > + tm = replay_get_dword(); > + } else if (sizeof(tm) == 8) { > + tm = replay_get_qword(); > + } else { > + fprintf(stderr, "invalid time_t sizeof: %u\n", > + (unsigned)sizeof(tm)); > + exit(1); > + } > + > + replay_check_error(); > + > + replay_has_unread_data = 0; > + replay_mutex_unlock(); > + > + return tm; > + } > + > + fprintf(stderr, "REPLAY INTERNAL ERROR %d\n", __LINE__); > + exit(1); > +} > + > +static void replay_save_tm(struct tm *tm) > +{ > + replay_save_instructions(); > + > + if (replay_file) { > + replay_mutex_lock(); > + replay_put_event(EVENT_TM); > + > + replay_put_dword(tm->tm_sec); > + replay_put_dword(tm->tm_min); > + replay_put_dword(tm->tm_hour); > + replay_put_dword(tm->tm_mday); > + replay_put_dword(tm->tm_mon); > + replay_put_dword(tm->tm_year); > + replay_put_dword(tm->tm_wday); > + replay_put_dword(tm->tm_yday); > + replay_put_dword(tm->tm_isdst); > + replay_mutex_unlock(); > + } > +} > + > +static void replay_read_tm(struct tm *tm) > +{ > + replay_exec_instructions(); > + > + if (replay_file) { > + replay_mutex_lock(); > + skip_async_events_until(EVENT_TM); > + > + tm->tm_sec = replay_get_dword(); > + tm->tm_min = replay_get_dword(); > + tm->tm_hour = replay_get_dword(); > + tm->tm_mday = replay_get_dword(); > + tm->tm_mon = replay_get_dword(); > + tm->tm_year = replay_get_dword(); > + tm->tm_wday = replay_get_dword(); > + tm->tm_yday = replay_get_dword(); > + tm->tm_isdst = replay_get_dword(); > + > + replay_check_error(); > + replay_has_unread_data = 0; > + replay_mutex_unlock(); > + > + return; > + } > + > + fprintf(stderr, "REPLAY INTERNAL ERROR %d\n", __LINE__); > + exit(1); > +} > + > +void replay_get_timedate(struct tm *tm) > +{ > + if (replay_mode == REPLAY_MODE_RECORD) { > + qemu_get_timedate_no_warning(tm, 0); > + replay_save_tm(tm); > + } else if (replay_mode == REPLAY_MODE_PLAY) { > + replay_read_tm(tm); > + } else { > + qemu_get_timedate_no_warning(tm, 0); > + } > +} > + > +time_t replay_time(void) > +{ > + time_t systime; > + > + if (replay_mode == REPLAY_MODE_RECORD) { > + systime = time(NULL); > + replay_save_time_t(systime); > + } else if (replay_mode == REPLAY_MODE_PLAY) { > + systime = replay_read_time_t(); > + } else { > + systime = time(NULL); > + } > + > + return systime; > +} > diff --git a/replay/replay.h b/replay/replay.h > index 8a8e7e0..2f1402c 100755 > --- a/replay/replay.h > +++ b/replay/replay.h > @@ -14,6 +14,7 @@ > > #include > #include > +#include > #include "qapi-types.h" > > /* replay clock kinds */ > @@ -67,6 +68,13 @@ int64_t replay_read_clock(ReplayClockKind kind); > : replay_mode == REPLAY_MODE_RECORD \ > ? replay_save_clock((clock), (value)) \ > : (value)) > +/*! Returns result of time() function execution in normal and record modes. > + In play mode returns value read from the log. */ > +time_t replay_time(void); > +/*! This function is used for obtaining current timedate. > + In record mode it also saves in into the replay log. > + In replay mode it just read from the log. */ > +void replay_get_timedate(struct tm *tm); > > /* Asynchronous events queue */ > > diff --git a/vl.c b/vl.c > index fbf4240..baff3b5 100644 > --- a/vl.c > +++ b/vl.c > @@ -118,6 +118,7 @@ int main(int argc, char **argv) > #include "qapi/opts-visitor.h" > #include "qom/object_interfaces.h" > #include "qapi-event.h" > +#include "replay/replay.h" > > #define DEFAULT_RAM_SIZE 128 > > @@ -715,7 +716,7 @@ void vm_start(void) > > /***********************************************************/ > /* host time/date access */ > -void qemu_get_timedate(struct tm *tm, int offset) > +void qemu_get_timedate_no_warning(struct tm *tm, int offset) > { > time_t ti; > > @@ -732,6 +733,16 @@ void qemu_get_timedate(struct tm *tm, int offset) > } > } > > +/* host time/date access with replay warning */ > +void qemu_get_timedate(struct tm *tm, int offset) > +{ > + if (replay_mode == REPLAY_MODE_RECORD) { > + fprintf(stderr, "REPLAY WARNING! qemu_get_timedate " > + "function may lead to non-determinism\n"); > + } > + qemu_get_timedate_no_warning(tm, offset); > +} > + > int qemu_timedate_diff(struct tm *tm) > { > time_t seconds; > @@ -747,7 +758,7 @@ int qemu_timedate_diff(struct tm *tm) > else > seconds = mktimegm(tm) + rtc_date_offset; > > - return seconds - time(NULL); > + return seconds - replay_time(); > } > > static void configure_rtc_date_offset(const char *startdate, int legacy) > @@ -785,7 +796,7 @@ static void configure_rtc_date_offset(const char *startdate, int legacy) > "'2006-06-17T16:01:21' or '2006-06-17'\n"); > exit(1); > } > - rtc_date_offset = time(NULL) - rtc_start_date; > + rtc_date_offset = replay_time() - rtc_start_date; > } > } > >