blob: 7b9e0de7c6d98adc635fe9a7025dcb5f34dab3d9 [file] [log] [blame]
Gabriel Charettef297f012018-01-17 20:59:071// Copyright 2018 The Chromium Authors. All rights reserved.
[email protected]30039e62008-09-08 14:11:132// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Gabriel Charettef297f012018-01-17 20:59:075#include "base/lazy_instance_helpers.h"
[email protected]30039e62008-09-08 14:11:136
7#include "base/at_exit.h"
8#include "base/atomicops.h"
[email protected]ce072a72010-12-31 20:02:169#include "base/threading/platform_thread.h"
[email protected]30039e62008-09-08 14:11:1310
11namespace base {
[email protected]6de0fd1d2011-11-15 13:31:4912namespace internal {
[email protected]30039e62008-09-08 14:11:1313
[email protected]6de0fd1d2011-11-15 13:31:4914bool 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).
Gabriel Charettef297f012018-01-17 20:59:0720 if (subtle::NoBarrier_CompareAndSwap(state, 0, kLazyInstanceStateCreating) ==
21 0) {
[email protected]c1aeaac2010-03-12 15:28:4822 // Caller must create instance
23 return true;
Gabriel Charettef297f012018-01-17 20:59:0724 }
[email protected]1b651d52011-05-16 15:01:5425
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
[email protected]6de0fd1d2011-11-15 13:31:4930 // CompleteLazyInstance().
Bruce Dawsoncdf5fae2018-01-05 22:12:4931 if (subtle::Acquire_Load(state) == kLazyInstanceStateCreating) {
Francois Doray94a0386f2018-01-23 14:18:4632 const base::TimeTicks start = base::TimeTicks::Now();
Bruce Dawsoncdf5fae2018-01-05 22:12:4933 do {
Francois Doray94a0386f2018-01-23 14:18:4634 const base::TimeDelta elapsed = base::TimeTicks::Now() - start;
Bruce Dawsoncdf5fae2018-01-05 22:12:4935 // 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);
[email protected]6de0fd1d2011-11-15 13:31:4944 }
[email protected]c1aeaac2010-03-12 15:28:4845 // Someone else created the instance.
46 return false;
47}
48
[email protected]6de0fd1d2011-11-15 13:31:4949void CompleteLazyInstance(subtle::AtomicWord* state,
50 subtle::AtomicWord new_instance,
Francois Doraya50035b2017-06-12 17:55:5051 void (*destructor)(void*),
52 void* destructor_arg) {
Gabriel Charettef297f012018-01-17 20:59:0753 // 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().
[email protected]6de0fd1d2011-11-15 13:31:4956 subtle::Release_Store(state, new_instance);
[email protected]c1aeaac2010-03-12 15:28:4857
[email protected]c1aeaac2010-03-12 15:28:4858 // Make sure that the lazily instantiated object will get destroyed at exit.
Gabriel Charettef297f012018-01-17 20:59:0759 if (new_instance && destructor)
Francois Doraya50035b2017-06-12 17:55:5060 AtExitManager::RegisterCallback(destructor, destructor_arg);
[email protected]30039e62008-09-08 14:11:1361}
62
[email protected]6de0fd1d2011-11-15 13:31:4963} // namespace internal
[email protected]30039e62008-09-08 14:11:1364} // namespace base