3 * Copyright 2015 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/support/port_platform.h>
21 #include "src/core/lib/transport/connectivity_state.h"
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/log.h>
27 #include <grpc/support/string_util.h>
29 grpc_core::TraceFlag grpc_connectivity_state_trace(false, "connectivity_state");
31 const char* grpc_connectivity_state_name(grpc_connectivity_state state) {
33 case GRPC_CHANNEL_IDLE:
35 case GRPC_CHANNEL_CONNECTING:
37 case GRPC_CHANNEL_READY:
39 case GRPC_CHANNEL_TRANSIENT_FAILURE:
40 return "TRANSIENT_FAILURE";
41 case GRPC_CHANNEL_SHUTDOWN:
44 GPR_UNREACHABLE_CODE(return "UNKNOWN");
47 void grpc_connectivity_state_init(grpc_connectivity_state_tracker* tracker,
48 grpc_connectivity_state init_state,
50 gpr_atm_no_barrier_store(&tracker->current_state_atm, init_state);
51 tracker->watchers = nullptr;
52 tracker->name = gpr_strdup(name);
55 void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker* tracker) {
57 grpc_connectivity_state_watcher* w;
58 while ((w = tracker->watchers)) {
59 tracker->watchers = w->next;
61 if (GRPC_CHANNEL_SHUTDOWN != *w->current) {
62 *w->current = GRPC_CHANNEL_SHUTDOWN;
63 error = GRPC_ERROR_NONE;
66 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutdown connectivity owner");
68 GRPC_CLOSURE_SCHED(w->notify, error);
71 gpr_free(tracker->name);
74 grpc_connectivity_state grpc_connectivity_state_check(
75 grpc_connectivity_state_tracker* tracker) {
76 grpc_connectivity_state cur = static_cast<grpc_connectivity_state>(
77 gpr_atm_no_barrier_load(&tracker->current_state_atm));
78 if (GRPC_TRACE_FLAG_ENABLED(grpc_connectivity_state_trace)) {
79 gpr_log(GPR_INFO, "CONWATCH: %p %s: get %s", tracker, tracker->name,
80 grpc_connectivity_state_name(cur));
85 bool grpc_connectivity_state_has_watchers(
86 grpc_connectivity_state_tracker* connectivity_state) {
87 return connectivity_state->watchers != nullptr;
90 bool grpc_connectivity_state_notify_on_state_change(
91 grpc_connectivity_state_tracker* tracker, grpc_connectivity_state* current,
92 grpc_closure* notify) {
93 grpc_connectivity_state cur = static_cast<grpc_connectivity_state>(
94 gpr_atm_no_barrier_load(&tracker->current_state_atm));
95 if (GRPC_TRACE_FLAG_ENABLED(grpc_connectivity_state_trace)) {
96 if (current == nullptr) {
97 gpr_log(GPR_INFO, "CONWATCH: %p %s: unsubscribe notify=%p", tracker,
98 tracker->name, notify);
100 gpr_log(GPR_INFO, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker,
101 tracker->name, grpc_connectivity_state_name(*current),
102 grpc_connectivity_state_name(cur), notify);
105 if (current == nullptr) {
106 grpc_connectivity_state_watcher* w = tracker->watchers;
107 if (w != nullptr && w->notify == notify) {
108 GRPC_CLOSURE_SCHED(notify, GRPC_ERROR_CANCELLED);
109 tracker->watchers = w->next;
113 while (w != nullptr) {
114 grpc_connectivity_state_watcher* rm_candidate = w->next;
115 if (rm_candidate != nullptr && rm_candidate->notify == notify) {
116 GRPC_CLOSURE_SCHED(notify, GRPC_ERROR_CANCELLED);
117 w->next = w->next->next;
118 gpr_free(rm_candidate);
125 if (cur != *current) {
127 GRPC_CLOSURE_SCHED(notify, GRPC_ERROR_NONE);
129 grpc_connectivity_state_watcher* w =
130 static_cast<grpc_connectivity_state_watcher*>(gpr_malloc(sizeof(*w)));
131 w->current = current;
133 w->next = tracker->watchers;
134 tracker->watchers = w;
136 return cur == GRPC_CHANNEL_IDLE;
140 void grpc_connectivity_state_set(grpc_connectivity_state_tracker* tracker,
141 grpc_connectivity_state state,
142 const char* reason) {
143 grpc_connectivity_state cur = static_cast<grpc_connectivity_state>(
144 gpr_atm_no_barrier_load(&tracker->current_state_atm));
145 grpc_connectivity_state_watcher* w;
146 if (GRPC_TRACE_FLAG_ENABLED(grpc_connectivity_state_trace)) {
147 gpr_log(GPR_INFO, "SET: %p %s: %s --> %s [%s]", tracker, tracker->name,
148 grpc_connectivity_state_name(cur),
149 grpc_connectivity_state_name(state), reason);
154 GPR_ASSERT(cur != GRPC_CHANNEL_SHUTDOWN);
155 gpr_atm_no_barrier_store(&tracker->current_state_atm, state);
156 while ((w = tracker->watchers) != nullptr) {
158 tracker->watchers = w->next;
159 if (GRPC_TRACE_FLAG_ENABLED(grpc_connectivity_state_trace)) {
160 gpr_log(GPR_INFO, "NOTIFY: %p %s: %p", tracker, tracker->name, w->notify);
162 GRPC_CLOSURE_SCHED(w->notify, GRPC_ERROR_NONE);