/* * * Copyright 2015 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #ifndef GRPC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H #define GRPC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H #include #include #include #include "absl/status/status.h" #include #include "src/core/lib/debug/trace.h" #include "src/core/lib/gprpp/atomic.h" #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/work_serializer.h" namespace grpc_core { extern TraceFlag grpc_connectivity_state_trace; // Enum to string conversion. const char* ConnectivityStateName(grpc_connectivity_state state); // Interface for watching connectivity state. // Subclasses must implement the Notify() method. // // Note: Most callers will want to use // AsyncConnectivityStateWatcherInterface instead. class ConnectivityStateWatcherInterface : public InternallyRefCounted { public: ~ConnectivityStateWatcherInterface() override = default; // Notifies the watcher that the state has changed to new_state. virtual void Notify(grpc_connectivity_state new_state, const absl::Status& status) = 0; void Orphan() override { Unref(); } }; // An alternative watcher interface that performs notifications via an // asynchronous callback scheduled on the ExecCtx. // Subclasses must implement the OnConnectivityStateChange() method. class AsyncConnectivityStateWatcherInterface : public ConnectivityStateWatcherInterface { public: ~AsyncConnectivityStateWatcherInterface() override = default; // Schedules a closure on the ExecCtx to invoke // OnConnectivityStateChange() asynchronously. void Notify(grpc_connectivity_state new_state, const absl::Status& status) final; protected: class Notifier; // If \a work_serializer is nullptr, then the notification will be scheduled // on the ExecCtx. explicit AsyncConnectivityStateWatcherInterface( std::shared_ptr work_serializer = nullptr) : work_serializer_(std::move(work_serializer)) {} // Invoked asynchronously when Notify() is called. virtual void OnConnectivityStateChange(grpc_connectivity_state new_state, const absl::Status& status) = 0; private: std::shared_ptr work_serializer_; }; // Tracks connectivity state. Maintains a list of watchers that are // notified whenever the state changes. // // Note that once the state becomes SHUTDOWN, watchers will be notified // and then automatically orphaned (i.e., RemoveWatcher() does not need // to be called). class ConnectivityStateTracker { public: explicit ConnectivityStateTracker( const char* name, grpc_connectivity_state state = GRPC_CHANNEL_IDLE, const absl::Status& status = absl::Status()) : name_(name), state_(state), status_(status) {} ~ConnectivityStateTracker(); // Adds a watcher. // If the current state is different than initial_state, the watcher // will be notified immediately. Otherwise, it will be notified // whenever the state changes. // Not thread safe; access must be serialized with an external lock. void AddWatcher(grpc_connectivity_state initial_state, OrphanablePtr watcher); // Removes a watcher. The watcher will be orphaned. // Not thread safe; access must be serialized with an external lock. void RemoveWatcher(ConnectivityStateWatcherInterface* watcher); // Sets connectivity state. // Not thread safe; access must be serialized with an external lock. void SetState(grpc_connectivity_state state, const absl::Status& status, const char* reason); // Gets the current state. // Thread safe; no need to use an external lock. grpc_connectivity_state state() const; // Get the current status. // Not thread safe; access must be serialized with an external lock. absl::Status status() const { return status_; } private: const char* name_; Atomic state_; absl::Status status_; // TODO(roth): Once we can use C++-14 heterogeneous lookups, this can // be a set instead of a map. std::map> watchers_; }; } // namespace grpc_core #endif /* GRPC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H */