blob: 0e707ef8392a5ff050da99225e623dc225631ba5 [file] [log] [blame]
Craig Tillera26637f2016-05-02 13:36:36 -07001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2016 gRPC authors.
Craig Tillera26637f2016-05-02 13:36:36 -07004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * 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
Craig Tillera26637f2016-05-02 13:36:36 -07008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Craig Tillera26637f2016-05-02 13:36:36 -070010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * 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.
Craig Tillera26637f2016-05-02 13:36:36 -070016 *
17 */
18
Craig Tillerf7cade12016-07-07 21:41:10 -070019#include "src/core/lib/iomgr/combiner.h"
Craig Tiller5842a5b2016-05-02 12:38:57 -070020
Craig Tiller18f09a02017-02-23 17:10:04 -080021#include <assert.h>
Yash Tibrewalfcd26bc2017-09-25 15:08:28 -070022#include <inttypes.h>
Craig Tillera26637f2016-05-02 13:36:36 -070023#include <string.h>
24
25#include <grpc/support/alloc.h>
26#include <grpc/support/log.h>
27
Craig Tiller57bb9a92017-08-31 16:44:15 -070028#include "src/core/lib/debug/stats.h"
Craig Tilleree4b1452017-05-12 10:56:03 -070029#include "src/core/lib/iomgr/executor.h"
Craig Tillerc69d27b2016-07-14 13:20:22 -070030#include "src/core/lib/profiling/timers.h"
31
ncteisen7712c7c2017-07-12 23:11:27 -070032grpc_tracer_flag grpc_combiner_trace =
33 GRPC_TRACER_INITIALIZER(false, "combiner");
Craig Tillere7603b82016-07-18 15:43:42 -070034
Craig Tiller84f75d42017-05-03 13:06:35 -070035#define GRPC_COMBINER_TRACE(fn) \
36 do { \
37 if (GRPC_TRACER_ON(grpc_combiner_trace)) { \
38 fn; \
39 } \
Craig Tillerc3df7b42016-07-18 15:51:26 -070040 } while (0)
Craig Tillere7603b82016-07-18 15:43:42 -070041
Craig Tillerd80a8c92016-10-10 13:19:56 -070042#define STATE_UNORPHANED 1
43#define STATE_ELEM_COUNT_LOW_BIT 2
44
Craig Tillerf7cade12016-07-07 21:41:10 -070045struct grpc_combiner {
Craig Tillerdfd3a8f2016-08-24 09:43:45 -070046 grpc_combiner *next_combiner_on_this_exec_ctx;
Craig Tilleree4b1452017-05-12 10:56:03 -070047 grpc_closure_scheduler scheduler;
48 grpc_closure_scheduler finally_scheduler;
Craig Tillercf600c92016-05-03 08:26:56 -070049 gpr_mpscq queue;
Craig Tiller68608c52017-05-18 06:27:29 -070050 // either:
51 // a pointer to the initiating exec ctx if that is the only exec_ctx that has
52 // ever queued to this combiner, or NULL. If this is non-null, it's not
53 // dereferencable (since the initiating exec_ctx may have gone out of scope)
54 gpr_atm initiating_exec_ctx_or_null;
Craig Tillercf600c92016-05-03 08:26:56 -070055 // state is:
Craig Tillerd80a8c92016-10-10 13:19:56 -070056 // lower bit - zero if orphaned (STATE_UNORPHANED)
57 // other bits - number of items queued on the lock (STATE_ELEM_COUNT_LOW_BIT)
Craig Tillercf600c92016-05-03 08:26:56 -070058 gpr_atm state;
Craig Tillerdfd3a8f2016-08-24 09:43:45 -070059 bool time_to_execute_final_list;
Craig Tillera36857d2016-07-08 16:57:42 -070060 grpc_closure_list final_list;
Craig Tillerdfd3a8f2016-08-24 09:43:45 -070061 grpc_closure offload;
Craig Tiller5634ef62017-02-09 14:25:32 -080062 gpr_refcount refs;
Craig Tillercf600c92016-05-03 08:26:56 -070063};
64
Craig Tilleree4b1452017-05-12 10:56:03 -070065static void combiner_exec(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
66 grpc_error *error);
67static void combiner_finally_exec(grpc_exec_ctx *exec_ctx,
Craig Tiller91031da2016-12-28 15:44:25 -080068 grpc_closure *closure, grpc_error *error);
Craig Tiller91031da2016-12-28 15:44:25 -080069
Craig Tilleree4b1452017-05-12 10:56:03 -070070static const grpc_closure_scheduler_vtable scheduler = {
71 combiner_exec, combiner_exec, "combiner:immediately"};
72static const grpc_closure_scheduler_vtable finally_scheduler = {
73 combiner_finally_exec, combiner_finally_exec, "combiner:finally"};
Craig Tiller91031da2016-12-28 15:44:25 -080074
Craig Tillerdfd3a8f2016-08-24 09:43:45 -070075static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
76
Craig Tilleree4b1452017-05-12 10:56:03 -070077grpc_combiner *grpc_combiner_create(void) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -070078 grpc_combiner *lock = (grpc_combiner *)gpr_zalloc(sizeof(*lock));
Craig Tiller5634ef62017-02-09 14:25:32 -080079 gpr_ref_init(&lock->refs, 1);
Craig Tilleree4b1452017-05-12 10:56:03 -070080 lock->scheduler.vtable = &scheduler;
81 lock->finally_scheduler.vtable = &finally_scheduler;
Craig Tillerd80a8c92016-10-10 13:19:56 -070082 gpr_atm_no_barrier_store(&lock->state, STATE_UNORPHANED);
Craig Tillerad3c8c12016-05-02 21:47:30 -070083 gpr_mpscq_init(&lock->queue);
Craig Tillera36857d2016-07-08 16:57:42 -070084 grpc_closure_list_init(&lock->final_list);
Craig Tiller7a82afd2017-07-18 09:40:40 -070085 GRPC_CLOSURE_INIT(&lock->offload, offload, lock,
86 grpc_executor_scheduler(GRPC_EXECUTOR_SHORT));
Craig Tillerc3df7b42016-07-18 15:51:26 -070087 GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p create", lock));
Craig Tillercf600c92016-05-03 08:26:56 -070088 return lock;
Craig Tiller5842a5b2016-05-02 12:38:57 -070089}
90
Craig Tillere0221ff2016-07-11 15:56:08 -070091static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) {
Craig Tillerc3df7b42016-07-18 15:51:26 -070092 GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p really_destroy", lock));
Craig Tillercf600c92016-05-03 08:26:56 -070093 GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0);
Craig Tillerad3c8c12016-05-02 21:47:30 -070094 gpr_mpscq_destroy(&lock->queue);
Craig Tiller14e3d9b2016-05-03 08:33:56 -070095 gpr_free(lock);
Craig Tiller5842a5b2016-05-02 12:38:57 -070096}
97
Craig Tiller5634ef62017-02-09 14:25:32 -080098static void start_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) {
Craig Tillerd80a8c92016-10-10 13:19:56 -070099 gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -STATE_UNORPHANED);
Craig Tillerc3df7b42016-07-18 15:51:26 -0700100 GRPC_COMBINER_TRACE(gpr_log(
101 GPR_DEBUG, "C:%p really_destroy old_state=%" PRIdPTR, lock, old_state));
Craig Tillere7603b82016-07-18 15:43:42 -0700102 if (old_state == 1) {
Craig Tillere0221ff2016-07-11 15:56:08 -0700103 really_destroy(exec_ctx, lock);
Craig Tiller5842a5b2016-05-02 12:38:57 -0700104 }
105}
106
ncteisena1354852017-06-08 16:25:53 -0700107#ifndef NDEBUG
ncteisen3bc25582017-06-09 10:35:35 -0700108#define GRPC_COMBINER_DEBUG_SPAM(op, delta) \
109 if (GRPC_TRACER_ON(grpc_combiner_trace)) { \
110 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, \
111 "C:%p %s %" PRIdPTR " --> %" PRIdPTR " %s", lock, (op), \
112 gpr_atm_no_barrier_load(&lock->refs.count), \
113 gpr_atm_no_barrier_load(&lock->refs.count) + (delta), reason); \
114 }
Craig Tiller3845e552017-02-09 15:19:28 -0800115#else
116#define GRPC_COMBINER_DEBUG_SPAM(op, delta)
117#endif
118
119void grpc_combiner_unref(grpc_exec_ctx *exec_ctx,
120 grpc_combiner *lock GRPC_COMBINER_DEBUG_ARGS) {
121 GRPC_COMBINER_DEBUG_SPAM("UNREF", -1);
Craig Tiller5634ef62017-02-09 14:25:32 -0800122 if (gpr_unref(&lock->refs)) {
123 start_destroy(exec_ctx, lock);
124 }
125}
126
Craig Tiller3845e552017-02-09 15:19:28 -0800127grpc_combiner *grpc_combiner_ref(grpc_combiner *lock GRPC_COMBINER_DEBUG_ARGS) {
128 GRPC_COMBINER_DEBUG_SPAM(" REF", 1);
129 gpr_ref(&lock->refs);
130 return lock;
131}
Craig Tiller5634ef62017-02-09 14:25:32 -0800132
Craig Tiller86037cd02016-09-02 19:58:43 -0700133static void push_last_on_exec_ctx(grpc_exec_ctx *exec_ctx,
134 grpc_combiner *lock) {
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700135 lock->next_combiner_on_this_exec_ctx = NULL;
136 if (exec_ctx->active_combiner == NULL) {
137 exec_ctx->active_combiner = exec_ctx->last_combiner = lock;
Craig Tiller4e436852016-07-10 14:01:50 -0700138 } else {
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700139 exec_ctx->last_combiner->next_combiner_on_this_exec_ctx = lock;
140 exec_ctx->last_combiner = lock;
Craig Tiller4e436852016-07-10 14:01:50 -0700141 }
Craig Tillercf600c92016-05-03 08:26:56 -0700142}
143
Craig Tiller86037cd02016-09-02 19:58:43 -0700144static void push_first_on_exec_ctx(grpc_exec_ctx *exec_ctx,
145 grpc_combiner *lock) {
146 lock->next_combiner_on_this_exec_ctx = exec_ctx->active_combiner;
147 exec_ctx->active_combiner = lock;
148 if (lock->next_combiner_on_this_exec_ctx == NULL) {
149 exec_ctx->last_combiner = lock;
150 }
151}
152
Craig Tilleree4b1452017-05-12 10:56:03 -0700153#define COMBINER_FROM_CLOSURE_SCHEDULER(closure, scheduler_name) \
154 ((grpc_combiner *)(((char *)((closure)->scheduler)) - \
155 offsetof(grpc_combiner, scheduler_name)))
156
157static void combiner_exec(grpc_exec_ctx *exec_ctx, grpc_closure *cl,
158 grpc_error *error) {
Craig Tiller57bb9a92017-08-31 16:44:15 -0700159 GRPC_STATS_INC_COMBINER_LOCKS_SCHEDULED_ITEMS(exec_ctx);
Craig Tillerc69d27b2016-07-14 13:20:22 -0700160 GPR_TIMER_BEGIN("combiner.execute", 0);
Craig Tilleree4b1452017-05-12 10:56:03 -0700161 grpc_combiner *lock = COMBINER_FROM_CLOSURE_SCHEDULER(cl, scheduler);
Craig Tillerd80a8c92016-10-10 13:19:56 -0700162 gpr_atm last = gpr_atm_full_fetch_add(&lock->state, STATE_ELEM_COUNT_LOW_BIT);
Craig Tilleree4b1452017-05-12 10:56:03 -0700163 GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG,
164 "C:%p grpc_combiner_execute c=%p last=%" PRIdPTR,
165 lock, cl, last));
Craig Tiller68608c52017-05-18 06:27:29 -0700166 if (last == 1) {
Craig Tiller57bb9a92017-08-31 16:44:15 -0700167 GRPC_STATS_INC_COMBINER_LOCKS_INITIATED(exec_ctx);
Craig Tiller68608c52017-05-18 06:27:29 -0700168 gpr_atm_no_barrier_store(&lock->initiating_exec_ctx_or_null,
169 (gpr_atm)exec_ctx);
170 // first element on this list: add it to the list of combiner locks
171 // executing within this exec_ctx
172 push_last_on_exec_ctx(exec_ctx, lock);
173 } else {
174 // there may be a race with setting here: if that happens, we may delay
175 // offload for one or two actions, and that's fine
176 gpr_atm initiator =
177 gpr_atm_no_barrier_load(&lock->initiating_exec_ctx_or_null);
178 if (initiator != 0 && initiator != (gpr_atm)exec_ctx) {
179 gpr_atm_no_barrier_store(&lock->initiating_exec_ctx_or_null, 0);
180 }
181 }
Craig Tillerd80a8c92016-10-10 13:19:56 -0700182 GPR_ASSERT(last & STATE_UNORPHANED); // ensure lock has not been destroyed
Craig Tiller18f09a02017-02-23 17:10:04 -0800183 assert(cl->cb);
Craig Tilleree4b1452017-05-12 10:56:03 -0700184 cl->error_data.error = error;
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700185 gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next);
Craig Tillerc69d27b2016-07-14 13:20:22 -0700186 GPR_TIMER_END("combiner.execute", 0);
Craig Tiller5842a5b2016-05-02 12:38:57 -0700187}
Craig Tillera36857d2016-07-08 16:57:42 -0700188
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700189static void move_next(grpc_exec_ctx *exec_ctx) {
190 exec_ctx->active_combiner =
191 exec_ctx->active_combiner->next_combiner_on_this_exec_ctx;
192 if (exec_ctx->active_combiner == NULL) {
193 exec_ctx->last_combiner = NULL;
194 }
195}
196
197static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700198 grpc_combiner *lock = (grpc_combiner *)arg;
Craig Tiller86037cd02016-09-02 19:58:43 -0700199 push_last_on_exec_ctx(exec_ctx, lock);
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700200}
201
202static void queue_offload(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) {
Craig Tiller57bb9a92017-08-31 16:44:15 -0700203 GRPC_STATS_INC_COMBINER_LOCKS_OFFLOADED(exec_ctx);
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700204 move_next(exec_ctx);
Craig Tilleree4b1452017-05-12 10:56:03 -0700205 GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p queue_offload", lock));
ncteisen969b46e2017-06-08 14:57:11 -0700206 GRPC_CLOSURE_SCHED(exec_ctx, &lock->offload, GRPC_ERROR_NONE);
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700207}
208
209bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) {
210 GPR_TIMER_BEGIN("combiner.continue_exec_ctx", 0);
211 grpc_combiner *lock = exec_ctx->active_combiner;
212 if (lock == NULL) {
213 GPR_TIMER_END("combiner.continue_exec_ctx", 0);
214 return false;
215 }
216
Craig Tiller3e6c7772017-06-06 08:37:40 -0700217 bool contended =
218 gpr_atm_no_barrier_load(&lock->initiating_exec_ctx_or_null) == 0;
Craig Tillere587a5c2017-06-06 15:12:33 +0000219
Craig Tilleree4b1452017-05-12 10:56:03 -0700220 GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG,
221 "C:%p grpc_combiner_continue_exec_ctx "
Craig Tillere587a5c2017-06-06 15:12:33 +0000222 "contended=%d "
Craig Tilleree4b1452017-05-12 10:56:03 -0700223 "exec_ctx_ready_to_finish=%d "
224 "time_to_execute_final_list=%d",
Craig Tiller3e6c7772017-06-06 08:37:40 -0700225 lock, contended,
226 grpc_exec_ctx_ready_to_finish(exec_ctx),
Craig Tilleree4b1452017-05-12 10:56:03 -0700227 lock->time_to_execute_final_list));
Craig Tillerfc2636d2016-09-12 09:57:07 -0700228
Craig Tiller3e6c7772017-06-06 08:37:40 -0700229 if (contended && grpc_exec_ctx_ready_to_finish(exec_ctx) &&
230 grpc_executor_is_threaded()) {
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700231 GPR_TIMER_MARK("offload_from_finished_exec_ctx", 0);
Craig Tiller747216f2017-06-08 08:08:11 -0700232 // this execution context wants to move on: schedule remaining work to be
233 // picked up on the executor
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700234 queue_offload(exec_ctx, lock);
235 GPR_TIMER_END("combiner.continue_exec_ctx", 0);
236 return true;
237 }
238
239 if (!lock->time_to_execute_final_list ||
240 // peek to see if something new has shown up, and execute that with
241 // priority
242 (gpr_atm_acq_load(&lock->state) >> 1) > 1) {
243 gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue);
244 GRPC_COMBINER_TRACE(
245 gpr_log(GPR_DEBUG, "C:%p maybe_finish_one n=%p", lock, n));
246 if (n == NULL) {
Craig Tillerd80a8c92016-10-10 13:19:56 -0700247 // queue is in an inconsistent state: use this as a cue that we should
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700248 // go off and do something else for a while (and come back later)
249 GPR_TIMER_MARK("delay_busy", 0);
Craig Tilleree4b1452017-05-12 10:56:03 -0700250 queue_offload(exec_ctx, lock);
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700251 GPR_TIMER_END("combiner.continue_exec_ctx", 0);
252 return true;
253 }
254 GPR_TIMER_BEGIN("combiner.exec1", 0);
255 grpc_closure *cl = (grpc_closure *)n;
Craig Tilleree4b1452017-05-12 10:56:03 -0700256 grpc_error *cl_err = cl->error_data.error;
ncteisenf8061e82017-06-09 10:44:42 -0700257#ifndef NDEBUG
Mark D. Roth43f774e2017-04-04 16:35:37 -0700258 cl->scheduled = false;
259#endif
Craig Tilleree4b1452017-05-12 10:56:03 -0700260 cl->cb(exec_ctx, cl->cb_arg, cl_err);
261 GRPC_ERROR_UNREF(cl_err);
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700262 GPR_TIMER_END("combiner.exec1", 0);
263 } else {
Craig Tillera7cd41c2016-08-31 12:59:24 -0700264 grpc_closure *c = lock->final_list.head;
265 GPR_ASSERT(c != NULL);
266 grpc_closure_list_init(&lock->final_list);
267 int loops = 0;
268 while (c != NULL) {
269 GPR_TIMER_BEGIN("combiner.exec_1final", 0);
270 GRPC_COMBINER_TRACE(
271 gpr_log(GPR_DEBUG, "C:%p execute_final[%d] c=%p", lock, loops, c));
272 grpc_closure *next = c->next_data.next;
273 grpc_error *error = c->error_data.error;
ncteisenf8061e82017-06-09 10:44:42 -0700274#ifndef NDEBUG
Mark D. Roth43f774e2017-04-04 16:35:37 -0700275 c->scheduled = false;
276#endif
Craig Tillera7cd41c2016-08-31 12:59:24 -0700277 c->cb(exec_ctx, c->cb_arg, error);
278 GRPC_ERROR_UNREF(error);
279 c = next;
280 GPR_TIMER_END("combiner.exec_1final", 0);
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700281 }
282 }
283
284 GPR_TIMER_MARK("unref", 0);
Craig Tiller86037cd02016-09-02 19:58:43 -0700285 move_next(exec_ctx);
286 lock->time_to_execute_final_list = false;
Craig Tillerd80a8c92016-10-10 13:19:56 -0700287 gpr_atm old_state =
288 gpr_atm_full_fetch_add(&lock->state, -STATE_ELEM_COUNT_LOW_BIT);
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700289 GRPC_COMBINER_TRACE(
290 gpr_log(GPR_DEBUG, "C:%p finish old_state=%" PRIdPTR, lock, old_state));
Craig Tillerd3ee0d52016-10-10 14:09:18 -0700291// Define a macro to ease readability of the following switch statement.
292#define OLD_STATE_WAS(orphaned, elem_count) \
293 (((orphaned) ? 0 : STATE_UNORPHANED) | \
294 ((elem_count)*STATE_ELEM_COUNT_LOW_BIT))
295 // Depending on what the previous state was, we need to perform different
296 // actions.
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700297 switch (old_state) {
Craig Tiller56f21aa2016-09-02 09:29:43 -0700298 default:
299 // we have multiple queued work items: just continue executing them
300 break;
Craig Tillerd3ee0d52016-10-10 14:09:18 -0700301 case OLD_STATE_WAS(false, 2):
302 case OLD_STATE_WAS(true, 2):
Craig Tillerd80a8c92016-10-10 13:19:56 -0700303 // we're down to one queued item: if it's the final list we should do that
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700304 if (!grpc_closure_list_empty(lock->final_list)) {
305 lock->time_to_execute_final_list = true;
306 }
307 break;
Craig Tillerd3ee0d52016-10-10 14:09:18 -0700308 case OLD_STATE_WAS(false, 1):
Craig Tillerd80a8c92016-10-10 13:19:56 -0700309 // had one count, one unorphaned --> unlocked unorphaned
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700310 GPR_TIMER_END("combiner.continue_exec_ctx", 0);
311 return true;
Craig Tillerd3ee0d52016-10-10 14:09:18 -0700312 case OLD_STATE_WAS(true, 1):
Craig Tillerd80a8c92016-10-10 13:19:56 -0700313 // and one count, one orphaned --> unlocked and orphaned
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700314 really_destroy(exec_ctx, lock);
315 GPR_TIMER_END("combiner.continue_exec_ctx", 0);
316 return true;
Craig Tillerd3ee0d52016-10-10 14:09:18 -0700317 case OLD_STATE_WAS(false, 0):
318 case OLD_STATE_WAS(true, 0):
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700319 // these values are illegal - representing an already unlocked or
320 // deleted lock
321 GPR_TIMER_END("combiner.continue_exec_ctx", 0);
322 GPR_UNREACHABLE_CODE(return true);
323 }
Craig Tiller86037cd02016-09-02 19:58:43 -0700324 push_first_on_exec_ctx(exec_ctx, lock);
Craig Tillerdfd3a8f2016-08-24 09:43:45 -0700325 GPR_TIMER_END("combiner.continue_exec_ctx", 0);
326 return true;
327}
328
Craig Tillere0221ff2016-07-11 15:56:08 -0700329static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure,
Craig Tiller91031da2016-12-28 15:44:25 -0800330 grpc_error *error);
Craig Tillere0221ff2016-07-11 15:56:08 -0700331
Craig Tilleree4b1452017-05-12 10:56:03 -0700332static void combiner_finally_exec(grpc_exec_ctx *exec_ctx,
333 grpc_closure *closure, grpc_error *error) {
Craig Tiller57bb9a92017-08-31 16:44:15 -0700334 GRPC_STATS_INC_COMBINER_LOCKS_SCHEDULED_FINAL_ITEMS(exec_ctx);
Craig Tilleree4b1452017-05-12 10:56:03 -0700335 grpc_combiner *lock =
336 COMBINER_FROM_CLOSURE_SCHEDULER(closure, finally_scheduler);
337 GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG,
338 "C:%p grpc_combiner_execute_finally c=%p; ac=%p",
339 lock, closure, exec_ctx->active_combiner));
Craig Tillerc69d27b2016-07-14 13:20:22 -0700340 GPR_TIMER_BEGIN("combiner.execute_finally", 0);
Craig Tillere0221ff2016-07-11 15:56:08 -0700341 if (exec_ctx->active_combiner != lock) {
Craig Tillerc69d27b2016-07-14 13:20:22 -0700342 GPR_TIMER_MARK("slowpath", 0);
ncteisen969b46e2017-06-08 14:57:11 -0700343 GRPC_CLOSURE_SCHED(exec_ctx,
344 GRPC_CLOSURE_CREATE(enqueue_finally, closure,
Craig Tilleree4b1452017-05-12 10:56:03 -0700345 grpc_combiner_scheduler(lock)),
346 error);
Craig Tillerc69d27b2016-07-14 13:20:22 -0700347 GPR_TIMER_END("combiner.execute_finally", 0);
Craig Tillere0221ff2016-07-11 15:56:08 -0700348 return;
349 }
350
Craig Tillera36857d2016-07-08 16:57:42 -0700351 if (grpc_closure_list_empty(lock->final_list)) {
Craig Tillerd80a8c92016-10-10 13:19:56 -0700352 gpr_atm_full_fetch_add(&lock->state, STATE_ELEM_COUNT_LOW_BIT);
Craig Tillera36857d2016-07-08 16:57:42 -0700353 }
354 grpc_closure_list_append(&lock->final_list, closure, error);
Craig Tillere7603b82016-07-18 15:43:42 -0700355 GPR_TIMER_END("combiner.execute_finally", 0);
Craig Tillera36857d2016-07-08 16:57:42 -0700356}
Craig Tiller91031da2016-12-28 15:44:25 -0800357
358static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure,
359 grpc_error *error) {
Yash Tibrewal52778c42017-09-11 15:00:11 -0700360 combiner_finally_exec(exec_ctx, (grpc_closure *)closure,
361 GRPC_ERROR_REF(error));
Craig Tiller91031da2016-12-28 15:44:25 -0800362}
363
Craig Tilleree4b1452017-05-12 10:56:03 -0700364grpc_closure_scheduler *grpc_combiner_scheduler(grpc_combiner *combiner) {
365 return &combiner->scheduler;
Craig Tiller91031da2016-12-28 15:44:25 -0800366}
367
368grpc_closure_scheduler *grpc_combiner_finally_scheduler(
Craig Tilleree4b1452017-05-12 10:56:03 -0700369 grpc_combiner *combiner) {
370 return &combiner->finally_scheduler;
Craig Tiller91031da2016-12-28 15:44:25 -0800371}