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