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