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