2 * Copyright 2016 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());
43 auto state = state_.load();
45 if (LIKELY(state == State::LOCAL)) {
49 } else if (state == State::GLOBAL_TRANSITION) {
54 auto globalCount = globalCount_.load();
60 } while (!globalCount_.compare_exchange_weak(globalCount,
63 return globalCount + 1;
67 Int operator--() noexcept {
68 auto& localCount = *localCount_;
70 std::lock_guard<RCUReadLock> lg(RCUReadLock::instance());
71 auto state = state_.load();
73 if (LIKELY(state == State::LOCAL)) {
78 auto value = --globalCount_;
80 if (state == State::GLOBAL) {
89 Int operator*() const {
90 std::lock_guard<RCUReadLock> lg(RCUReadLock::instance());
92 if (state_ == State::GLOBAL) {
99 void useGlobal() noexcept {
100 state_ = State::GLOBAL_TRANSITION;
103 // At this point everyone is using the global count
105 auto accessor = localCount_.accessAllThreads();
106 for (auto& count : accessor) {
110 state_ = State::GLOBAL;
113 // After this ++ or -- can return 0.
117 using AtomicInt = std::atomic<Int>;
125 class LocalRefCount {
127 explicit LocalRefCount(AtomicInt& globalCount) :
129 globalCount_(globalCount) {
138 globalCount_ += count_;
152 AtomicInt& globalCount_;
155 std::atomic<State> state_{State::LOCAL};
156 folly::ThreadLocal<LocalRefCount, RCURefCount> localCount_;
157 std::atomic<int64_t> globalCount_{1};