Bug 1067513 - Import updated base::LazyInstance from upstream. r=bsmedberg, a=sledru
authorJim Chen <nchen@mozilla.com>
Wed, 17 Sep 2014 12:59:21 -0400
changeset 216808 d6aa05e710f2
parent 216807 ae87b325401d
child 216809 91f4e2aed979
push id3921
push userryanvm@gmail.com
push date2014-09-22 15:03 +0000
treeherdermozilla-beta@f8eec8fe1b2b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg, sledru
bugs1067513, 28749, 64930, 65298, 82122
milestone33.0
Bug 1067513 - Import updated base::LazyInstance from upstream. r=bsmedberg, a=sledru This patch imports the following files from upstream, and adapts them to the in-tree fork at ipc/chromium, * src/base/lazy_instance.cc * src/base/lazy_instance.h The updated code fixes several issues with LazyInstance [1-4]. LazyInstance usages are also updated to reflect changes in the class interface. [1] https://code.google.com/p/chromium/issues/detail?id=28749 [2] https://code.google.com/p/chromium/issues/detail?id=64930 [3] https://code.google.com/p/chromium/issues/detail?id=65298 [4] https://code.google.com/p/chromium/issues/detail?id=82122
ipc/chromium/src/base/idle_timer.cc
ipc/chromium/src/base/lazy_instance.cc
ipc/chromium/src/base/lazy_instance.h
ipc/chromium/src/base/message_loop.cc
ipc/chromium/src/base/thread.cc
ipc/chromium/src/chrome/common/ipc_sync_channel.cc
ipc/chromium/src/chrome/common/notification_service.cc
--- a/ipc/chromium/src/base/idle_timer.cc
+++ b/ipc/chromium/src/base/idle_timer.cc
@@ -84,17 +84,17 @@ class IdleState {
  private:
   bool have_idle_info_;
   ThreadLocalPointer<XScreenSaverInfo> idle_info_;
 
   DISALLOW_COPY_AND_ASSIGN(IdleState);
 };
 
 bool OSIdleTimeSource(int32_t* milliseconds_interval_since_last_event) {
-  static LazyInstance<IdleState> state_instance(base::LINKER_INITIALIZED);
+  static LazyInstance<IdleState> state_instance = LAZY_INSTANCE_INITIALIZER;
   IdleState* state = state_instance.Pointer();
   int32_t idle_time = state->IdleTime();
   if (0 < idle_time) {
     *milliseconds_interval_since_last_event = idle_time;
     return true;
   }
   return false;
 }
