1*14675a02SAndroid Build Coastguard Worker /* 2*14675a02SAndroid Build Coastguard Worker * Copyright 2021 Google LLC 3*14675a02SAndroid Build Coastguard Worker * 4*14675a02SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*14675a02SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*14675a02SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*14675a02SAndroid Build Coastguard Worker * 8*14675a02SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*14675a02SAndroid Build Coastguard Worker * 10*14675a02SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*14675a02SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*14675a02SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*14675a02SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*14675a02SAndroid Build Coastguard Worker * limitations under the License. 15*14675a02SAndroid Build Coastguard Worker */ 16*14675a02SAndroid Build Coastguard Worker 17*14675a02SAndroid Build Coastguard Worker #ifndef FCP_BASE_REENTRANCY_GUARD_H_ 18*14675a02SAndroid Build Coastguard Worker #define FCP_BASE_REENTRANCY_GUARD_H_ 19*14675a02SAndroid Build Coastguard Worker 20*14675a02SAndroid Build Coastguard Worker #include <atomic> 21*14675a02SAndroid Build Coastguard Worker 22*14675a02SAndroid Build Coastguard Worker #include "fcp/base/monitoring.h" 23*14675a02SAndroid Build Coastguard Worker 24*14675a02SAndroid Build Coastguard Worker namespace fcp { 25*14675a02SAndroid Build Coastguard Worker 26*14675a02SAndroid Build Coastguard Worker /** 27*14675a02SAndroid Build Coastguard Worker * ReentrancyGuard class is used to enforce strictly sequential calling pattern. 28*14675a02SAndroid Build Coastguard Worker * Usage pattern: 29*14675a02SAndroid Build Coastguard Worker * 30*14675a02SAndroid Build Coastguard Worker * Status Method(...) { 31*14675a02SAndroid Build Coastguard Worker * ReentrancyGuard guard; 32*14675a02SAndroid Build Coastguard Worker * FCP_RETURN_IF_ERROR(guard.Check(&in_use_)); 33*14675a02SAndroid Build Coastguard Worker * 34*14675a02SAndroid Build Coastguard Worker * // The rest of the method body... 35*14675a02SAndroid Build Coastguard Worker * } 36*14675a02SAndroid Build Coastguard Worker * 37*14675a02SAndroid Build Coastguard Worker * in_use_ above is std::atomic<bool> value stored in the object which methods 38*14675a02SAndroid Build Coastguard Worker * are enforced. 39*14675a02SAndroid Build Coastguard Worker */ 40*14675a02SAndroid Build Coastguard Worker class ReentrancyGuard { 41*14675a02SAndroid Build Coastguard Worker public: Check(std::atomic<bool> * in_use)42*14675a02SAndroid Build Coastguard Worker Status Check(std::atomic<bool>* in_use) { 43*14675a02SAndroid Build Coastguard Worker FCP_CHECK(in_use != nullptr); 44*14675a02SAndroid Build Coastguard Worker bool expected_value = false; 45*14675a02SAndroid Build Coastguard Worker if (!in_use->compare_exchange_strong(expected_value, true)) { 46*14675a02SAndroid Build Coastguard Worker return FCP_STATUS(FAILED_PRECONDITION) 47*14675a02SAndroid Build Coastguard Worker << "Concurrent method calls detected"; 48*14675a02SAndroid Build Coastguard Worker } 49*14675a02SAndroid Build Coastguard Worker 50*14675a02SAndroid Build Coastguard Worker in_use_ = in_use; 51*14675a02SAndroid Build Coastguard Worker return FCP_STATUS(OK); 52*14675a02SAndroid Build Coastguard Worker } 53*14675a02SAndroid Build Coastguard Worker ~ReentrancyGuard()54*14675a02SAndroid Build Coastguard Worker ~ReentrancyGuard() { 55*14675a02SAndroid Build Coastguard Worker if (in_use_ != nullptr) { 56*14675a02SAndroid Build Coastguard Worker in_use_->store(false); 57*14675a02SAndroid Build Coastguard Worker } 58*14675a02SAndroid Build Coastguard Worker } 59*14675a02SAndroid Build Coastguard Worker 60*14675a02SAndroid Build Coastguard Worker private: 61*14675a02SAndroid Build Coastguard Worker // Pointer to atomic boolean value which is owned by the object which methods 62*14675a02SAndroid Build Coastguard Worker // are guarded against reentrancy. This value is set to true when inside 63*14675a02SAndroid Build Coastguard Worker // a method call; otherwise false. 64*14675a02SAndroid Build Coastguard Worker // Note: std::atomic is used here rather than Mutex is emphasise non-blocking 65*14675a02SAndroid Build Coastguard Worker // nature of the implementation. The purpose in_use_ is only to check against 66*14675a02SAndroid Build Coastguard Worker // reentrancy rather than synchronization. 67*14675a02SAndroid Build Coastguard Worker std::atomic<bool>* in_use_ = nullptr; 68*14675a02SAndroid Build Coastguard Worker }; 69*14675a02SAndroid Build Coastguard Worker 70*14675a02SAndroid Build Coastguard Worker } // namespace fcp 71*14675a02SAndroid Build Coastguard Worker 72*14675a02SAndroid Build Coastguard Worker #endif // FCP_BASE_REENTRANCY_GUARD_H_ 73