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