Merge pull request #5929 from murgatroid99/backport_ruby_creds_gc

Backport "Properly mark proc used in call credentials for garbage collection" to 0.13
pull/5961/head
Jan Tattermusch 9 years ago
commit 8e996fdc02
  1. 6
      src/ruby/ext/grpc/rb_call.c
  2. 26
      src/ruby/ext/grpc/rb_call_credentials.c
  3. 22
      src/ruby/ext/grpc/rb_channel.c
  4. 23
      src/ruby/ext/grpc/rb_channel_credentials.c

@ -72,6 +72,10 @@ static ID id_cq;
* the flags used to create metadata from a Hash */ * the flags used to create metadata from a Hash */
static ID id_flags; static ID id_flags;
/* id_credentials is the name of the hidden ivar that preserves the value
* of the credentials added to the call */
static ID id_credentials;
/* id_input_md is the name of the hidden ivar that preserves the hash used to /* id_input_md is the name of the hidden ivar that preserves the hash used to
* create metadata, so that references to the strings it contains last as long * create metadata, so that references to the strings it contains last as long
* as the call the metadata is added to. */ * as the call the metadata is added to. */
@ -299,6 +303,7 @@ static VALUE grpc_rb_call_set_credentials(VALUE self, VALUE credentials) {
"grpc_call_set_credentials failed with %s (code=%d)", "grpc_call_set_credentials failed with %s (code=%d)",
grpc_call_error_detail_of(err), err); grpc_call_error_detail_of(err), err);
} }
rb_ivar_set(self, id_credentials, credentials);
return Qnil; return Qnil;
} }
@ -859,6 +864,7 @@ void Init_grpc_call() {
id_cq = rb_intern("__cq"); id_cq = rb_intern("__cq");
id_flags = rb_intern("__flags"); id_flags = rb_intern("__flags");
id_input_md = rb_intern("__input_md"); id_input_md = rb_intern("__input_md");
id_credentials = rb_intern("__credentials");
/* Ids used in constructing the batch result. */ /* Ids used in constructing the batch result. */
sym_send_message = ID2SYM(rb_intern("send_message")); sym_send_message = ID2SYM(rb_intern("send_message"));

@ -50,9 +50,9 @@
* grpc_call_credentials */ * grpc_call_credentials */
static VALUE grpc_rb_cCallCredentials = Qnil; static VALUE grpc_rb_cCallCredentials = Qnil;
/* grpc_rb_call_credentials wraps a grpc_call_credentials. It provides a peer /* grpc_rb_call_credentials wraps a grpc_call_credentials. It provides a mark
* ruby object, 'mark' to minimize copying when a credential is created from * object that is used to hold references to any objects used to create the
* ruby. */ * credentials. */
typedef struct grpc_rb_call_credentials { typedef struct grpc_rb_call_credentials {
/* Holder of ruby objects involved in contructing the credentials */ /* Holder of ruby objects involved in contructing the credentials */
VALUE mark; VALUE mark;
@ -146,13 +146,8 @@ static void grpc_rb_call_credentials_free(void *p) {
return; return;
} }
wrapper = (grpc_rb_call_credentials *)p; wrapper = (grpc_rb_call_credentials *)p;
grpc_call_credentials_release(wrapper->wrapped);
/* Delete the wrapped object if the mark object is Qnil, which indicates that wrapper->wrapped = NULL;
* no other object is the actual owner. */
if (wrapper->wrapped != NULL && wrapper->mark == Qnil) {
grpc_call_credentials_release(wrapper->wrapped);
wrapper->wrapped = NULL;
}
xfree(p); xfree(p);
} }
@ -164,8 +159,6 @@ static void grpc_rb_call_credentials_mark(void *p) {
return; return;
} }
wrapper = (grpc_rb_call_credentials *)p; wrapper = (grpc_rb_call_credentials *)p;
/* If it's not already cleaned up, mark the mark object */
if (wrapper->mark != Qnil) { if (wrapper->mark != Qnil) {
rb_gc_mark(wrapper->mark); rb_gc_mark(wrapper->mark);
} }
@ -194,7 +187,7 @@ static VALUE grpc_rb_call_credentials_alloc(VALUE cls) {
/* Creates a wrapping object for a given call credentials. This should only be /* Creates a wrapping object for a given call credentials. This should only be
* called with grpc_call_credentials objects that are not already associated * called with grpc_call_credentials objects that are not already associated
* with any Ruby object */ * with any Ruby object */
VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c) { VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c, VALUE mark) {
VALUE rb_wrapper; VALUE rb_wrapper;
grpc_rb_call_credentials *wrapper; grpc_rb_call_credentials *wrapper;
if (c == NULL) { if (c == NULL) {
@ -204,6 +197,7 @@ VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c) {
TypedData_Get_Struct(rb_wrapper, grpc_rb_call_credentials, TypedData_Get_Struct(rb_wrapper, grpc_rb_call_credentials,
&grpc_rb_call_credentials_data_type, wrapper); &grpc_rb_call_credentials_data_type, wrapper);
wrapper->wrapped = c; wrapper->wrapped = c;
wrapper->mark = mark;
return rb_wrapper; return rb_wrapper;
} }
@ -267,6 +261,7 @@ static VALUE grpc_rb_call_credentials_init(VALUE self, VALUE proc) {
return Qnil; return Qnil;
} }
wrapper->mark = proc;
wrapper->wrapped = creds; wrapper->wrapped = creds;
rb_ivar_set(self, id_callback, proc); rb_ivar_set(self, id_callback, proc);
@ -277,15 +272,18 @@ static VALUE grpc_rb_call_credentials_compose(int argc, VALUE *argv,
VALUE self) { VALUE self) {
grpc_call_credentials *creds; grpc_call_credentials *creds;
grpc_call_credentials *other; grpc_call_credentials *other;
VALUE mark;
if (argc == 0) { if (argc == 0) {
return self; return self;
} }
mark = rb_ary_new();
creds = grpc_rb_get_wrapped_call_credentials(self); creds = grpc_rb_get_wrapped_call_credentials(self);
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
rb_ary_push(mark, argv[i]);
other = grpc_rb_get_wrapped_call_credentials(argv[i]); other = grpc_rb_get_wrapped_call_credentials(argv[i]);
creds = grpc_composite_call_credentials_create(creds, other, NULL); creds = grpc_composite_call_credentials_create(creds, other, NULL);
} }
return grpc_rb_wrap_call_credentials(creds); return grpc_rb_wrap_call_credentials(creds, mark);
} }
void Init_grpc_call_credentials() { void Init_grpc_call_credentials() {

@ -70,11 +70,10 @@ static VALUE grpc_rb_cChannel = Qnil;
/* Used during the conversion of a hash to channel args during channel setup */ /* Used during the conversion of a hash to channel args during channel setup */
static VALUE grpc_rb_cChannelArgs; static VALUE grpc_rb_cChannelArgs;
/* grpc_rb_channel wraps a grpc_channel. It provides a peer ruby object, /* grpc_rb_channel wraps a grpc_channel. */
* 'mark' to minimize copying when a channel is created from ruby. */
typedef struct grpc_rb_channel { typedef struct grpc_rb_channel {
/* Holder of ruby objects involved in constructing the channel */ VALUE credentials;
VALUE mark;
/* The actual channel */ /* The actual channel */
grpc_channel *wrapped; grpc_channel *wrapped;
} grpc_rb_channel; } grpc_rb_channel;
@ -87,13 +86,8 @@ static void grpc_rb_channel_free(void *p) {
}; };
ch = (grpc_rb_channel *)p; ch = (grpc_rb_channel *)p;
/* Deletes the wrapped object if the mark object is Qnil, which indicates if (ch->wrapped != NULL) {
* that no other object is the actual owner. */
if (ch->wrapped != NULL && ch->mark == Qnil) {
grpc_channel_destroy(ch->wrapped); grpc_channel_destroy(ch->wrapped);
rb_warning("channel gc: destroyed the c channel");
} else {
rb_warning("channel gc: did not destroy the c channel");
} }
xfree(p); xfree(p);
@ -106,8 +100,8 @@ static void grpc_rb_channel_mark(void *p) {
return; return;
} }
channel = (grpc_rb_channel *)p; channel = (grpc_rb_channel *)p;
if (channel->mark != Qnil) { if (channel->credentials != Qnil) {
rb_gc_mark(channel->mark); rb_gc_mark(channel->credentials);
} }
} }
@ -125,7 +119,7 @@ static rb_data_type_t grpc_channel_data_type = {
static VALUE grpc_rb_channel_alloc(VALUE cls) { static VALUE grpc_rb_channel_alloc(VALUE cls) {
grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel); grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel);
wrapper->wrapped = NULL; wrapper->wrapped = NULL;
wrapper->mark = Qnil; wrapper->credentials = Qnil;
return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper); return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper);
} }
@ -162,6 +156,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
} }
ch = grpc_insecure_channel_create(target_chars, &args, NULL); ch = grpc_insecure_channel_create(target_chars, &args, NULL);
} else { } else {
wrapper->credentials = credentials;
creds = grpc_rb_get_wrapped_channel_credentials(credentials); creds = grpc_rb_get_wrapped_channel_credentials(credentials);
ch = grpc_secure_channel_create(creds, target_chars, &args, NULL); ch = grpc_secure_channel_create(creds, target_chars, &args, NULL);
} }
@ -330,7 +325,6 @@ static VALUE grpc_rb_channel_destroy(VALUE self) {
if (ch != NULL) { if (ch != NULL) {
grpc_channel_destroy(ch); grpc_channel_destroy(ch);
wrapper->wrapped = NULL; wrapper->wrapped = NULL;
wrapper->mark = Qnil;
} }
return Qnil; return Qnil;

@ -49,8 +49,8 @@
static VALUE grpc_rb_cChannelCredentials = Qnil; static VALUE grpc_rb_cChannelCredentials = Qnil;
/* grpc_rb_channel_credentials wraps a grpc_channel_credentials. It provides a /* grpc_rb_channel_credentials wraps a grpc_channel_credentials. It provides a
* peer ruby object, 'mark' to minimize copying when a credential is * mark object that is used to hold references to any objects used to create
* created from ruby. */ * the credentials. */
typedef struct grpc_rb_channel_credentials { typedef struct grpc_rb_channel_credentials {
/* Holder of ruby objects involved in constructing the credentials */ /* Holder of ruby objects involved in constructing the credentials */
VALUE mark; VALUE mark;
@ -66,13 +66,8 @@ static void grpc_rb_channel_credentials_free(void *p) {
return; return;
}; };
wrapper = (grpc_rb_channel_credentials *)p; wrapper = (grpc_rb_channel_credentials *)p;
grpc_channel_credentials_release(wrapper->wrapped);
/* Delete the wrapped object if the mark object is Qnil, which indicates that wrapper->wrapped = NULL;
* no other object is the actual owner. */
if (wrapper->wrapped != NULL && wrapper->mark == Qnil) {
grpc_channel_credentials_release(wrapper->wrapped);
wrapper->wrapped = NULL;
}
xfree(p); xfree(p);
} }
@ -85,7 +80,6 @@ static void grpc_rb_channel_credentials_mark(void *p) {
} }
wrapper = (grpc_rb_channel_credentials *)p; wrapper = (grpc_rb_channel_credentials *)p;
/* If it's not already cleaned up, mark the mark object */
if (wrapper->mark != Qnil) { if (wrapper->mark != Qnil) {
rb_gc_mark(wrapper->mark); rb_gc_mark(wrapper->mark);
} }
@ -114,7 +108,7 @@ static VALUE grpc_rb_channel_credentials_alloc(VALUE cls) {
/* Creates a wrapping object for a given channel credentials. This should only /* Creates a wrapping object for a given channel credentials. This should only
* be called with grpc_channel_credentials objects that are not already * be called with grpc_channel_credentials objects that are not already
* associated with any Ruby object. */ * associated with any Ruby object. */
VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c) { VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c, VALUE mark) {
VALUE rb_wrapper; VALUE rb_wrapper;
grpc_rb_channel_credentials *wrapper; grpc_rb_channel_credentials *wrapper;
if (c == NULL) { if (c == NULL) {
@ -124,6 +118,7 @@ VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c) {
TypedData_Get_Struct(rb_wrapper, grpc_rb_channel_credentials, TypedData_Get_Struct(rb_wrapper, grpc_rb_channel_credentials,
&grpc_rb_channel_credentials_data_type, wrapper); &grpc_rb_channel_credentials_data_type, wrapper);
wrapper->wrapped = c; wrapper->wrapped = c;
wrapper->mark = mark;
return rb_wrapper; return rb_wrapper;
} }
@ -222,11 +217,15 @@ static VALUE grpc_rb_channel_credentials_compose(int argc, VALUE *argv,
VALUE self) { VALUE self) {
grpc_channel_credentials *creds; grpc_channel_credentials *creds;
grpc_call_credentials *other; grpc_call_credentials *other;
VALUE mark;
if (argc == 0) { if (argc == 0) {
return self; return self;
} }
mark = rb_ary_new();
rb_ary_push(mark, self);
creds = grpc_rb_get_wrapped_channel_credentials(self); creds = grpc_rb_get_wrapped_channel_credentials(self);
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
rb_ary_push(mark, argv[i]);
other = grpc_rb_get_wrapped_call_credentials(argv[i]); other = grpc_rb_get_wrapped_call_credentials(argv[i]);
creds = grpc_composite_channel_credentials_create(creds, other, NULL); creds = grpc_composite_channel_credentials_create(creds, other, NULL);
if (creds == NULL) { if (creds == NULL) {
@ -234,7 +233,7 @@ static VALUE grpc_rb_channel_credentials_compose(int argc, VALUE *argv,
"Failed to compose channel and call credentials"); "Failed to compose channel and call credentials");
} }
} }
return grpc_rb_wrap_channel_credentials(creds); return grpc_rb_wrap_channel_credentials(creds, mark);
} }
void Init_grpc_channel_credentials() { void Init_grpc_channel_credentials() {

Loading…
Cancel
Save