• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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