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/support/port_platform.h> 23 24 #include <atomic> 25 #include <map> 26 #include <memory> 27 #include <utility> 28 29 #include "absl/status/status.h" 30 31 #include <grpc/impl/connectivity_state.h> 32 33 #include "src/core/lib/debug/trace.h" 34 #include "src/core/lib/gprpp/orphanable.h" 35 #include "src/core/lib/gprpp/work_serializer.h" 36 37 namespace grpc_core { 38 39 extern TraceFlag grpc_connectivity_state_trace; 40 41 // Enum to string conversion. 42 const char* ConnectivityStateName(grpc_connectivity_state state); 43 44 // Interface for watching connectivity state. 45 // Subclasses must implement the Notify() method. 46 // 47 // Note: Most callers will want to use 48 // AsyncConnectivityStateWatcherInterface instead. 49 class ConnectivityStateWatcherInterface 50 : public InternallyRefCounted<ConnectivityStateWatcherInterface> { 51 public: 52 ~ConnectivityStateWatcherInterface() override = default; 53 54 // Notifies the watcher that the state has changed to new_state. 55 virtual void Notify(grpc_connectivity_state new_state, 56 const absl::Status& status) = 0; 57 Orphan()58 void Orphan() override { Unref(); } 59 }; 60 61 // An alternative watcher interface that performs notifications via an 62 // asynchronous callback scheduled on the ExecCtx. 63 // Subclasses must implement the OnConnectivityStateChange() method. 64 class AsyncConnectivityStateWatcherInterface 65 : public ConnectivityStateWatcherInterface { 66 public: 67 ~AsyncConnectivityStateWatcherInterface() override = default; 68 69 // Schedules a closure on the ExecCtx to invoke 70 // OnConnectivityStateChange() asynchronously. 71 void Notify(grpc_connectivity_state new_state, 72 const absl::Status& status) final; 73 74 protected: 75 class Notifier; 76 77 // If \a work_serializer is nullptr, then the notification will be scheduled 78 // on the ExecCtx. 79 explicit AsyncConnectivityStateWatcherInterface( 80 std::shared_ptr<WorkSerializer> work_serializer = nullptr) work_serializer_(std::move (work_serializer))81 : work_serializer_(std::move(work_serializer)) {} 82 83 // Invoked asynchronously when Notify() is called. 84 virtual void OnConnectivityStateChange(grpc_connectivity_state new_state, 85 const absl::Status& status) = 0; 86 87 private: 88 std::shared_ptr<WorkSerializer> work_serializer_; 89 }; 90 91 // Tracks connectivity state. Maintains a list of watchers that are 92 // notified whenever the state changes. 93 // 94 // Note that once the state becomes SHUTDOWN, watchers will be notified 95 // and then automatically orphaned (i.e., RemoveWatcher() does not need 96 // to be called). 97 class ConnectivityStateTracker { 98 public: 99 explicit ConnectivityStateTracker( 100 const char* name, grpc_connectivity_state state = GRPC_CHANNEL_IDLE, 101 const absl::Status& status = absl::Status()) name_(name)102 : name_(name), state_(state), status_(status) {} 103 104 ~ConnectivityStateTracker(); 105 106 // Adds a watcher. 107 // If the current state is different than initial_state, the watcher 108 // will be notified immediately. Otherwise, it will be notified 109 // whenever the state changes. 110 // Not thread safe; access must be serialized with an external lock. 111 void AddWatcher(grpc_connectivity_state initial_state, 112 OrphanablePtr<ConnectivityStateWatcherInterface> watcher); 113 114 // Removes a watcher. The watcher will be orphaned. 115 // Not thread safe; access must be serialized with an external lock. 116 void RemoveWatcher(ConnectivityStateWatcherInterface* watcher); 117 118 // Sets connectivity state. 119 // Not thread safe; access must be serialized with an external lock. 120 void SetState(grpc_connectivity_state state, const absl::Status& status, 121 const char* reason); 122 123 // Gets the current state. 124 // Thread safe; no need to use an external lock. 125 grpc_connectivity_state state() const; 126 127 // Get the current status. 128 // Not thread safe; access must be serialized with an external lock. status()129 absl::Status status() const { return status_; } 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