--- a/ipc/chromium/src/base/lazy_instance.cc
+++ b/ipc/chromium/src/base/lazy_instance.cc
@@ -1,34 +1,55 @@
-// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/lazy_instance.h"
 
 #include "base/at_exit.h"
 #include "base/atomicops.h"
 #include "base/basictypes.h"
 #include "base/platform_thread.h"
 
 namespace base {
+namespace internal {
 
-void LazyInstanceHelper::EnsureInstance(void* instance,
-                                        void (*ctor)(void*),
-                                        void (*dtor)(void*)) {
-  // Try to create the instance, if we're the first, will go from EMPTY
-  // to CREATING, otherwise we've already been beaten here.
-  if (base::subtle::Acquire_CompareAndSwap(
-          &state_, STATE_EMPTY, STATE_CREATING) == STATE_EMPTY) {
-    // Created the instance in the space provided by |instance|.
-    ctor(instance);
-    // Instance is created, go from CREATING to CREATED.
-    base::subtle::Release_Store(&state_, STATE_CREATED);
-    // Register the destructor callback with AtExitManager.
-    base::AtExitManager::RegisterCallback(dtor, instance);
-  } else {
-    // It's either in the process of being created, or already created.  Spin.
-    while (base::subtle::NoBarrier_Load(&state_) != STATE_CREATED)
-      PlatformThread::YieldCurrentThread();
+// TODO(joth): This function could be shared with Singleton, in place of its
+// WaitForInstance() call.
+bool NeedsLazyInstance(subtle::AtomicWord* state) {
+  // Try to create the instance, if we're the first, will go from 0 to
+  // kLazyInstanceStateCreating, otherwise we've already been beaten here.
+  // The memory access has no memory ordering as state 0 and
+  // kLazyInstanceStateCreating have no associated data (memory barriers are
+  // all about ordering of memory accesses to *associated* data).
+  if (subtle::NoBarrier_CompareAndSwap(state, 0,
+                                       kLazyInstanceStateCreating) == 0)
+    // Caller must create instance
+    return true;
+
+  // It's either in the process of being created, or already created. Spin.
+  // The load has acquire memory ordering as a thread which sees
+  // state_ == STATE_CREATED needs to acquire visibility over
+  // the associated data (buf_). Pairing Release_Store is in
+  // CompleteLazyInstance().
+  while (subtle::Acquire_Load(state) == kLazyInstanceStateCreating) {
+    PlatformThread::YieldCurrentThread();
   }
+  // Someone else created the instance.
+  return false;
 }
 
+void CompleteLazyInstance(subtle::AtomicWord* state,
+                          subtle::AtomicWord new_instance,
+                          void* lazy_instance,
+                          void (*dtor)(void*)) {
+  // Instance is created, go from CREATING to CREATED.
+  // Releases visibility over private_buf_ to readers. Pairing Acquire_Load's
+  // are in NeedsInstance() and Pointer().
+  subtle::Release_Store(state, new_instance);
+
+  // Make sure that the lazily instantiated object will get destroyed at exit.
+  if (dtor)
+    AtExitManager::RegisterCallback(dtor, lazy_instance);
+}
+
+}  // namespace internal
 }  // namespace base
--- a/ipc/chromium/src/base/lazy_instance.h
+++ b/ipc/chromium/src/base/lazy_instance.h
@@ -1,110 +1,195 @@
-// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 // The LazyInstance<Type, Traits> class manages a single instance of Type,
 // which will be lazily created on the first time it's accessed.  This class is
 // useful for places you would normally use a function-level static, but you
 // need to have guaranteed thread-safety.  The Type constructor will only ever
 // be called once, even if two threads are racing to create the object.  Get()
 // and Pointer() will always return the same, completely initialized instance.
 // When the instance is constructed it is registered with AtExitManager.  The
 // destructor will be called on program exit.
 //
 // LazyInstance is completely thread safe, assuming that you create it safely.
 // The class was designed to be POD initialized, so it shouldn't require a
 // static constructor.  It really only makes sense to declare a LazyInstance as
-// a global variable using the base::LinkerInitialized constructor.
+// a global variable using the LAZY_INSTANCE_INITIALIZER initializer.
 //
 // LazyInstance is similar to Singleton, except it does not have the singleton
 // property.  You can have multiple LazyInstance's of the same type, and each
 // will manage a unique instance.  It also preallocates the space for Type, as
 // to avoid allocating the Type instance on the heap.  This may help with the
 // performance of creating the instance, and reducing heap fragmentation.  This
 // requires that Type be a complete type so we can determine the size.
 //
 // Example usage:
-//   static LazyInstance<MyClass> my_instance(base::LINKER_INITIALIZED);
+//   static LazyInstance<MyClass> my_instance = LAZY_INSTANCE_INITIALIZER;
 //   void SomeMethod() {
 //     my_instance.Get().SomeMethod();  // MyClass::SomeMethod()
 //
 //     MyClass* ptr = my_instance.Pointer();
 //     ptr->DoDoDo();  // MyClass::DoDoDo
 //   }
 
 #ifndef BASE_LAZY_INSTANCE_H_
 #define BASE_LAZY_INSTANCE_H_
 
+#include <new>  // For placement new.
+
 #include "base/atomicops.h"
 #include "base/basictypes.h"
+#include "base/logging.h"
+
+#include "mozilla/Alignment.h"
+
+// LazyInstance uses its own struct initializer-list style static
+// initialization, as base's LINKER_INITIALIZED requires a constructor and on
+// some compilers (notably gcc 4.4) this still ends up needing runtime
+// initialization.
+#define LAZY_INSTANCE_INITIALIZER {0}
 
 namespace base {
 
 template <typename Type>
 struct DefaultLazyInstanceTraits {
-  static void New(void* instance) {
+  static const bool kRegisterOnExit = true;
+
+  static Type* New(void* instance) {
+    DCHECK_EQ(reinterpret_cast<uintptr_t>(instance) & (MOZ_ALIGNOF(Type) - 1), 0u)
+        << ": Bad boy, the buffer passed to placement new is not aligned!\n"
+        "This may break some stuff like SSE-based optimizations assuming the "
+        "<Type> objects are word aligned.";
     // Use placement new to initialize our instance in our preallocated space.
     // The parenthesis is very important here to force POD type initialization.
-    new (instance) Type();
+    return new (instance) Type();
   }
-  static void Delete(void* instance) {
+  static void Delete(Type* instance) {
     // Explicitly call the destructor.
-    reinterpret_cast<Type*>(instance)->~Type();
+    instance->~Type();
   }
 };
 
-// We pull out some of the functionality into a non-templated base, so that we
+// We pull out some of the functionality into non-templated functions, so we
 // can implement the more complicated pieces out of line in the .cc file.
-class LazyInstanceHelper {
- protected:
-  enum {
-    STATE_EMPTY    = 0,
-    STATE_CREATING = 1,
-    STATE_CREATED  = 2
-  };
+namespace internal {
 
-  explicit LazyInstanceHelper(LinkerInitialized x) { /* state_ is 0 */ }
-  // Declaring a destructor (even if it's empty) will cause MSVC to register a
-  // static initializer to register the empty destructor with atexit().
+// Use LazyInstance<T>::Leaky for a less-verbose call-site typedef; e.g.:
+// base::LazyInstance<T>::Leaky my_leaky_lazy_instance;
+// instead of:
+// base::LazyInstance<T, base::internal::LeakyLazyInstanceTraits<T> >
+// my_leaky_lazy_instance;
+// (especially when T is MyLongTypeNameImplClientHolderFactory).
+// Only use this internal::-qualified verbose form to extend this traits class
+// (depending on its implementation details).
+template <typename Type>
+struct LeakyLazyInstanceTraits {
+  static const bool kRegisterOnExit = false;
 
-  // Make sure that instance is created, creating or waiting for it to be
-  // created if neccessary.  Constructs with |ctor| in the space provided by
-  // |instance| and registers dtor for destruction at program exit.
-  void EnsureInstance(void* instance, void (*ctor)(void*), void (*dtor)(void*));
-
-  base::subtle::Atomic32 state_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(LazyInstanceHelper);
+  static Type* New(void* instance) {
+    return DefaultLazyInstanceTraits<Type>::New(instance);
+  }
+  static void Delete(Type* instance) {
+  }
 };
 
+// Our AtomicWord doubles as a spinlock, where a value of
+// kBeingCreatedMarker means the spinlock is being held for creation.
+static const subtle::AtomicWord kLazyInstanceStateCreating = 1;
+
+// Check if instance needs to be created. If so return true otherwise
+// if another thread has beat us, wait for instance to be created and
+// return false.
+bool NeedsLazyInstance(subtle::AtomicWord* state);
+
+// After creating an instance, call this to register the dtor to be called
+// at program exit and to update the atomic state to hold the |new_instance|
+void CompleteLazyInstance(subtle::AtomicWord* state,
+                                      subtle::AtomicWord new_instance,
+                                      void* lazy_instance,
+                                      void (*dtor)(void*));
+
+}  // namespace internal
+
 template <typename Type, typename Traits = DefaultLazyInstanceTraits<Type> >
-class LazyInstance : public LazyInstanceHelper {
+class LazyInstance {
  public:
-  explicit LazyInstance(LinkerInitialized x) : LazyInstanceHelper(x) { }
-  // Declaring a destructor (even if it's empty) will cause MSVC to register a
-  // static initializer to register the empty destructor with atexit().
+  // Do not define a destructor, as doing so makes LazyInstance a
+  // non-POD-struct. We don't want that because then a static initializer will
+  // be created to register the (empty) destructor with atexit() under MSVC, for
+  // example. We handle destruction of the contained Type class explicitly via
+  // the OnExit member function, where needed.
+  // ~LazyInstance() {}
+
+  // Convenience typedef to avoid having to repeat Type for leaky lazy
+  // instances.
+  typedef LazyInstance<Type, internal::LeakyLazyInstanceTraits<Type> > Leaky;
 
   Type& Get() {
     return *Pointer();
   }
 
   Type* Pointer() {
-    Type* instance = reinterpret_cast<Type*>(&buf_);
+    // If any bit in the created mask is true, the instance has already been
+    // fully constructed.
+    static const subtle::AtomicWord kLazyInstanceCreatedMask =
+        ~internal::kLazyInstanceStateCreating;
 
     // We will hopefully have fast access when the instance is already created.
-    if (base::subtle::NoBarrier_Load(&state_) != STATE_CREATED)
-      EnsureInstance(instance, Traits::New, Traits::Delete);
+    // Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating
+    // at most once, the load is taken out of NeedsInstance() as a fast-path.
+    // The load has acquire memory ordering as a thread which sees
+    // private_instance_ > creating needs to acquire visibility over
+    // the associated data (private_buf_). Pairing Release_Store is in
+    // CompleteLazyInstance().
+    subtle::AtomicWord value = subtle::Acquire_Load(&private_instance_);
+    if (!(value & kLazyInstanceCreatedMask) &&
+        internal::NeedsLazyInstance(&private_instance_)) {
+      // Create the instance in the space provided by |private_buf_|.
+      value = reinterpret_cast<subtle::AtomicWord>(
+          Traits::New(private_buf_.addr()));
+      internal::CompleteLazyInstance(&private_instance_, value, this,
+                                     Traits::kRegisterOnExit ? OnExit : NULL);
+    }
 
-    return instance;
+    return instance();
   }
 
+  bool operator==(Type* p) {
+    switch (subtle::NoBarrier_Load(&private_instance_)) {
+      case 0:
+        return p == NULL;
+      case internal::kLazyInstanceStateCreating:
+        return static_cast<void*>(p) == private_buf_.addr();
+      default:
+        return p == instance();
+    }
+  }
+
+  // Effectively private: member data is only public to allow the linker to
+  // statically initialize it and to maintain a POD class. DO NOT USE FROM
+  // OUTSIDE THIS CLASS.
+
+  subtle::AtomicWord private_instance_;
+  // Preallocated space for the Type instance.
+  mozilla::AlignedStorage2<Type> private_buf_;
+
  private:
-  int8_t buf_[sizeof(Type)];  // Preallocate the space for the Type instance.
+  Type* instance() {
+    return reinterpret_cast<Type*>(subtle::NoBarrier_Load(&private_instance_));
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(LazyInstance);
+  // Adapter function for use with AtExit.  This should be called single
+  // threaded, so don't synchronize across threads.
+  // Calling OnExit while the instance is in use by other threads is a mistake.
+  static void OnExit(void* lazy_instance) {
+    LazyInstance<Type, Traits>* me =
+        reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance);
+    Traits::Delete(me->instance());
+    subtle::NoBarrier_Store(&me->private_instance_, 0);
+  }
 };
 
 }  // namespace base
 
 #endif  // BASE_LAZY_INSTANCE_H_
--- a/ipc/chromium/src/base/message_loop.cc
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -38,18 +38,18 @@
 #include "MessagePump.h"
 
 using base::Time;
 using base::TimeDelta;
 using base::TimeTicks;
 
 // A lazily created thread local storage for quick access to a thread's message
 // loop, if one exists.  This should be safe and free of static constructors.
-static base::LazyInstance<base::ThreadLocalPointer<MessageLoop> > lazy_tls_ptr(
-    base::LINKER_INITIALIZED);
+static base::LazyInstance<base::ThreadLocalPointer<MessageLoop> > lazy_tls_ptr =
+    LAZY_INSTANCE_INITIALIZER;
 
 //------------------------------------------------------------------------------
 
 // Logical events for Histogram profiling. Run with -message-loop-histogrammer
 // to get an accounting of messages and actions taken on each thread.
 static const int kTaskRunEvent = 0x1;
 static const int kTimerEvent = 0x2;
 
--- a/ipc/chromium/src/base/thread.cc
+++ b/ipc/chromium/src/base/thread.cc
@@ -53,18 +53,18 @@ Thread::~Thread() {
 }
 
 namespace {
 
 // We use this thread-local variable to record whether or not a thread exited
 // because its Stop method was called.  This allows us to catch cases where
 // MessageLoop::Quit() is called directly, which is unexpected when using a
 // Thread to setup and run a MessageLoop.
-base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool(
-    base::LINKER_INITIALIZED);
+base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool =
+    LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
 
 void Thread::SetThreadWasQuitProperly(bool flag) {
   lazy_tls_bool.Pointer()->Set(flag);
 }
 
 bool Thread::GetThreadWasQuitProperly() {
--- a/ipc/chromium/src/chrome/common/ipc_sync_channel.cc
+++ b/ipc/chromium/src/chrome/common/ipc_sync_channel.cc
@@ -176,17 +176,17 @@ class SyncChannel::ReceivedSyncMsgQueue 
   WaitableEvent dispatch_event_;
   MessageLoop* listener_message_loop_;
   Lock message_lock_;
   bool task_pending_;
   int listener_count_;
 };
 
 base::LazyInstance<base::ThreadLocalPointer<SyncChannel::ReceivedSyncMsgQueue> >
-    SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_(base::LINKER_INITIALIZED);
+  SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_ = LAZY_INSTANCE_INITIALIZER;
 
 SyncChannel::SyncContext::SyncContext(
     Channel::Listener* listener,
     MessageFilter* filter,
     MessageLoop* ipc_thread,
     WaitableEvent* shutdown_event)
     : ChannelProxy::Context(listener, filter, ipc_thread),
       received_sync_msgs_(ReceivedSyncMsgQueue::AddContext()),
--- a/ipc/chromium/src/chrome/common/notification_service.cc
+++ b/ipc/chromium/src/chrome/common/notification_service.cc
@@ -3,17 +3,17 @@
 // found in the LICENSE file.
 
 #include "chrome/common/notification_service.h"
 
 #include "base/lazy_instance.h"
 #include "base/thread_local.h"
 
 static base::LazyInstance<base::ThreadLocalPointer<NotificationService> >
-    lazy_tls_ptr(base::LINKER_INITIALIZED);
+    lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
 
 // static
 NotificationService* NotificationService::current() {
   return lazy_tls_ptr.Pointer()->Get();
 }
 
 // static
 bool NotificationService::HasKey(const NotificationSourceMap& map,