Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Unified Diff: third_party/grpc/src/ruby/ext/grpc/rb_completion_queue.c

Issue 1932353002: Initial checkin of gRPC to third_party/ Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/grpc/src/ruby/ext/grpc/rb_completion_queue.c
diff --git a/third_party/grpc/src/ruby/ext/grpc/rb_completion_queue.c b/third_party/grpc/src/ruby/ext/grpc/rb_completion_queue.c
new file mode 100644
index 0000000000000000000000000000000000000000..1eb5a28750086a0017d012b9e302a1b359624c14
--- /dev/null
+++ b/third_party/grpc/src/ruby/ext/grpc/rb_completion_queue.c
@@ -0,0 +1,183 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
+#include "rb_completion_queue.h"
+
+#include <ruby/ruby.h>
+#include <ruby/thread.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/time.h>
+#include "rb_grpc.h"
+
+/* grpc_rb_cCompletionQueue is the ruby class that proxies
+ * grpc_completion_queue. */
+static VALUE grpc_rb_cCompletionQueue = Qnil;
+
+/* Used to allow grpc_completion_queue_next call to release the GIL */
+typedef struct next_call_stack {
+ grpc_completion_queue *cq;
+ grpc_event event;
+ gpr_timespec timeout;
+ void *tag;
+} next_call_stack;
+
+/* Calls grpc_completion_queue_next without holding the ruby GIL */
+static void *grpc_rb_completion_queue_next_no_gil(void *param) {
+ next_call_stack *const next_call = (next_call_stack*)param;
+ next_call->event =
+ grpc_completion_queue_next(next_call->cq, next_call->timeout, NULL);
+ return NULL;
+}
+
+/* Calls grpc_completion_queue_pluck without holding the ruby GIL */
+static void *grpc_rb_completion_queue_pluck_no_gil(void *param) {
+ next_call_stack *const next_call = (next_call_stack*)param;
+ next_call->event = grpc_completion_queue_pluck(next_call->cq, next_call->tag,
+ next_call->timeout, NULL);
+ return NULL;
+}
+
+/* Shuts down and drains the completion queue if necessary.
+ *
+ * This is done when the ruby completion queue object is about to be GCed.
+ */
+static void grpc_rb_completion_queue_shutdown_drain(grpc_completion_queue *cq) {
+ next_call_stack next_call;
+ grpc_completion_type type;
+ int drained = 0;
+ MEMZERO(&next_call, next_call_stack, 1);
+
+ grpc_completion_queue_shutdown(cq);
+ next_call.cq = cq;
+ next_call.event.type = GRPC_QUEUE_TIMEOUT;
+ /* TODO: the timeout should be a module level constant that defaults
+ * to gpr_inf_future(GPR_CLOCK_REALTIME).
+ *
+ * - at the moment this does not work, it stalls. Using a small timeout like
+ * this one works, and leads to fast test run times; a longer timeout was
+ * causing unnecessary delays in the test runs.
+ *
+ * - investigate further, this is probably another example of C-level cleanup
+ * not working consistently in all cases.
+ */
+ next_call.timeout = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_micros(5e3, GPR_TIMESPAN));
+ do {
+ rb_thread_call_without_gvl(grpc_rb_completion_queue_next_no_gil,
+ (void *)&next_call, NULL, NULL);
+ type = next_call.event.type;
+ if (type == GRPC_QUEUE_TIMEOUT) break;
+ if (type != GRPC_QUEUE_SHUTDOWN) {
+ ++drained;
+ rb_warning("completion queue shutdown: %d undrained events", drained);
+ }
+ } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+/* Helper function to free a completion queue. */
+static void grpc_rb_completion_queue_destroy(void *p) {
+ grpc_completion_queue *cq = NULL;
+ if (p == NULL) {
+ return;
+ }
+ cq = (grpc_completion_queue *)p;
+ grpc_rb_completion_queue_shutdown_drain(cq);
+ grpc_completion_queue_destroy(cq);
+}
+
+static rb_data_type_t grpc_rb_completion_queue_data_type = {
+ "grpc_completion_queue",
+ {GRPC_RB_GC_NOT_MARKED, grpc_rb_completion_queue_destroy,
+ GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
+ NULL, NULL,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ /* cannot immediately free because grpc_rb_completion_queue_shutdown_drain
+ * calls rb_thread_call_without_gvl. */
+ 0,
+#endif
+};
+
+/* Allocates a completion queue. */
+static VALUE grpc_rb_completion_queue_alloc(VALUE cls) {
+ grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+ if (cq == NULL) {
+ rb_raise(rb_eArgError, "could not create a completion queue: not sure why");
+ }
+ return TypedData_Wrap_Struct(cls, &grpc_rb_completion_queue_data_type, cq);
+}
+
+/* Blocks until the next event for given tag is available, and returns the
+ * event. */
+grpc_event grpc_rb_completion_queue_pluck_event(VALUE self, VALUE tag,
+ VALUE timeout) {
+ next_call_stack next_call;
+ MEMZERO(&next_call, next_call_stack, 1);
+ TypedData_Get_Struct(self, grpc_completion_queue,
+ &grpc_rb_completion_queue_data_type, next_call.cq);
+ if (TYPE(timeout) == T_NIL) {
+ next_call.timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
+ } else {
+ next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0);
+ }
+ if (TYPE(tag) == T_NIL) {
+ next_call.tag = NULL;
+ } else {
+ next_call.tag = ROBJECT(tag);
+ }
+ next_call.event.type = GRPC_QUEUE_TIMEOUT;
+ rb_thread_call_without_gvl(grpc_rb_completion_queue_pluck_no_gil,
+ (void *)&next_call, NULL, NULL);
+ return next_call.event;
+}
+
+void Init_grpc_completion_queue() {
+ grpc_rb_cCompletionQueue =
+ rb_define_class_under(grpc_rb_mGrpcCore, "CompletionQueue", rb_cObject);
+
+ /* constructor: uses an alloc func without an initializer. Using a simple
+ alloc func works here as the grpc header does not specify any args for
+ this func, so no separate initialization step is necessary. */
+ rb_define_alloc_func(grpc_rb_cCompletionQueue,
+ grpc_rb_completion_queue_alloc);
+}
+
+/* Gets the wrapped completion queue from the ruby wrapper */
+grpc_completion_queue *grpc_rb_get_wrapped_completion_queue(VALUE v) {
+ grpc_completion_queue *cq = NULL;
+ TypedData_Get_Struct(v, grpc_completion_queue,
+ &grpc_rb_completion_queue_data_type, cq);
+ return cq;
+}
« no previous file with comments | « third_party/grpc/src/ruby/ext/grpc/rb_completion_queue.h ('k') | third_party/grpc/src/ruby/ext/grpc/rb_event_thread.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698