Skip to content

Commit

Permalink
More feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
Steve Pfister committed Sep 9, 2022
1 parent 1088724 commit a9034d2
Showing 1 changed file with 18 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ namespace System
{
public readonly partial struct DateTimeOffset
{
private static bool s_androidTZDataLoaded;
private static readonly object s_localUtcOffsetLock = new();
private static Thread? s_loadAndroidTZData;
private static bool s_startNewBackgroundThread = true;
// 0 == in process of being loaded, 1 == loaded
private static int s_androidTZDataLoaded = -1;

// Now on Android does the following
// 1) quickly returning a fast path result when first called if the right AppContext data element is set
Expand All @@ -29,55 +27,30 @@ public static DateTimeOffset Now
{
DateTime utcDateTime = DateTime.UtcNow;

if (s_androidTZDataLoaded) // The background thread finished, the cache is loaded.
if (s_androidTZDataLoaded == 1) // The background thread finished, the cache is loaded.
{
return ToLocalTime(utcDateTime, true);
}

if (s_startNewBackgroundThread) // The cache isn't loaded and no background thread has been created
if (Interlocked.CompareExchange(ref s_androidTZDataLoaded, 0, -1) != -1)
{
lock (s_localUtcOffsetLock)
{
// Now may be called multiple times before a cache is loaded and a background thread is running,
// once the lock is available, check for a cache and background thread.
if (s_androidTZDataLoaded)
return ToLocalTime(utcDateTime, true);

if (s_loadAndroidTZData == null)
{
s_loadAndroidTZData = new Thread(() => {
// Delay the background thread to avoid impacting startup, if it still coincides after 1s, startup is already perceived as slow
Thread.Sleep(1000);
return ToLocalTime(utcDateTime, true);
}

_ = TimeZoneInfo.Local; // Load AndroidTZData
s_androidTZDataLoaded = true;
new Thread(() =>
{
try
{
// Delay the background thread to avoid impacting startup, if it still coincides after 1s, startup is already perceived as slow
Thread.Sleep(1000);
lock (s_localUtcOffsetLock)
{
s_loadAndroidTZData = null; // Ensure thread is cleared when cache is loaded
}
}) { IsBackground = true };
}
_ = TimeZoneInfo.Local; // Load AndroidTZData
}

if (s_startNewBackgroundThread)
finally
{
// Because Start does not block the calling thread,
// setting the boolean flag to false immediately after should
// prevent two calls to DateTimeOffset.Now in quick succession
// from both reaching here.
//
// In the event multiple threads hit Start at the same time,
// swallow the exception and move on.
try
{
s_loadAndroidTZData.Start();
s_startNewBackgroundThread = false;
}
catch
{
}
Volatile.Write(ref s_androidTZDataLoaded, 1);
}
}

}) { IsBackground = true }.Start();

object? localDateTimeOffset = AppContext.GetData("System.TimeZoneInfo.LocalDateTimeOffset");
if (localDateTimeOffset == null) // If no offset property provided through monovm app context, default
Expand Down

0 comments on commit a9034d2

Please sign in to comment.