|  | @@ -74,6 +74,13 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
 | 
	
		
			
				|  |  |    // all. This wrapper over our actual writeable ensures thread-safety and
 | 
	
		
			
				|  |  |    // correct ordering.
 | 
	
		
			
				|  |  |    GRXConcurrentWriteable *_responseWriteable;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // The network thread wants the requestWriter to resume (when the server is ready for more input),
 | 
	
		
			
				|  |  | +  // or to stop (on errors), concurrently with user threads that want to start it, pause it or stop
 | 
	
		
			
				|  |  | +  // it. Because a writer isn't thread-safe, we'll synchronize those operations on it.
 | 
	
		
			
				|  |  | +  // We don't use a dispatch queue for that purpose, because the writer can call writeValue: or
 | 
	
		
			
				|  |  | +  // writesFinishedWithError: on this GRPCCall as part of those operations. We want to be able to
 | 
	
		
			
				|  |  | +  // pause the writer immediately on writeValue:, so we need our locking to be recursive.
 | 
	
		
			
				|  |  |    GRXWriter *_requestWriter;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // To create a retain cycle when a call is started, up until it finishes. See
 | 
	
	
		
			
				|  | @@ -139,8 +146,10 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
 | 
	
		
			
				|  |  |    _self = nil;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // If there were still request messages coming, stop them.
 | 
	
		
			
				|  |  | -  _requestWriter.state = GRXWriterStateFinished;
 | 
	
		
			
				|  |  | -  _requestWriter = nil;
 | 
	
		
			
				|  |  | +  @synchronized(_requestWriter) {
 | 
	
		
			
				|  |  | +    _requestWriter.state = GRXWriterStateFinished;
 | 
	
		
			
				|  |  | +    _requestWriter = nil;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (errorOrNil) {
 | 
	
		
			
				|  |  |      [_responseWriteable cancelWithError:errorOrNil];
 | 
	
	
		
			
				|  | @@ -240,12 +249,14 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
 | 
	
		
			
				|  |  |      // Resume the request writer.
 | 
	
		
			
				|  |  |      GRPCCall *strongSelf = weakSelf;
 | 
	
		
			
				|  |  |      if (strongSelf) {
 | 
	
		
			
				|  |  | -      strongSelf->_requestWriter.state = GRXWriterStateStarted;
 | 
	
		
			
				|  |  | +      @synchronized(_requestWriter) {
 | 
	
		
			
				|  |  | +        strongSelf->_requestWriter.state = GRXWriterStateStarted;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    };
 | 
	
		
			
				|  |  | -  [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMessage alloc]
 | 
	
		
			
				|  |  | -                                            initWithMessage:message
 | 
	
		
			
				|  |  | -                                            handler:resumingHandler]] errorHandler:errorHandler];
 | 
	
		
			
				|  |  | +  [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMessage alloc] initWithMessage:message
 | 
	
		
			
				|  |  | +                                                                              handler:resumingHandler]]
 | 
	
		
			
				|  |  | +                            errorHandler:errorHandler];
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  - (void)writeValue:(id)value {
 | 
	
	
		
			
				|  | @@ -253,7 +264,9 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Pause the input and only resume it when the C layer notifies us that writes
 | 
	
		
			
				|  |  |    // can proceed.
 | 
	
		
			
				|  |  | -  _requestWriter.state = GRXWriterStatePaused;
 | 
	
		
			
				|  |  | +  @synchronized(_requestWriter) {
 | 
	
		
			
				|  |  | +    _requestWriter.state = GRXWriterStatePaused;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    __weak GRPCCall *weakSelf = self;
 | 
	
		
			
				|  |  |    dispatch_async(_callQueue, ^{
 | 
	
	
		
			
				|  | @@ -273,7 +286,9 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  - (void)writesFinishedWithError:(NSError *)errorOrNil {
 | 
	
		
			
				|  |  | -  _requestWriter = nil;
 | 
	
		
			
				|  |  | +  @synchronized(_requestWriter) {
 | 
	
		
			
				|  |  | +    _requestWriter = nil;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    if (errorOrNil) {
 | 
	
		
			
				|  |  |      [self cancel];
 | 
	
		
			
				|  |  |    } else {
 | 
	
	
		
			
				|  | @@ -327,7 +342,9 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }];
 | 
	
		
			
				|  |  |    // Now that the RPC has been initiated, request writes can start.
 | 
	
		
			
				|  |  | -  [_requestWriter startWithWriteable:self];
 | 
	
		
			
				|  |  | +  @synchronized(_requestWriter) {
 | 
	
		
			
				|  |  | +    [_requestWriter startWithWriteable:self];
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #pragma mark GRXWriter implementation
 |