diff mbox series

[5/5] dm: rtc: Try to handle the localtime() race

Message ID 20220801135848.992449-6-sjg@chromium.org
State Accepted
Commit 21ddac140e3040b2693c1a5558a84c19a879c04f
Delegated to: Tom Rini
Headers show
Series rtc: Work around race conditions | expand

Commit Message

Simon Glass Aug. 1, 2022, 1:58 p.m. UTC
At present the sandbox timer uses localtime() which can jump around twice
a year when daylight-saving time changes.

It would be tricky to make use of gmtime() since we still need to present
the time in local time, as seems to be required by U-Boot's RTC interface.

The problem can only happen once, so use a loop to detect it and try
again. This should be sufficient to detect either a change in the 'second'
value, or a daylight-saving change. We can assume that the latter also
incorporates a 'second' change, so there is no need to loop more than
twice.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 test/dm/rtc.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

Comments

Heinrich Schuchardt Aug. 1, 2022, 3 p.m. UTC | #1
On 8/1/22 15:58, Simon Glass wrote:
> At present the sandbox timer uses localtime() which can jump around twice
> a year when daylight-saving time changes.
>
> It would be tricky to make use of gmtime() since we still need to present
> the time in local time, as seems to be required by U-Boot's RTC interface.
>
> The problem can only happen once, so use a loop to detect it and try
> again. This should be sufficient to detect either a change in the 'second'
> value, or a daylight-saving change. We can assume that the latter also
> incorporates a 'second' change, so there is no need to loop more than
> twice.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>

Linux systems tend to use UTC on the RTC. There is no reason for
sandbox_defconfig to deviate. Please, avoid all this complication by
reading the time with gmtime() instead of localtime().

Best regards

Heinrich

> ---
>
>   test/dm/rtc.c | 32 +++++++++++++++++++-------------
>   1 file changed, 19 insertions(+), 13 deletions(-)
>
> diff --git a/test/dm/rtc.c b/test/dm/rtc.c
> index 50086ffcf36..bf97dbbd2f9 100644
> --- a/test/dm/rtc.c
> +++ b/test/dm/rtc.c
> @@ -252,6 +252,7 @@ static int dm_test_rtc_reset(struct unit_test_state *uts)
>   	struct rtc_time now;
>   	struct udevice *dev, *emul;
>   	long old_base_time, base_time;
> +	int i;
>
>   	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
>   	ut_assertok(dm_rtc_get(dev, &now));
> @@ -259,19 +260,24 @@ static int dm_test_rtc_reset(struct unit_test_state *uts)
>   	ut_assertok(i2c_emul_find(dev, &emul));
>   	ut_assertnonnull(emul);
>
> -	old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, 0);
> -
> -	ut_asserteq(0, sandbox_i2c_rtc_get_set_base_time(emul, -1));
> -
> -	/*
> -	 * Resetting the RTC should put the base time back to normal. Allow for
> -	 * a one-second adjustment in case the time flips over while this
> -	 * test process is pre-empted, since reset_time() in i2c_rtc_emul.c
> -	 * reads the time from the OS.
> -	 */
> -	ut_assertok(dm_rtc_reset(dev));
> -	base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
> -	ut_assert(base_time - old_base_time <= 1);
> +	i = 0;
> +	do {
> +		old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, 0);
> +
> +		ut_asserteq(0, sandbox_i2c_rtc_get_set_base_time(emul, -1));
> +
> +		ut_assertok(dm_rtc_reset(dev));
> +		base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
> +
> +		/*
> +		 * Resetting the RTC should put the base time back to normal.
> +		 * Allow for a one-timeadjustment in case the time flips over
> +		 * while this test process is pre-empted (either by a second
> +		 * or a daylight-saving change), since reset_time() in
> +		 * i2c_rtc_emul.c reads the time from the OS.
> +		 */
> +	} while (++i < 2 && base_time != old_base_time);
> +	ut_asserteq(old_base_time, base_time);
>
>   	return 0;
>   }
Simon Glass Aug. 1, 2022, 7:13 p.m. UTC | #2
Hi Heinrich,

On Mon, 1 Aug 2022 at 09:00, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>
> On 8/1/22 15:58, Simon Glass wrote:
> > At present the sandbox timer uses localtime() which can jump around twice
> > a year when daylight-saving time changes.
> >
> > It would be tricky to make use of gmtime() since we still need to present
> > the time in local time, as seems to be required by U-Boot's RTC interface.
> >
> > The problem can only happen once, so use a loop to detect it and try
> > again. This should be sufficient to detect either a change in the 'second'
> > value, or a daylight-saving change. We can assume that the latter also
> > incorporates a 'second' change, so there is no need to loop more than
> > twice.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
>
> Linux systems tend to use UTC on the RTC. There is no reason for
> sandbox_defconfig to deviate. Please, avoid all this complication by
> reading the time with gmtime() instead of localtime().

That is an API change...how will we show the local time in that case?
I suppose we need to add this concept to rtc.h ?

Regards,
Simon
diff mbox series

Patch

diff --git a/test/dm/rtc.c b/test/dm/rtc.c
index 50086ffcf36..bf97dbbd2f9 100644
--- a/test/dm/rtc.c
+++ b/test/dm/rtc.c
@@ -252,6 +252,7 @@  static int dm_test_rtc_reset(struct unit_test_state *uts)
 	struct rtc_time now;
 	struct udevice *dev, *emul;
 	long old_base_time, base_time;
+	int i;
 
 	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
 	ut_assertok(dm_rtc_get(dev, &now));
@@ -259,19 +260,24 @@  static int dm_test_rtc_reset(struct unit_test_state *uts)
 	ut_assertok(i2c_emul_find(dev, &emul));
 	ut_assertnonnull(emul);
 
-	old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, 0);
-
-	ut_asserteq(0, sandbox_i2c_rtc_get_set_base_time(emul, -1));
-
-	/*
-	 * Resetting the RTC should put the base time back to normal. Allow for
-	 * a one-second adjustment in case the time flips over while this
-	 * test process is pre-empted, since reset_time() in i2c_rtc_emul.c
-	 * reads the time from the OS.
-	 */
-	ut_assertok(dm_rtc_reset(dev));
-	base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
-	ut_assert(base_time - old_base_time <= 1);
+	i = 0;
+	do {
+		old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, 0);
+
+		ut_asserteq(0, sandbox_i2c_rtc_get_set_base_time(emul, -1));
+
+		ut_assertok(dm_rtc_reset(dev));
+		base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
+
+		/*
+		 * Resetting the RTC should put the base time back to normal.
+		 * Allow for a one-timeadjustment in case the time flips over
+		 * while this test process is pre-empted (either by a second
+		 * or a daylight-saving change), since reset_time() in
+		 * i2c_rtc_emul.c reads the time from the OS.
+		 */
+	} while (++i < 2 && base_time != old_base_time);
+	ut_asserteq(old_base_time, base_time);
 
 	return 0;
 }