blob: c6b274a5dad256a7b6591157050b72607d9851e4 [file] [log] [blame]
Craig Tillerc7b5f762015-06-27 11:48:42 -07001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Craig Tillerc7b5f762015-06-27 11:48:42 -07004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
Craig Tiller9533d042016-03-25 17:11:06 -070034#include "src/core/lib/transport/connectivity_state.h"
Craig Tiller5795da72015-09-17 15:27:13 -070035
36#include <string.h>
37
Craig Tillerc7b5f762015-06-27 11:48:42 -070038#include <grpc/support/alloc.h>
Craig Tiller98465032015-06-29 14:36:42 -070039#include <grpc/support/log.h>
Craig Tiller1ada6ad2015-07-16 16:19:14 -070040#include <grpc/support/string_util.h>
41
42int grpc_connectivity_state_trace = 0;
43
Craig Tillera82950e2015-09-22 12:33:20 -070044const char *grpc_connectivity_state_name(grpc_connectivity_state state) {
45 switch (state) {
Craig Tiller03dc6552015-07-17 23:12:34 -070046 case GRPC_CHANNEL_IDLE:
47 return "IDLE";
48 case GRPC_CHANNEL_CONNECTING:
49 return "CONNECTING";
50 case GRPC_CHANNEL_READY:
51 return "READY";
52 case GRPC_CHANNEL_TRANSIENT_FAILURE:
53 return "TRANSIENT_FAILURE";
54 case GRPC_CHANNEL_FATAL_FAILURE:
55 return "FATAL_FAILURE";
Craig Tillera82950e2015-09-22 12:33:20 -070056 }
Craig Tiller179e6fe2015-12-09 11:09:47 -080057 GPR_UNREACHABLE_CODE(return "UNKNOWN");
Craig Tiller1ada6ad2015-07-16 16:19:14 -070058}
Craig Tillerc7b5f762015-06-27 11:48:42 -070059
Craig Tillera82950e2015-09-22 12:33:20 -070060void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
61 grpc_connectivity_state init_state,
62 const char *name) {
Craig Tiller08a1cf82015-06-29 09:37:52 -070063 tracker->current_state = init_state;
64 tracker->watchers = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -070065 tracker->name = gpr_strdup(name);
Craig Tillerc7b5f762015-06-27 11:48:42 -070066}
67
Craig Tillera82950e2015-09-22 12:33:20 -070068void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx,
69 grpc_connectivity_state_tracker *tracker) {
Craig Tillerf51457b2016-05-03 17:06:32 -070070 grpc_error *error;
Craig Tillerc7b5f762015-06-27 11:48:42 -070071 grpc_connectivity_state_watcher *w;
Craig Tiller804ff712016-05-05 16:25:40 -070072 grpc_error_unref(tracker->current_error);
Craig Tillera82950e2015-09-22 12:33:20 -070073 while ((w = tracker->watchers)) {
74 tracker->watchers = w->next;
Craig Tillerc7b5f762015-06-27 11:48:42 -070075
Craig Tillera82950e2015-09-22 12:33:20 -070076 if (GRPC_CHANNEL_FATAL_FAILURE != *w->current) {
77 *w->current = GRPC_CHANNEL_FATAL_FAILURE;
Craig Tillerf51457b2016-05-03 17:06:32 -070078 error = GRPC_ERROR_NONE;
Craig Tillera82950e2015-09-22 12:33:20 -070079 } else {
Craig Tillerf51457b2016-05-03 17:06:32 -070080 error = GRPC_ERROR_CREATE("Shutdown connectivity owner");
Craig Tiller08a1cf82015-06-29 09:37:52 -070081 }
Craig Tillerf51457b2016-05-03 17:06:32 -070082 grpc_exec_ctx_push(exec_ctx, w->notify, error, NULL);
Craig Tillera82950e2015-09-22 12:33:20 -070083 gpr_free(w);
84 }
85 gpr_free(tracker->name);
Craig Tillerc7b5f762015-06-27 11:48:42 -070086}
87
Craig Tillera82950e2015-09-22 12:33:20 -070088grpc_connectivity_state grpc_connectivity_state_check(
Craig Tiller804ff712016-05-05 16:25:40 -070089 grpc_connectivity_state_tracker *tracker, grpc_error **error) {
Craig Tillera82950e2015-09-22 12:33:20 -070090 if (grpc_connectivity_state_trace) {
Craig Tiller53ee0402015-11-25 09:07:09 -080091 gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
Craig Tillera82950e2015-09-22 12:33:20 -070092 grpc_connectivity_state_name(tracker->current_state));
93 }
Craig Tiller804ff712016-05-05 16:25:40 -070094 if (error != NULL) {
95 *error = grpc_error_ref(tracker->current_error);
96 }
Craig Tiller08a1cf82015-06-29 09:37:52 -070097 return tracker->current_state;
Craig Tillerc7b5f762015-06-27 11:48:42 -070098}
99
Craig Tillera82950e2015-09-22 12:33:20 -0700100int grpc_connectivity_state_notify_on_state_change(
101 grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
102 grpc_connectivity_state *current, grpc_closure *notify) {
103 if (grpc_connectivity_state_trace) {
Craig Tiller48613042015-11-29 14:45:11 -0800104 if (current == NULL) {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800105 gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker,
106 tracker->name, notify);
Craig Tiller48613042015-11-29 14:45:11 -0800107 } else {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800108 gpr_log(GPR_DEBUG, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker,
109 tracker->name, grpc_connectivity_state_name(*current),
Craig Tiller48613042015-11-29 14:45:11 -0800110 grpc_connectivity_state_name(tracker->current_state), notify);
David Garcia Quintas3b147812015-09-30 15:59:52 -0700111 }
David Garcia Quintas3b147812015-09-30 15:59:52 -0700112 }
Craig Tiller48613042015-11-29 14:45:11 -0800113 if (current == NULL) {
114 grpc_connectivity_state_watcher *w = tracker->watchers;
115 if (w != NULL && w->notify == notify) {
Craig Tillerf51457b2016-05-03 17:06:32 -0700116 grpc_exec_ctx_push(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL);
Craig Tiller48613042015-11-29 14:45:11 -0800117 tracker->watchers = w->next;
118 gpr_free(w);
119 return 0;
120 }
121 while (w != NULL) {
122 grpc_connectivity_state_watcher *rm_candidate = w->next;
123 if (rm_candidate != NULL && rm_candidate->notify == notify) {
Craig Tillerf51457b2016-05-03 17:06:32 -0700124 grpc_exec_ctx_push(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL);
Craig Tiller48613042015-11-29 14:45:11 -0800125 w->next = w->next->next;
126 gpr_free(rm_candidate);
127 return 0;
128 }
129 w = w->next;
130 }
131 return 0;
132 } else {
133 if (tracker->current_state != *current) {
134 *current = tracker->current_state;
Craig Tillerf51457b2016-05-03 17:06:32 -0700135 grpc_exec_ctx_push(exec_ctx, notify, GRPC_ERROR_NONE, NULL);
Craig Tiller48613042015-11-29 14:45:11 -0800136 } else {
137 grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
138 w->current = current;
139 w->notify = notify;
140 w->next = tracker->watchers;
141 tracker->watchers = w;
142 }
143 return tracker->current_state == GRPC_CHANNEL_IDLE;
144 }
David Garcia Quintas3b147812015-09-30 15:59:52 -0700145}
146
Craig Tillera82950e2015-09-22 12:33:20 -0700147void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
148 grpc_connectivity_state_tracker *tracker,
149 grpc_connectivity_state state,
Craig Tiller804ff712016-05-05 16:25:40 -0700150 grpc_error *error, const char *reason) {
Craig Tiller000cd8f2015-09-18 07:20:29 -0700151 grpc_connectivity_state_watcher *w;
Craig Tillera82950e2015-09-22 12:33:20 -0700152 if (grpc_connectivity_state_trace) {
Craig Tiller53ee0402015-11-25 09:07:09 -0800153 gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s]", tracker, tracker->name,
Craig Tillera82950e2015-09-22 12:33:20 -0700154 grpc_connectivity_state_name(tracker->current_state),
155 grpc_connectivity_state_name(state), reason);
156 }
Craig Tiller804ff712016-05-05 16:25:40 -0700157 switch (state) {
158 case GRPC_CHANNEL_CONNECTING:
159 case GRPC_CHANNEL_IDLE:
160 case GRPC_CHANNEL_READY:
161 GPR_ASSERT(error == GRPC_ERROR_NONE);
162 break;
163 case GRPC_CHANNEL_FATAL_FAILURE:
164 case GRPC_CHANNEL_TRANSIENT_FAILURE:
165 GPR_ASSERT(error != GRPC_ERROR_NONE);
166 break;
167 }
168 grpc_error_unref(tracker->current_error);
169 tracker->current_error = error;
Craig Tillera82950e2015-09-22 12:33:20 -0700170 if (tracker->current_state == state) {
171 return;
172 }
173 GPR_ASSERT(tracker->current_state != GRPC_CHANNEL_FATAL_FAILURE);
Craig Tillerc7b5f762015-06-27 11:48:42 -0700174 tracker->current_state = state;
Craig Tillera82950e2015-09-22 12:33:20 -0700175 while ((w = tracker->watchers) != NULL) {
176 *w->current = tracker->current_state;
177 tracker->watchers = w->next;
Craig Tiller804ff712016-05-05 16:25:40 -0700178 grpc_exec_ctx_push(exec_ctx, w->notify,
179 grpc_error_ref(tracker->current_error), NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700180 gpr_free(w);
181 }
Craig Tillerff3ae682015-06-29 17:44:04 -0700182}