|  | @@ -118,12 +118,14 @@ static void on_read(void *tcpp, int from_iocp) {
 | 
	
		
			
				|  |  |    gpr_slice *slice = NULL;
 | 
	
		
			
				|  |  |    size_t nslices = 0;
 | 
	
		
			
				|  |  |    grpc_endpoint_cb_status status;
 | 
	
		
			
				|  |  | -  grpc_endpoint_read_cb cb = tcp->read_cb;
 | 
	
		
			
				|  |  | +  grpc_endpoint_read_cb cb;
 | 
	
		
			
				|  |  |    grpc_winsocket_callback_info *info = &socket->read_info;
 | 
	
		
			
				|  |  |    void *opaque = tcp->read_user_data;
 | 
	
		
			
				|  |  |    int do_abort = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    gpr_mu_lock(&tcp->mu);
 | 
	
		
			
				|  |  | +  cb = tcp->read_cb;
 | 
	
		
			
				|  |  | +  tcp->read_cb = NULL;
 | 
	
		
			
				|  |  |    if (!from_iocp || tcp->shutting_down) {
 | 
	
		
			
				|  |  |      /* If we are here with from_iocp set to true, it means we got raced to
 | 
	
		
			
				|  |  |      shutting down the endpoint. No actual abort callback will happen
 | 
	
	
		
			
				|  | @@ -133,9 +135,12 @@ static void on_read(void *tcpp, int from_iocp) {
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&tcp->mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (do_abort) {
 | 
	
		
			
				|  |  | -    if (from_iocp) gpr_slice_unref(tcp->read_slice);
 | 
	
		
			
				|  |  | +    if (from_iocp) {
 | 
	
		
			
				|  |  | +      tcp->socket->read_info.outstanding = 0;
 | 
	
		
			
				|  |  | +      gpr_slice_unref(tcp->read_slice);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      tcp_unref(tcp);
 | 
	
		
			
				|  |  | -    cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
 | 
	
		
			
				|  |  | +    if (cb) cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -225,11 +230,13 @@ static void on_write(void *tcpp, int from_iocp) {
 | 
	
		
			
				|  |  |    grpc_winsocket *handle = tcp->socket;
 | 
	
		
			
				|  |  |    grpc_winsocket_callback_info *info = &handle->write_info;
 | 
	
		
			
				|  |  |    grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK;
 | 
	
		
			
				|  |  | -  grpc_endpoint_write_cb cb = tcp->write_cb;
 | 
	
		
			
				|  |  | +  grpc_endpoint_write_cb cb;
 | 
	
		
			
				|  |  |    void *opaque = tcp->write_user_data;
 | 
	
		
			
				|  |  |    int do_abort = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    gpr_mu_lock(&tcp->mu);
 | 
	
		
			
				|  |  | +  cb = tcp->write_cb;
 | 
	
		
			
				|  |  | +  tcp->write_cb = NULL;
 | 
	
		
			
				|  |  |    if (!from_iocp || tcp->shutting_down) {
 | 
	
		
			
				|  |  |      /* If we are here with from_iocp set to true, it means we got raced to
 | 
	
		
			
				|  |  |          shutting down the endpoint. No actual abort callback will happen
 | 
	
	
		
			
				|  | @@ -238,15 +245,18 @@ static void on_write(void *tcpp, int from_iocp) {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&tcp->mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  GPR_ASSERT(tcp->socket->write_info.outstanding);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    if (do_abort) {
 | 
	
		
			
				|  |  | -    if (from_iocp) gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
 | 
	
		
			
				|  |  | +    if (from_iocp) {
 | 
	
		
			
				|  |  | +      tcp->socket->write_info.outstanding = 0;
 | 
	
		
			
				|  |  | +      gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      tcp_unref(tcp);
 | 
	
		
			
				|  |  | -    cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
 | 
	
		
			
				|  |  | +    if (cb) cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  GPR_ASSERT(tcp->socket->write_info.outstanding);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    if (info->wsa_error != 0) {
 | 
	
		
			
				|  |  |      char *utf8_message = gpr_format_message(info->wsa_error);
 | 
	
		
			
				|  |  |      gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
 | 
	
	
		
			
				|  | @@ -361,11 +371,13 @@ static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
 | 
	
		
			
				|  |  |     concurrent access of the data structure in that regard. */
 | 
	
		
			
				|  |  |  static void win_shutdown(grpc_endpoint *ep) {
 | 
	
		
			
				|  |  |    grpc_tcp *tcp = (grpc_tcp *) ep;
 | 
	
		
			
				|  |  | +  int extra_refs = 0;
 | 
	
		
			
				|  |  |    gpr_mu_lock(&tcp->mu);
 | 
	
		
			
				|  |  |    /* At that point, what may happen is that we're already inside the IOCP
 | 
	
		
			
				|  |  |       callback. See the comments in on_read and on_write. */
 | 
	
		
			
				|  |  |    tcp->shutting_down = 1;
 | 
	
		
			
				|  |  | -  grpc_winsocket_shutdown(tcp->socket);
 | 
	
		
			
				|  |  | +  extra_refs = grpc_winsocket_shutdown(tcp->socket);
 | 
	
		
			
				|  |  | +  while (extra_refs--) tcp_ref(tcp);
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&tcp->mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |