|  | @@ -101,30 +101,14 @@ static VALUE sym_message;
 | 
	
		
			
				|  |  |  static VALUE sym_status;
 | 
	
		
			
				|  |  |  static VALUE sym_cancelled;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/* hash_all_calls is a hash of Call address -> reference count that is used to
 | 
	
		
			
				|  |  | - * track the creation and destruction of rb_call instances.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -static VALUE hash_all_calls;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /* Destroys a Call. */
 | 
	
		
			
				|  |  |  static void grpc_rb_call_destroy(void *p) {
 | 
	
		
			
				|  |  | -  grpc_call *call = NULL;
 | 
	
		
			
				|  |  | -  VALUE ref_count = Qnil;
 | 
	
		
			
				|  |  | +  grpc_call* call = NULL;
 | 
	
		
			
				|  |  |    if (p == NULL) {
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  | -  };
 | 
	
		
			
				|  |  | -  call = (grpc_call *)p;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  ref_count = rb_hash_aref(hash_all_calls, OFFT2NUM((VALUE)call));
 | 
	
		
			
				|  |  | -  if (ref_count == Qnil) {
 | 
	
		
			
				|  |  | -    return; /* No longer in the hash, so already deleted */
 | 
	
		
			
				|  |  | -  } else if (NUM2UINT(ref_count) == 1) {
 | 
	
		
			
				|  |  | -    rb_hash_delete(hash_all_calls, OFFT2NUM((VALUE)call));
 | 
	
		
			
				|  |  | -    grpc_call_destroy(call);
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)call),
 | 
	
		
			
				|  |  | -                 UINT2NUM(NUM2UINT(ref_count) - 1));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  call = (grpc_call *)p;
 | 
	
		
			
				|  |  | +  grpc_call_destroy(call);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static size_t md_ary_datasize(const void *p) {
 | 
	
	
		
			
				|  | @@ -151,7 +135,7 @@ static const rb_data_type_t grpc_rb_md_ary_data_type = {
 | 
	
		
			
				|  |  |       * touches a hash object.
 | 
	
		
			
				|  |  |       * TODO(yugui) Directly use st_table and call the free function earlier?
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  | -    0,
 | 
	
		
			
				|  |  | +     0,
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -163,12 +147,7 @@ static const rb_data_type_t grpc_call_data_type = {
 | 
	
		
			
				|  |  |      NULL,
 | 
	
		
			
				|  |  |      NULL,
 | 
	
		
			
				|  |  |  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
 | 
	
		
			
				|  |  | -    /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because
 | 
	
		
			
				|  |  | -     * grpc_rb_call_destroy
 | 
	
		
			
				|  |  | -     * touches a hash object.
 | 
	
		
			
				|  |  | -     * TODO(yugui) Directly use st_table and call the free function earlier?
 | 
	
		
			
				|  |  | -     */
 | 
	
		
			
				|  |  | -    0,
 | 
	
		
			
				|  |  | +    RUBY_TYPED_FREE_IMMEDIATELY
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -190,6 +169,11 @@ const char *grpc_call_error_detail_of(grpc_call_error err) {
 | 
	
		
			
				|  |  |  static VALUE grpc_rb_call_cancel(VALUE self) {
 | 
	
		
			
				|  |  |    grpc_call *call = NULL;
 | 
	
		
			
				|  |  |    grpc_call_error err;
 | 
	
		
			
				|  |  | +  if (RTYPEDDATA_DATA(self) == NULL) {
 | 
	
		
			
				|  |  | +    //This call has been closed
 | 
	
		
			
				|  |  | +    return Qnil;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
 | 
	
		
			
				|  |  |    err = grpc_call_cancel(call, NULL);
 | 
	
		
			
				|  |  |    if (err != GRPC_CALL_OK) {
 | 
	
	
		
			
				|  | @@ -200,11 +184,29 @@ static VALUE grpc_rb_call_cancel(VALUE self) {
 | 
	
		
			
				|  |  |    return Qnil;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* Releases the c-level resources associated with a call
 | 
	
		
			
				|  |  | +   Once a call has been closed, no further requests can be
 | 
	
		
			
				|  |  | +   processed.
 | 
	
		
			
				|  |  | +*/
 | 
	
		
			
				|  |  | +static VALUE grpc_rb_call_close(VALUE self) {
 | 
	
		
			
				|  |  | +  grpc_call *call = NULL;
 | 
	
		
			
				|  |  | +  TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
 | 
	
		
			
				|  |  | +  if(call != NULL) {
 | 
	
		
			
				|  |  | +    grpc_call_destroy(call);
 | 
	
		
			
				|  |  | +    RTYPEDDATA_DATA(self) = NULL;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return Qnil;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /* Called to obtain the peer that this call is connected to. */
 | 
	
		
			
				|  |  |  static VALUE grpc_rb_call_get_peer(VALUE self) {
 | 
	
		
			
				|  |  |    VALUE res = Qnil;
 | 
	
		
			
				|  |  |    grpc_call *call = NULL;
 | 
	
		
			
				|  |  |    char *peer = NULL;
 | 
	
		
			
				|  |  | +  if (RTYPEDDATA_DATA(self) == NULL) {
 | 
	
		
			
				|  |  | +    rb_raise(grpc_rb_eCallError, "Cannot get peer value on closed call");
 | 
	
		
			
				|  |  | +    return Qnil;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
 | 
	
		
			
				|  |  |    peer = grpc_call_get_peer(call);
 | 
	
		
			
				|  |  |    res = rb_str_new2(peer);
 | 
	
	
		
			
				|  | @@ -218,6 +220,10 @@ static VALUE grpc_rb_call_get_peer_cert(VALUE self) {
 | 
	
		
			
				|  |  |    grpc_call *call = NULL;
 | 
	
		
			
				|  |  |    VALUE res = Qnil;
 | 
	
		
			
				|  |  |    grpc_auth_context *ctx = NULL;
 | 
	
		
			
				|  |  | +  if (RTYPEDDATA_DATA(self) == NULL) {
 | 
	
		
			
				|  |  | +    rb_raise(grpc_rb_eCallError, "Cannot get peer cert on closed call");
 | 
	
		
			
				|  |  | +    return Qnil;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    ctx = grpc_call_auth_context(call);
 | 
	
	
		
			
				|  | @@ -323,6 +329,10 @@ static VALUE grpc_rb_call_set_credentials(VALUE self, VALUE credentials) {
 | 
	
		
			
				|  |  |    grpc_call *call = NULL;
 | 
	
		
			
				|  |  |    grpc_call_credentials *creds;
 | 
	
		
			
				|  |  |    grpc_call_error err;
 | 
	
		
			
				|  |  | +  if (RTYPEDDATA_DATA(self) == NULL) {
 | 
	
		
			
				|  |  | +    rb_raise(grpc_rb_eCallError, "Cannot set credentials of closed call");
 | 
	
		
			
				|  |  | +    return Qnil;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
 | 
	
		
			
				|  |  |    creds = grpc_rb_get_wrapped_call_credentials(credentials);
 | 
	
		
			
				|  |  |    err = grpc_call_set_credentials(call, creds);
 | 
	
	
		
			
				|  | @@ -731,7 +741,7 @@ static VALUE grpc_run_batch_stack_build_result(run_batch_stack *st) {
 | 
	
		
			
				|  |  |     }
 | 
	
		
			
				|  |  |     tag = Object.new
 | 
	
		
			
				|  |  |     timeout = 10
 | 
	
		
			
				|  |  | -   call.start_batch(cqueue, tag, timeout, ops)
 | 
	
		
			
				|  |  | +   call.start_batch(cq, tag, timeout, ops)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     Start a batch of operations defined in the array ops; when complete, post a
 | 
	
		
			
				|  |  |     completion of type 'tag' to the completion queue bound to the call.
 | 
	
	
		
			
				|  | @@ -749,6 +759,10 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag,
 | 
	
		
			
				|  |  |    VALUE result = Qnil;
 | 
	
		
			
				|  |  |    VALUE rb_write_flag = rb_ivar_get(self, id_write_flag);
 | 
	
		
			
				|  |  |    unsigned write_flag = 0;
 | 
	
		
			
				|  |  | +  if (RTYPEDDATA_DATA(self) == NULL) {
 | 
	
		
			
				|  |  | +    rb_raise(grpc_rb_eCallError, "Cannot run batch on closed call");
 | 
	
		
			
				|  |  | +    return Qnil;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Validate the ops args, adding them to a ruby array */
 | 
	
	
		
			
				|  | @@ -888,6 +902,7 @@ void Init_grpc_call() {
 | 
	
		
			
				|  |  |    /* Add ruby analogues of the Call methods. */
 | 
	
		
			
				|  |  |    rb_define_method(grpc_rb_cCall, "run_batch", grpc_rb_call_run_batch, 4);
 | 
	
		
			
				|  |  |    rb_define_method(grpc_rb_cCall, "cancel", grpc_rb_call_cancel, 0);
 | 
	
		
			
				|  |  | +  rb_define_method(grpc_rb_cCall, "close", grpc_rb_call_close, 0);
 | 
	
		
			
				|  |  |    rb_define_method(grpc_rb_cCall, "peer", grpc_rb_call_get_peer, 0);
 | 
	
		
			
				|  |  |    rb_define_method(grpc_rb_cCall, "peer_cert", grpc_rb_call_get_peer_cert, 0);
 | 
	
		
			
				|  |  |    rb_define_method(grpc_rb_cCall, "status", grpc_rb_call_get_status, 0);
 | 
	
	
		
			
				|  | @@ -925,11 +940,6 @@ void Init_grpc_call() {
 | 
	
		
			
				|  |  |        "BatchResult", "send_message", "send_metadata", "send_close",
 | 
	
		
			
				|  |  |        "send_status", "message", "metadata", "status", "cancelled", NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* The hash for reference counting calls, to ensure they can't be destroyed
 | 
	
		
			
				|  |  | -   * more than once */
 | 
	
		
			
				|  |  | -  hash_all_calls = rb_hash_new();
 | 
	
		
			
				|  |  | -  rb_define_const(grpc_rb_cCall, "INTERNAL_ALL_CALLs", hash_all_calls);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    Init_grpc_error_codes();
 | 
	
		
			
				|  |  |    Init_grpc_op_codes();
 | 
	
		
			
				|  |  |    Init_grpc_write_flags();
 | 
	
	
		
			
				|  | @@ -944,16 +954,8 @@ grpc_call *grpc_rb_get_wrapped_call(VALUE v) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Obtains the wrapped object for a given call */
 | 
	
		
			
				|  |  |  VALUE grpc_rb_wrap_call(grpc_call *c) {
 | 
	
		
			
				|  |  | -  VALUE obj = Qnil;
 | 
	
		
			
				|  |  |    if (c == NULL) {
 | 
	
		
			
				|  |  |      return Qnil;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  obj = rb_hash_aref(hash_all_calls, OFFT2NUM((VALUE)c));
 | 
	
		
			
				|  |  | -  if (obj == Qnil) { /* Not in the hash add it */
 | 
	
		
			
				|  |  | -    rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c), UINT2NUM(1));
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c),
 | 
	
		
			
				|  |  | -                 UINT2NUM(NUM2UINT(obj) + 1));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |    return TypedData_Wrap_Struct(grpc_rb_cCall, &grpc_call_data_type, c);
 | 
	
		
			
				|  |  |  }
 |