OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * |
| 3 * Copyright 2015-2016, Google Inc. |
| 4 * 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 |
| 34 #include "src/core/surface/channel.h" |
| 35 |
| 36 #include <grpc/support/alloc.h> |
| 37 #include <grpc/support/log.h> |
| 38 |
| 39 #include "src/core/channel/client_channel.h" |
| 40 #include "src/core/channel/client_uchannel.h" |
| 41 #include "src/core/iomgr/timer.h" |
| 42 #include "src/core/surface/api_trace.h" |
| 43 #include "src/core/surface/completion_queue.h" |
| 44 |
| 45 grpc_connectivity_state grpc_channel_check_connectivity_state( |
| 46 grpc_channel *channel, int try_to_connect) { |
| 47 /* forward through to the underlying client channel */ |
| 48 grpc_channel_element *client_channel_elem = |
| 49 grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); |
| 50 grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
| 51 grpc_connectivity_state state; |
| 52 GRPC_API_TRACE( |
| 53 "grpc_channel_check_connectivity_state(channel=%p, try_to_connect=%d)", 2, |
| 54 (channel, try_to_connect)); |
| 55 if (client_channel_elem->filter == &grpc_client_channel_filter) { |
| 56 state = grpc_client_channel_check_connectivity_state( |
| 57 &exec_ctx, client_channel_elem, try_to_connect); |
| 58 grpc_exec_ctx_finish(&exec_ctx); |
| 59 return state; |
| 60 } |
| 61 if (client_channel_elem->filter == &grpc_client_uchannel_filter) { |
| 62 state = grpc_client_uchannel_check_connectivity_state( |
| 63 &exec_ctx, client_channel_elem, try_to_connect); |
| 64 grpc_exec_ctx_finish(&exec_ctx); |
| 65 return state; |
| 66 } |
| 67 gpr_log(GPR_ERROR, |
| 68 "grpc_channel_check_connectivity_state called on something that is " |
| 69 "not a (u)client channel, but '%s'", |
| 70 client_channel_elem->filter->name); |
| 71 grpc_exec_ctx_finish(&exec_ctx); |
| 72 return GRPC_CHANNEL_FATAL_FAILURE; |
| 73 } |
| 74 |
| 75 typedef enum { |
| 76 WAITING, |
| 77 CALLING_BACK, |
| 78 CALLING_BACK_AND_FINISHED, |
| 79 CALLED_BACK |
| 80 } callback_phase; |
| 81 |
| 82 typedef struct { |
| 83 gpr_mu mu; |
| 84 callback_phase phase; |
| 85 int success; |
| 86 grpc_closure on_complete; |
| 87 grpc_timer alarm; |
| 88 grpc_connectivity_state state; |
| 89 grpc_completion_queue *cq; |
| 90 grpc_cq_completion completion_storage; |
| 91 grpc_channel *channel; |
| 92 void *tag; |
| 93 } state_watcher; |
| 94 |
| 95 static void delete_state_watcher(grpc_exec_ctx *exec_ctx, state_watcher *w) { |
| 96 grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( |
| 97 grpc_channel_get_channel_stack(w->channel)); |
| 98 if (client_channel_elem->filter == &grpc_client_channel_filter) { |
| 99 GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel, |
| 100 "watch_channel_connectivity"); |
| 101 } else if (client_channel_elem->filter == &grpc_client_uchannel_filter) { |
| 102 GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel, |
| 103 "watch_uchannel_connectivity"); |
| 104 } else { |
| 105 abort(); |
| 106 } |
| 107 gpr_mu_destroy(&w->mu); |
| 108 gpr_free(w); |
| 109 } |
| 110 |
| 111 static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw, |
| 112 grpc_cq_completion *ignored) { |
| 113 int delete = 0; |
| 114 state_watcher *w = pw; |
| 115 gpr_mu_lock(&w->mu); |
| 116 switch (w->phase) { |
| 117 case WAITING: |
| 118 case CALLED_BACK: |
| 119 GPR_UNREACHABLE_CODE(return ); |
| 120 case CALLING_BACK: |
| 121 w->phase = CALLED_BACK; |
| 122 break; |
| 123 case CALLING_BACK_AND_FINISHED: |
| 124 delete = 1; |
| 125 break; |
| 126 } |
| 127 gpr_mu_unlock(&w->mu); |
| 128 |
| 129 if (delete) { |
| 130 delete_state_watcher(exec_ctx, w); |
| 131 } |
| 132 } |
| 133 |
| 134 static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, |
| 135 int due_to_completion) { |
| 136 int delete = 0; |
| 137 |
| 138 if (due_to_completion) { |
| 139 grpc_timer_cancel(exec_ctx, &w->alarm); |
| 140 } |
| 141 |
| 142 gpr_mu_lock(&w->mu); |
| 143 if (due_to_completion) { |
| 144 w->success = 1; |
| 145 } |
| 146 switch (w->phase) { |
| 147 case WAITING: |
| 148 w->phase = CALLING_BACK; |
| 149 grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->success, finished_completion, |
| 150 w, &w->completion_storage); |
| 151 break; |
| 152 case CALLING_BACK: |
| 153 w->phase = CALLING_BACK_AND_FINISHED; |
| 154 break; |
| 155 case CALLING_BACK_AND_FINISHED: |
| 156 GPR_UNREACHABLE_CODE(return ); |
| 157 case CALLED_BACK: |
| 158 delete = 1; |
| 159 break; |
| 160 } |
| 161 gpr_mu_unlock(&w->mu); |
| 162 |
| 163 if (delete) { |
| 164 delete_state_watcher(exec_ctx, w); |
| 165 } |
| 166 } |
| 167 |
| 168 static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) { |
| 169 partly_done(exec_ctx, pw, 1); |
| 170 } |
| 171 |
| 172 static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) { |
| 173 partly_done(exec_ctx, pw, 0); |
| 174 } |
| 175 |
| 176 void grpc_channel_watch_connectivity_state( |
| 177 grpc_channel *channel, grpc_connectivity_state last_observed_state, |
| 178 gpr_timespec deadline, grpc_completion_queue *cq, void *tag) { |
| 179 grpc_channel_element *client_channel_elem = |
| 180 grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); |
| 181 grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
| 182 state_watcher *w = gpr_malloc(sizeof(*w)); |
| 183 |
| 184 GRPC_API_TRACE( |
| 185 "grpc_channel_watch_connectivity_state(" |
| 186 "channel=%p, last_observed_state=%d, " |
| 187 "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " |
| 188 "cq=%p, tag=%p)", |
| 189 7, (channel, (int)last_observed_state, (long long)deadline.tv_sec, |
| 190 (int)deadline.tv_nsec, (int)deadline.clock_type, cq, tag)); |
| 191 |
| 192 grpc_cq_begin_op(cq, tag); |
| 193 |
| 194 gpr_mu_init(&w->mu); |
| 195 grpc_closure_init(&w->on_complete, watch_complete, w); |
| 196 w->phase = WAITING; |
| 197 w->state = last_observed_state; |
| 198 w->success = 0; |
| 199 w->cq = cq; |
| 200 w->tag = tag; |
| 201 w->channel = channel; |
| 202 |
| 203 grpc_timer_init(&exec_ctx, &w->alarm, |
| 204 gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), |
| 205 timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC)); |
| 206 |
| 207 if (client_channel_elem->filter == &grpc_client_channel_filter) { |
| 208 GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity"); |
| 209 grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem, |
| 210 grpc_cq_pollset(cq), &w->state, |
| 211 &w->on_complete); |
| 212 } else if (client_channel_elem->filter == &grpc_client_uchannel_filter) { |
| 213 GRPC_CHANNEL_INTERNAL_REF(channel, "watch_uchannel_connectivity"); |
| 214 grpc_client_uchannel_watch_connectivity_state( |
| 215 &exec_ctx, client_channel_elem, grpc_cq_pollset(cq), &w->state, |
| 216 &w->on_complete); |
| 217 } |
| 218 |
| 219 grpc_exec_ctx_finish(&exec_ctx); |
| 220 } |
OLD | NEW |