2 * Copyright 2015 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <folly/ThreadLocal.h>
19 #include <folly/experimental/RCUUtils.h>
29 return new LocalRefCount(globalCount_);
33 ~RCURefCount() noexcept {
34 assert(state_ == State::GLOBAL);
35 assert(globalCount_.load() == 0);
38 // This can't increment from 0.
39 Int operator++() noexcept {
40 auto& localCount = *localCount_;
42 std::lock_guard<RCUReadLock> lg(RCUReadLock::instance());
44 if (LIKELY(state_ == State::LOCAL)) {
48 } else if (state_ == State::GLOBAL_TRANSITION) {
53 auto globalCount = globalCount_.load();
59 } while (!globalCount_.compare_exchange_weak(globalCount,
62 return globalCount + 1;
66 Int operator--() noexcept {
67 auto& localCount = *localCount_;
69 std::lock_guard<RCUReadLock> lg(RCUReadLock::instance());
71 if (LIKELY(state_ == State::LOCAL)) {
76 auto value = --globalCount_;
78 if (state_ == State::GLOBAL) {
87 Int operator*() const {
88 std::lock_guard<RCUReadLock> lg(RCUReadLock::instance());
90 if (state_ == State::GLOBAL) {
97 void useGlobal() noexcept {
98 state_ = State::GLOBAL_TRANSITION;
101 // At this point everyone is using the global count
103 auto accessor = localCount_.accessAllThreads();
104 for (auto& count : accessor) {
108 state_ = State::GLOBAL;
111 // After this ++ or -- can return 0.
115 using AtomicInt = std::atomic<Int>;
123 class LocalRefCount {
125 explicit LocalRefCount(AtomicInt& globalCount) :
127 globalCount_(globalCount) {
136 globalCount_ += count_;
150 AtomicInt& globalCount_;
153 std::atomic<State> state_{State::LOCAL};
154 folly::ThreadLocal<LocalRefCount, RCURefCount> localCount_;
155 std::atomic<int64_t> globalCount_{1};