2 * Copyright 2014 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.
21 #include <folly/SmallLocks.h>
23 namespace folly { namespace wangle { namespace detail {
25 /// Finite State Machine helper base class.
26 /// Inherit from this.
27 /// For best results, use an "enum class" for Enum.
31 // I am not templatizing this because folly::MicroSpinLock needs to be
32 // zero-initialized (or call init) which isn't generic enough for something
33 // that behaves like std::mutex. :(
34 using Mutex = folly::MicroSpinLock;
37 // This might not be necessary for all Enum types, e.g. anything
38 // that is atomically updated in practice on this CPU and there's no risk
39 // of returning a bogus state because of tearing.
40 // An optimization would be to use a static conditional on the Enum type.
41 std::atomic<Enum> state_;
44 FSM(Enum startState) : state_(startState) {}
46 Enum getState() const {
47 return state_.load(std::memory_order_relaxed);
50 // transition from state A to state B, and then perform action while the
51 // lock is still held.
53 // If the current state is not A, returns false.
55 bool updateState(Enum A, Enum B, F const& action) {
56 std::lock_guard<Mutex> lock(mutex_);
57 if (state_ != A) return false;
68 #define FSM_UPDATE2(a, b, action, unlocked_code) \
70 if (!updateState((a), (b), (action))) goto retry; \
74 #define FSM_UPDATE(a, b, action) FSM_UPDATE2((a), (b), (action), {})