|  | @@ -44,6 +44,8 @@
 | 
	
		
			
				|  |  |  #include <grpc/support/useful.h>
 | 
	
		
			
				|  |  |  #include "src/core/lib/slice/slice_internal.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define WRITE_BUFFER_SIZE (2 * 1024 * 1024)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  typedef struct {
 | 
	
		
			
				|  |  |    grpc_endpoint base;
 | 
	
		
			
				|  |  |    double bytes_per_second;
 | 
	
	
		
			
				|  | @@ -55,6 +57,7 @@ typedef struct {
 | 
	
		
			
				|  |  |    grpc_slice_buffer writing_buffer;
 | 
	
		
			
				|  |  |    grpc_error *error;
 | 
	
		
			
				|  |  |    bool writing;
 | 
	
		
			
				|  |  | +  grpc_closure *write_cb;
 | 
	
		
			
				|  |  |  } trickle_endpoint;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void te_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
 | 
	
	
		
			
				|  | @@ -63,6 +66,15 @@ static void te_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
 | 
	
		
			
				|  |  |    grpc_endpoint_read(exec_ctx, te->wrapped, slices, cb);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void maybe_call_write_cb_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                       trickle_endpoint *te) {
 | 
	
		
			
				|  |  | +  if (te->write_cb != NULL && (te->error != GRPC_ERROR_NONE ||
 | 
	
		
			
				|  |  | +                               te->write_buffer.length <= WRITE_BUFFER_SIZE)) {
 | 
	
		
			
				|  |  | +    grpc_closure_sched(exec_ctx, te->write_cb, GRPC_ERROR_REF(te->error));
 | 
	
		
			
				|  |  | +    te->write_cb = NULL;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void te_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
 | 
	
		
			
				|  |  |                       grpc_slice_buffer *slices, grpc_closure *cb) {
 | 
	
		
			
				|  |  |    trickle_endpoint *te = (trickle_endpoint *)ep;
 | 
	
	
		
			
				|  | @@ -70,11 +82,13 @@ static void te_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
 | 
	
		
			
				|  |  |      grpc_slice_ref_internal(slices->slices[i]);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_mu_lock(&te->mu);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(te->write_cb == NULL);
 | 
	
		
			
				|  |  |    if (te->write_buffer.length == 0) {
 | 
	
		
			
				|  |  |      te->last_write = gpr_now(GPR_CLOCK_MONOTONIC);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    grpc_slice_buffer_addn(&te->write_buffer, slices->slices, slices->count);
 | 
	
		
			
				|  |  | -  grpc_closure_sched(exec_ctx, cb, GRPC_ERROR_REF(te->error));
 | 
	
		
			
				|  |  | +  te->write_cb = cb;
 | 
	
		
			
				|  |  | +  maybe_call_write_cb_locked(exec_ctx, te);
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&te->mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -102,6 +116,7 @@ static void te_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
 | 
	
		
			
				|  |  |    if (te->error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      te->error = GRPC_ERROR_REF(why);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  maybe_call_write_cb_locked(exec_ctx, te);
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&te->mu);
 | 
	
		
			
				|  |  |    grpc_endpoint_shutdown(exec_ctx, te->wrapped, why);
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -157,6 +172,7 @@ grpc_endpoint *grpc_trickle_endpoint_create(grpc_endpoint *wrap,
 | 
	
		
			
				|  |  |    te->base.vtable = &vtable;
 | 
	
		
			
				|  |  |    te->wrapped = wrap;
 | 
	
		
			
				|  |  |    te->bytes_per_second = bytes_per_second;
 | 
	
		
			
				|  |  | +  te->write_cb = NULL;
 | 
	
		
			
				|  |  |    gpr_mu_init(&te->mu);
 | 
	
		
			
				|  |  |    grpc_slice_buffer_init(&te->write_buffer);
 | 
	
		
			
				|  |  |    grpc_slice_buffer_init(&te->writing_buffer);
 | 
	
	
		
			
				|  | @@ -187,6 +203,7 @@ size_t grpc_trickle_endpoint_trickle(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |        grpc_endpoint_write(
 | 
	
		
			
				|  |  |            exec_ctx, te->wrapped, &te->writing_buffer,
 | 
	
		
			
				|  |  |            grpc_closure_create(te_finish_write, te, grpc_schedule_on_exec_ctx));
 | 
	
		
			
				|  |  | +      maybe_call_write_cb_locked(exec_ctx, te);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    size_t backlog = te->write_buffer.length;
 |