1 // 2 // 3 // Copyright 2015 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // 17 // 18 19 #ifndef GRPC_SRC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H 20 #define GRPC_SRC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H 21 22 #include <grpc/impl/connectivity_state.h> 23 #include <grpc/support/port_platform.h> 24 25 #include <atomic> 26 #include <map> 27 #include <memory> 28 #include <utility> 29 30 #include "absl/status/status.h" 31 #include "src/core/lib/debug/trace.h" 32 #include "src/core/util/orphanable.h" 33 #include "src/core/util/work_serializer.h" 34 35 namespace grpc_core { 36 37 // Enum to string conversion. 38 const char* ConnectivityStateName(grpc_connectivity_state state); 39 40 // Interface for watching connectivity state. 41 // Subclasses must implement the Notify() method. 42 // 43 // Note: Most callers will want to use 44 // AsyncConnectivityStateWatcherInterface instead. 45 class ConnectivityStateWatcherInterface 46 : public InternallyRefCounted<ConnectivityStateWatcherInterface> { 47 public: 48 ~ConnectivityStateWatcherInterface() override = default; 49 50 // Notifies the watcher that the state has changed to new_state. 51 virtual void Notify(grpc_connectivity_state new_state, 52 const absl::Status& status) = 0; 53 Orphan()54 void Orphan() override { Unref(); } 55 }; 56 57 // An alternative watcher interface that performs notifications via an 58 // asynchronous callback scheduled on the ExecCtx. 59 // Subclasses must implement the OnConnectivityStateChange() method. 60 class AsyncConnectivityStateWatcherInterface 61 : public ConnectivityStateWatcherInterface { 62 public: 63 ~AsyncConnectivityStateWatcherInterface() override = default; 64 65 // Schedules a closure on the ExecCtx to invoke 66 // OnConnectivityStateChange() asynchronously. 67 void Notify(grpc_connectivity_state new_state, 68 const absl::Status& status) final; 69 70 protected: 71 class Notifier; 72 73 // If \a work_serializer is nullptr, then the notification will be scheduled 74 // on the ExecCtx. 75 explicit AsyncConnectivityStateWatcherInterface( 76 std::shared_ptr<WorkSerializer> work_serializer = nullptr) work_serializer_(std::move (work_serializer))77 : work_serializer_(std::move(work_serializer)) {} 78 79 // Invoked asynchronously when Notify() is called. 80 virtual void OnConnectivityStateChange(grpc_connectivity_state new_state, 81 const absl::Status& status) = 0; 82 83 private: 84 std::shared_ptr<WorkSerializer> work_serializer_; 85 }; 86 87 // Tracks connectivity state. Maintains a list of watchers that are 88 // notified whenever the state changes. 89 // 90 // Note that once the state becomes SHUTDOWN, watchers will be notified 91 // and then automatically orphaned (i.e., RemoveWatcher() does not need 92 // to be called). 93 class ConnectivityStateTracker { 94 public: 95 explicit ConnectivityStateTracker( 96 const char* name, grpc_connectivity_state state = GRPC_CHANNEL_IDLE, 97 const absl::Status& status = absl::Status()) name_(name)98 : name_(name), state_(state), status_(status) {} 99 100 ~ConnectivityStateTracker(); 101 102 // Adds a watcher. 103 // If the current state is different than initial_state, the watcher 104 // will be notified immediately. Otherwise, it will be notified 105 // whenever the state changes. 106 // Not thread safe; access must be serialized with an external lock. 107 void AddWatcher(grpc_connectivity_state initial_state, 108 OrphanablePtr<ConnectivityStateWatcherInterface> watcher); 109 110 // Removes a watcher. The watcher will be orphaned. 111 // Not thread safe; access must be serialized with an external lock. 112 void RemoveWatcher(ConnectivityStateWatcherInterface* watcher); 113 114 // Sets connectivity state. 115 // Not thread safe; access must be serialized with an external lock. 116 void SetState(grpc_connectivity_state state, const absl::Status& status, 117 const char* reason); 118 119 // Gets the current state. 120 // Thread safe; no need to use an external lock. 121 grpc_connectivity_state state() const; 122 123 // Get the current status. 124 // Not thread safe; access must be serialized with an external lock. status()125 absl::Status status() const { return status_; } 126 127 // Returns the number of watchers. 128 // Not thread safe; access must be serialized with an external lock. NumWatchers()129 size_t NumWatchers() const { return watchers_.size(); } 130 131 private: 132 const char* name_; 133 std::atomic<grpc_connectivity_state> state_{grpc_connectivity_state()}; 134 absl::Status status_; 135 // TODO(roth): Once we can use C++-14 heterogeneous lookups, this can 136 // be a set instead of a map. 137 std::map<ConnectivityStateWatcherInterface*, 138 OrphanablePtr<ConnectivityStateWatcherInterface>> 139 watchers_; 140 }; 141 142 } // namespace grpc_core 143 144 #endif // GRPC_SRC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H 145