Exposes event#finish as #close.

- ensures that it's a runtime error if an event if used after it's finished

- updates all calls where the completion_queue is used to ensure the event's
retrieved are explicitly finished
	Change on 2014/12/18 by temiola <temiola@google.com>
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=82445748
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 872f8e3..bf292fa 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -38,7 +38,6 @@
 #include <grpc/grpc.h>
 #include "rb_byte_buffer.h"
 #include "rb_completion_queue.h"
-#include "rb_event.h"
 #include "rb_metadata.h"
 #include "rb_grpc.h"
 
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index dfde442..dc95838 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -141,8 +141,7 @@
   if (next_call.event == NULL) {
     return Qnil;
   }
-  return Data_Wrap_Struct(rb_cEvent, GC_NOT_MARKED, grpc_rb_event_finish,
-                          next_call.event);
+  return grpc_rb_new_event(next_call.event);
 }
 
 /* Blocks until the next event for given tag is available, and returns the
@@ -160,8 +159,7 @@
   if (next_call.event == NULL) {
     return Qnil;
   }
-  return Data_Wrap_Struct(rb_cEvent, GC_NOT_MARKED, grpc_rb_event_finish,
-                          next_call.event);
+  return grpc_rb_new_event(next_call.event);
 }
 
 /* rb_cCompletionQueue is the ruby class that proxies grpc_completion_queue. */
diff --git a/src/ruby/ext/grpc/rb_event.c b/src/ruby/ext/grpc/rb_event.c
index 76ea6ad..9200f92 100644
--- a/src/ruby/ext/grpc/rb_event.c
+++ b/src/ruby/ext/grpc/rb_event.c
@@ -41,12 +41,49 @@
 #include "rb_call.h"
 #include "rb_metadata.h"
 
+/* grpc_rb_event wraps a grpc_event.  It provides a peer ruby object,
+ * 'mark' to minimize copying when an event is created from ruby. */
+typedef struct grpc_rb_event {
+  /* Holder of ruby objects involved in constructing the channel */
+  VALUE mark;
+  /* The actual event */
+  grpc_event *wrapped;
+} grpc_rb_event;
+
+
 /* rb_mCompletionType is a ruby module that holds the completion type values */
 VALUE rb_mCompletionType = Qnil;
 
