• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/lazy_instance_helpers.h"
6 
7 #include "base/at_exit.h"
8 #include "base/atomicops.h"
9 #include "base/threading/platform_thread.h"
10 
11 namespace base {
12 namespace internal {
13 
NeedsLazyInstance(subtle::AtomicWord * state)14 bool NeedsLazyInstance(subtle::AtomicWord* state) {
15   // Try to create the instance, if we're the first, will go from 0 to
16   // kLazyInstanceStateCreating, otherwise we've already been beaten here.
17   // The memory access has no memory ordering as state 0 and
18   // kLazyInstanceStateCreating have no associated data (memory barriers are
19   // all about ordering of memory accesses to *associated* data).
20   if (subtle::NoBarrier_CompareAndSwap(state, 0, kLazyInstanceStateCreating) ==
21       0) {
22     // Caller must create instance
23     return true;
24   }
25 
26   // It's either in the process of being created, or already created. Spin.
27   // The load has acquire memory ordering as a thread which sees
28   // state_ == STATE_CREATED needs to acquire visibility over
29   // the associated data (buf_). Pairing Release_Store is in
30   // CompleteLazyInstance().
31   if (subtle::Acquire_Load(state) == kLazyInstanceStateCreating) {
32     const base::TimeTicks start = base::TimeTicks::Now();
33     do {
34       const base::TimeDelta elapsed = base::TimeTicks::Now() - start;
35       // Spin with YieldCurrentThread for at most one ms - this ensures maximum
36       // responsiveness. After that spin with Sleep(1ms) so that we don't burn
37       // excessive CPU time - this also avoids infinite loops due to priority
38       // inversions (https://crbug.com/797129).
39       if (elapsed < TimeDelta::FromMilliseconds(1))
40         PlatformThread::YieldCurrentThread();
41       else
42         PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
43     } while (subtle::Acquire_Load(state) == kLazyInstanceStateCreating);
44   }
45   // Someone else created the instance.
46   return false;
47 }
48 
CompleteLazyInstance(subtle::AtomicWord * state,subtle::AtomicWord new_instance,void (* destructor)(void *),void * destructor_arg)49 void CompleteLazyInstance(subtle::AtomicWord* state,
50                           subtle::AtomicWord new_instance,
51                           void (*destructor)(void*),
52                           void* destructor_arg) {
53   // Instance is created, go from CREATING to CREATED (or reset it if
54   // |new_instance| is null). Releases visibility over |private_buf_| to
55   // readers. Pairing Acquire_Load is in NeedsLazyInstance().
56   subtle::Release_Store(state, new_instance);
57 
58   // Make sure that the lazily instantiated object will get destroyed at exit.
59   if (new_instance && destructor)
60     AtExitManager::RegisterCallback(destructor, destructor_arg);
61 }
62 
63 }  // namespace internal
64 }  // namespace base
65