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