-/* Helper function to free an event. */
-void grpc_rb_event_finish(void *p) {
-  grpc_event_finish(p);
+/* Destroys Event instances. */
+static void grpc_rb_event_free(void *p) {
+  grpc_rb_event *ev = NULL;
+  if (p == NULL) {
+    return;
+  };
+  ev = (grpc_rb_event *)p;
+
+  /* Deletes the wrapped object if the mark object is Qnil, which indicates
+   * that no other object is the actual owner. */
+  if (ev->wrapped != NULL && ev->mark == Qnil) {
+    grpc_event_finish(ev->wrapped);
+    rb_warning("event gc: destroyed the c event");
+  } else {
+    rb_warning("event gc: did not destroy the c event");
+  }
+
+  xfree(p);
+}
+
+/* Protects the mark object from GC */
+static void grpc_rb_event_mark(void *p) {
+  grpc_rb_event *event = NULL;
+  if (p == NULL) {
+    return;
+  }
+  event = (grpc_rb_event *)p;
+  if (event->mark != Qnil) {
+    rb_gc_mark(event->mark);
+  }
 }
 
 static VALUE grpc_rb_event_result(VALUE self);
@@ -54,7 +91,14 @@
 /* Obtains the type of an event. */
 static VALUE grpc_rb_event_type(VALUE self) {
   grpc_event *event = NULL;
-  Data_Get_Struct(self, grpc_event, event);
+  grpc_rb_event *wrapper = NULL;
+  Data_Get_Struct(self, grpc_rb_event, wrapper);
+  if (wrapper->wrapped == NULL) {
+    rb_raise(rb_eRuntimeError, "finished!");
+    return Qnil;
+  }
+
+  event = wrapper->wrapped;
   switch (event->type) {
     case GRPC_QUEUE_SHUTDOWN:
       return rb_const_get(rb_mCompletionType, rb_intern("QUEUE_SHUTDOWN"));
@@ -94,7 +138,14 @@
 /* Obtains the tag associated with an event. */
 static VALUE grpc_rb_event_tag(VALUE self) {
   grpc_event *event = NULL;
-  Data_Get_Struct(self, grpc_event, event);
+  grpc_rb_event *wrapper = NULL;
+  Data_Get_Struct(self, grpc_rb_event, wrapper);
+  if (wrapper->wrapped == NULL) {
+    rb_raise(rb_eRuntimeError, "finished!");
+    return Qnil;
+  }
+
+  event = wrapper->wrapped;
   if (event->tag == NULL) {
     return Qnil;
   }
@@ -103,10 +154,17 @@
 
 /* Obtains the call associated with an event. */
 static VALUE grpc_rb_event_call(VALUE self) {
-  grpc_event *ev = NULL;
-  Data_Get_Struct(self, grpc_event, ev);
-  if (ev->call != NULL) {
-    return grpc_rb_wrap_call(ev->call);
+  grpc_event *event = NULL;
+  grpc_rb_event *wrapper = NULL;
+  Data_Get_Struct(self, grpc_rb_event, wrapper);
+  if (wrapper->wrapped == NULL) {
+    rb_raise(rb_eRuntimeError, "finished!");
+    return Qnil;
+  }
+
+  event = wrapper->wrapped;
+  if (event->call != NULL) {
+    return grpc_rb_wrap_call(event->call);
   }
   return Qnil;
 }
@@ -114,6 +172,7 @@
 /* Obtains the metadata associated with an event. */
 static VALUE grpc_rb_event_metadata(VALUE self) {
   grpc_event *event = NULL;
+  grpc_rb_event *wrapper = NULL;
   grpc_metadata *metadata = NULL;
   VALUE key = Qnil;
   VALUE new_ary = Qnil;
@@ -121,9 +180,14 @@
   VALUE value = Qnil;
   size_t count = 0;
   size_t i = 0;
+  Data_Get_Struct(self, grpc_rb_event, wrapper);
+  if (wrapper->wrapped == NULL) {
+    rb_raise(rb_eRuntimeError, "finished!");
+    return Qnil;
+  }
 
   /* Figure out which metadata to read. */
-  Data_Get_Struct(self, grpc_event, event);
+  event = wrapper->wrapped;
   switch (event->type) {
 
     case GRPC_CLIENT_METADATA_READ:
@@ -179,7 +243,13 @@
 /* Obtains the data associated with an event. */
 static VALUE grpc_rb_event_result(VALUE self) {
   grpc_event *event = NULL;
-  Data_Get_Struct(self, grpc_event, event);
+  grpc_rb_event *wrapper = NULL;
+  Data_Get_Struct(self, grpc_rb_event, wrapper);
+  if (wrapper->wrapped == NULL) {
+    rb_raise(rb_eRuntimeError, "finished!");
+    return Qnil;
+  }
+  event = wrapper->wrapped;
 
   switch (event->type) {
 
@@ -245,11 +315,19 @@
   return Qfalse;
 }
 
-/* rb_sNewServerRpc is the struct that holds new server rpc details. */
-VALUE rb_sNewServerRpc = Qnil;
-
-/* rb_sStatus is the struct that holds status details. */
-VALUE rb_sStatus = Qnil;
+static VALUE grpc_rb_event_finish(VALUE self) {
+  grpc_event *event = NULL;
+  grpc_rb_event *wrapper = NULL;
+  Data_Get_Struct(self, grpc_rb_event, wrapper);
+  if (wrapper->wrapped == NULL) {  /* already closed  */
+    return Qnil;
+  }
+  event = wrapper->wrapped;
+  grpc_event_finish(event);
+  wrapper->wrapped = NULL;
+  wrapper->mark = Qnil;
+  return Qnil;
+}
 
 /* rb_cEvent is the Event class whose instances proxy grpc_event */
 VALUE rb_cEvent = Qnil;
@@ -262,9 +340,6 @@
   rb_eEventError = rb_define_class_under(rb_mGoogleRpcCore, "EventError",
                                          rb_eStandardError);
   rb_cEvent = rb_define_class_under(rb_mGoogleRpcCore, "Event", rb_cObject);
-  rb_sNewServerRpc = rb_struct_define("NewServerRpc", "method", "host",
-                                      "deadline", "metadata", NULL);
-  rb_sStatus = rb_struct_define("Status", "code", "details", "metadata", NULL);
 
   /* Prevent allocation or inialization from ruby. */
   rb_define_alloc_func(rb_cEvent, grpc_rb_cannot_alloc);
@@ -276,6 +351,8 @@
   rb_define_method(rb_cEvent, "result", grpc_rb_event_result, 0);
   rb_define_method(rb_cEvent, "tag", grpc_rb_event_tag, 0);
   rb_define_method(rb_cEvent, "type", grpc_rb_event_type, 0);
+  rb_define_method(rb_cEvent, "finish", grpc_rb_event_finish, 0);
+  rb_define_alias(rb_cEvent, "close", "finish");
 
   /* Constants representing the completion types */
   rb_mCompletionType = rb_define_module_under(rb_mGoogleRpcCore,
@@ -298,3 +375,11 @@
   rb_define_const(rb_mCompletionType, "RESERVED",
                   INT2NUM(GRPC_COMPLETION_DO_NOT_USE));
 }
+
+VALUE grpc_rb_new_event(grpc_event *ev) {
+  grpc_rb_event *wrapper = ALLOC(grpc_rb_event);
+  wrapper->wrapped = ev;
+  wrapper->mark = Qnil;
+  return Data_Wrap_Struct(rb_cEvent, grpc_rb_event_mark, grpc_rb_event_free,
+                          wrapper);
+}
diff --git a/src/ruby/ext/grpc/rb_event.h b/src/ruby/ext/grpc/rb_event.h
index 459502c..e4e4a79 100644
--- a/src/ruby/ext/grpc/rb_event.h
+++ b/src/ruby/ext/grpc/rb_event.h
@@ -35,12 +35,7 @@
 #define GRPC_RB_EVENT_H_
 
 #include <ruby.h>
-
-/* rb_sNewServerRpc is the struct that holds new server rpc details. */
-extern VALUE rb_sNewServerRpc;
-
-/* rb_sStruct is the struct that holds status details. */
-extern VALUE rb_sStatus;
+#include <grpc/grpc.h>
 
 /* rb_cEvent is the Event class whose instances proxy grpc_event. */
 extern VALUE rb_cEvent;
@@ -49,8 +44,8 @@
    event processing. */
 extern VALUE rb_eEventError;
 
-/* Helper function to free an event. */
-void grpc_rb_event_finish(void *p);
+/* Used to create new ruby event objects */
+VALUE grpc_rb_new_event(grpc_event *ev);
 
 /* Initializes the Event and EventError classes. */
 void Init_google_rpc_event();
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index f0e432a..eae011d 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -245,16 +245,27 @@
   grpc_shutdown();
 }
 
+/* Initialize the Google RPC module structs */
+
+/* rb_sNewServerRpc is the struct that holds new server rpc details. */
+VALUE rb_sNewServerRpc = Qnil;
+/* rb_sStatus is the struct that holds status details. */
+VALUE rb_sStatus = Qnil;
+
 /* Initialize the Google RPC module. */
 VALUE rb_mGoogle = Qnil;
 VALUE rb_mGoogleRPC = Qnil;
 VALUE rb_mGoogleRpcCore = Qnil;
+
 void Init_grpc() {
   grpc_init();
   ruby_vm_at_exit(grpc_rb_shutdown);
   rb_mGoogle = rb_define_module("Google");
   rb_mGoogleRPC = rb_define_module_under(rb_mGoogle, "RPC");
   rb_mGoogleRpcCore = rb_define_module_under(rb_mGoogleRPC, "Core");
+  rb_sNewServerRpc = rb_struct_define("NewServerRpc", "method", "host",
+                                      "deadline", "metadata", NULL);
+  rb_sStatus = rb_struct_define("Status", "code", "details", "metadata", NULL);
 
   Init_google_rpc_byte_buffer();
   Init_google_rpc_event();
diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h
index 68f8a06..c2c8942 100644
--- a/src/ruby/ext/grpc/rb_grpc.h
+++ b/src/ruby/ext/grpc/rb_grpc.h
@@ -47,6 +47,12 @@
 /* Class used to wrap timeval structs. */
 extern VALUE rb_cTimeVal;
 
+/* rb_sNewServerRpc is the struct that holds new server rpc details. */
+extern VALUE rb_sNewServerRpc;
+
+/* rb_sStruct is the struct that holds status details. */
+extern VALUE rb_sStatus;
+
 /* GC_NOT_MARKED is used in calls to Data_Wrap_Struct to indicate that the
    wrapped struct does not need to participate in ruby gc. */
 extern const RUBY_DATA_FUNC GC_NOT_MARKED;