|  | @@ -53,6 +53,9 @@ typedef struct grpc_workqueue grpc_workqueue;
 | 
	
		
			
				|  |  |   *  - track a list of work that needs to be delayed until the top of the
 | 
	
		
			
				|  |  |   *    call stack (this provides a convenient mechanism to run callbacks
 | 
	
		
			
				|  |  |   *    without worrying about locking issues)
 | 
	
		
			
				|  |  | + *  - provide a decision maker (via grpc_exec_ctx_ready_to_finish) that provides
 | 
	
		
			
				|  |  | + *    signal as to whether a borrowed thread should continue to do work or
 | 
	
		
			
				|  |  | + *    should actively try to finish up and get this thread back to its owner
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  |   *  CONVENTIONS:
 | 
	
		
			
				|  |  |   *  Instance of this must ALWAYS be constructed on the stack, never
 | 
	
	
		
			
				|  | @@ -63,18 +66,26 @@ typedef struct grpc_workqueue grpc_workqueue;
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  struct grpc_exec_ctx {
 | 
	
		
			
				|  |  |    grpc_closure_list closure_list;
 | 
	
		
			
				|  |  | +  bool cached_ready_to_finish;
 | 
	
		
			
				|  |  | +  void *check_ready_to_finish_arg;
 | 
	
		
			
				|  |  | +  bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg);
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#define GRPC_EXEC_CTX_INIT \
 | 
	
		
			
				|  |  | -  { GRPC_CLOSURE_LIST_INIT }
 | 
	
		
			
				|  |  | +#define GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(finish_check, finish_check_arg) \
 | 
	
		
			
				|  |  | +  { GRPC_CLOSURE_LIST_INIT, false, finish_check_arg, finish_check }
 | 
	
		
			
				|  |  |  #else
 | 
	
		
			
				|  |  |  struct grpc_exec_ctx {
 | 
	
		
			
				|  |  | -  int unused;
 | 
	
		
			
				|  |  | +  bool cached_ready_to_finish;
 | 
	
		
			
				|  |  | +  void *check_ready_to_finish_arg;
 | 
	
		
			
				|  |  | +  bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg);
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  | -#define GRPC_EXEC_CTX_INIT \
 | 
	
		
			
				|  |  | -  { 0 }
 | 
	
		
			
				|  |  | +#define GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(finish_check, finish_check_arg) \
 | 
	
		
			
				|  |  | +  { false, finish_check_arg, finish_check }
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define GRPC_EXEC_CTX_INIT \
 | 
	
		
			
				|  |  | +  GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(grpc_never_ready_to_finish, NULL)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** Flush any work that has been enqueued onto this grpc_exec_ctx.
 | 
	
		
			
				|  |  |   *  Caller must guarantee that no interfering locks are held.
 | 
	
		
			
				|  |  |   *  Returns true if work was performed, false otherwise. */
 | 
	
	
		
			
				|  | @@ -86,6 +97,14 @@ void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx);
 | 
	
		
			
				|  |  |  void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
 | 
	
		
			
				|  |  |                             bool success,
 | 
	
		
			
				|  |  |                             grpc_workqueue *offload_target_or_null);
 | 
	
		
			
				|  |  | +/** Returns true if we'd like to leave this execution context as soon as
 | 
	
		
			
				|  |  | +    possible: useful for deciding whether to do something more or not depending
 | 
	
		
			
				|  |  | +    on outside context */
 | 
	
		
			
				|  |  | +bool grpc_exec_ctx_ready_to_finish(grpc_exec_ctx *exec_ctx);
 | 
	
		
			
				|  |  | +/** A finish check that is never ready to finish */
 | 
	
		
			
				|  |  | +bool grpc_never_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored);
 | 
	
		
			
				|  |  | +/** A finish check that is always ready to finish */
 | 
	
		
			
				|  |  | +bool grpc_always_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored);
 | 
	
		
			
				|  |  |  /** Add a list of closures to be executed at the next flush/finish point.
 | 
	
		
			
				|  |  |   *  Leaves \a list empty. */
 | 
	
		
			
				|  |  |  void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
 |