about summary refs log tree commit diff
path: root/absl/time/internal/cctz/src/time_zone_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/time/internal/cctz/src/time_zone_impl.cc')
-rw-r--r--absl/time/internal/cctz/src/time_zone_impl.cc34
1 files changed, 13 insertions, 21 deletions
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc
index 030ae0e19e07..f34e3aec84d6 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.cc
+++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -15,6 +15,7 @@
 #include "time_zone_impl.h"
 
 #include <deque>
+#include <memory>
 #include <mutex>
 #include <string>
 #include <unordered_map>
@@ -48,17 +49,16 @@ std::mutex& TimeZoneMutex() {
 time_zone time_zone::Impl::UTC() { return time_zone(UTCImpl()); }
 
 bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
-  const time_zone::Impl* const utc_impl = UTCImpl();
+  const Impl* const utc_impl = UTCImpl();
 
-  // First check for UTC (which is never a key in time_zone_map).
+  // Check for UTC (which is never a key in time_zone_map).
   auto offset = seconds::zero();
   if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) {
     *tz = time_zone(utc_impl);
     return true;
   }
 
-  // Then check, under a shared lock, whether the time zone has already
-  // been loaded. This is the common path. TODO: Move to shared_mutex.
+  // Check whether the time zone has already been loaded.
   {
     std::lock_guard<std::mutex> lock(TimeZoneMutex());
     if (time_zone_map != nullptr) {
@@ -70,20 +70,15 @@ bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
     }
   }
 
-  // Now check again, under an exclusive lock.
+  // Load the new time zone (outside the lock).
+  std::unique_ptr<const Impl> new_impl(new Impl(name));
+
+  // Add the new time zone to the map.
   std::lock_guard<std::mutex> lock(TimeZoneMutex());
   if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
   const Impl*& impl = (*time_zone_map)[name];
-  if (impl == nullptr) {
-    // The first thread in loads the new time zone.
-    Impl* new_impl = new Impl(name);
-    new_impl->zone_ = TimeZoneIf::Load(new_impl->name_);
-    if (new_impl->zone_ == nullptr) {
-      delete new_impl;  // free the nascent Impl
-      impl = utc_impl;  // and fallback to UTC
-    } else {
-      impl = new_impl;  // install new time zone
-    }
+  if (impl == nullptr) {  // this thread won any load race
+    impl = new_impl->zone_ ? new_impl.release() : utc_impl;
   }
   *tz = time_zone(impl);
   return impl != utc_impl;
@@ -104,14 +99,11 @@ void time_zone::Impl::ClearTimeZoneMapTestOnly() {
   }
 }
 
-time_zone::Impl::Impl(const std::string& name) : name_(name) {}
+time_zone::Impl::Impl(const std::string& name)
+    : name_(name), zone_(TimeZoneIf::Load(name_)) {}
 
 const time_zone::Impl* time_zone::Impl::UTCImpl() {
-  static Impl* utc_impl = [] {
-    Impl* impl = new Impl("UTC");
-    impl->zone_ = TimeZoneIf::Load(impl->name_);  // never fails
-    return impl;
-  }();
+  static const Impl* utc_impl = new Impl("UTC");  // never fails
   return utc_impl;
 }