grpc 0.15.0 → 1.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grpc might be problematic. Click here for more details.

Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +127 -159
  3. data/etc/roots.pem +784 -509
  4. data/include/grpc/grpc_posix.h +8 -0
  5. data/include/grpc/impl/codegen/byte_buffer.h +5 -4
  6. data/include/grpc/impl/codegen/grpc_types.h +2 -0
  7. data/include/grpc/impl/codegen/port_platform.h +2 -1
  8. data/include/grpc/module.modulemap +15 -0
  9. data/src/core/ext/census/grpc_filter.c +3 -0
  10. data/src/core/ext/client_config/channel_connectivity.c +4 -3
  11. data/src/core/ext/client_config/client_channel.c +6 -0
  12. data/src/core/ext/client_config/subchannel.c +2 -0
  13. data/src/core/ext/client_config/subchannel_call_holder.c +2 -5
  14. data/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c +2 -1
  15. data/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c +2 -1
  16. data/src/core/ext/transport/chttp2/transport/chttp2_transport.c +171 -104
  17. data/src/core/ext/transport/chttp2/transport/internal.h +5 -3
  18. data/src/core/ext/transport/chttp2/transport/parsing.c +4 -3
  19. data/src/core/ext/transport/chttp2/transport/status_conversion.c +8 -2
  20. data/src/core/ext/transport/chttp2/transport/status_conversion.h +1 -1
  21. data/src/core/lib/channel/channel_stack.c +12 -1
  22. data/src/core/lib/channel/channel_stack.h +5 -0
  23. data/src/core/lib/channel/http_client_filter.c +7 -1
  24. data/src/core/lib/debug/trace.c +6 -2
  25. data/src/core/lib/iomgr/error.c +62 -19
  26. data/src/core/lib/iomgr/error.h +10 -6
  27. data/src/core/lib/iomgr/ev_epoll_linux.c +1872 -0
  28. data/src/core/lib/{surface/surface_trace.h → iomgr/ev_epoll_linux.h} +11 -12
  29. data/src/core/lib/iomgr/ev_posix.c +9 -6
  30. data/src/core/lib/iomgr/ev_posix.h +3 -0
  31. data/src/core/lib/iomgr/network_status_tracker.c +121 -0
  32. data/{include/grpc/grpc_zookeeper.h → src/core/lib/iomgr/network_status_tracker.h} +8 -26
  33. data/src/core/lib/iomgr/socket_utils_common_posix.c +22 -0
  34. data/src/core/lib/iomgr/socket_utils_posix.h +3 -0
  35. data/src/core/lib/iomgr/tcp_posix.c +6 -2
  36. data/src/core/lib/iomgr/tcp_server.h +3 -0
  37. data/src/core/lib/iomgr/tcp_server_posix.c +114 -16
  38. data/src/core/lib/iomgr/tcp_server_windows.c +1 -0
  39. data/src/core/lib/iomgr/tcp_windows.c +5 -0
  40. data/src/core/lib/iomgr/udp_server.c +28 -16
  41. data/src/core/lib/iomgr/wakeup_fd_eventfd.c +4 -2
  42. data/src/core/lib/profiling/basic_timers.c +4 -4
  43. data/src/core/lib/security/credentials/composite/composite_credentials.c +4 -3
  44. data/src/core/lib/security/credentials/credentials.c +1 -1
  45. data/src/core/lib/security/credentials/credentials.h +4 -5
  46. data/src/core/lib/security/credentials/fake/fake_credentials.c +2 -2
  47. data/src/core/lib/security/credentials/iam/iam_credentials.c +1 -1
  48. data/src/core/lib/security/credentials/jwt/jwt_credentials.c +7 -6
  49. data/src/core/lib/security/credentials/oauth2/oauth2_credentials.c +6 -4
  50. data/src/core/lib/security/credentials/plugin/plugin_credentials.c +4 -3
  51. data/src/core/lib/security/transport/client_auth_filter.c +10 -7
  52. data/src/core/lib/surface/byte_buffer_reader.c +6 -4
  53. data/src/core/lib/surface/call.c +64 -51
  54. data/src/core/lib/surface/call.h +0 -1
  55. data/src/core/lib/surface/channel.c +10 -8
  56. data/src/core/lib/surface/completion_queue.c +26 -12
  57. data/src/core/lib/surface/completion_queue.h +4 -0
  58. data/src/core/lib/surface/init.c +6 -1
  59. data/src/core/lib/surface/version.c +1 -1
  60. data/src/core/lib/transport/transport.c +62 -29
  61. data/src/core/lib/transport/transport.h +8 -5
  62. data/src/core/lib/transport/transport_op_string.c +14 -3
  63. data/src/ruby/ext/grpc/rb_byte_buffer.c +4 -1
  64. data/src/ruby/ext/grpc/rb_call.c +87 -54
  65. data/src/ruby/ext/grpc/rb_call.h +1 -1
  66. data/src/ruby/ext/grpc/rb_call_credentials.c +1 -30
  67. data/src/ruby/ext/grpc/rb_channel.c +25 -50
  68. data/src/ruby/ext/grpc/rb_channel_credentials.c +1 -31
  69. data/src/ruby/ext/grpc/rb_completion_queue.c +15 -134
  70. data/src/ruby/ext/grpc/rb_completion_queue.h +3 -7
  71. data/src/ruby/ext/grpc/rb_grpc.c +2 -4
  72. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +2 -0
  73. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +4 -1
  74. data/src/ruby/ext/grpc/rb_server.c +81 -133
  75. data/src/ruby/ext/grpc/rb_server_credentials.c +4 -33
  76. data/src/ruby/lib/grpc/generic/active_call.rb +40 -55
  77. data/src/ruby/lib/grpc/generic/bidi_call.rb +21 -23
  78. data/src/ruby/lib/grpc/generic/client_stub.rb +20 -15
  79. data/src/ruby/lib/grpc/generic/rpc_server.rb +15 -37
  80. data/src/ruby/lib/grpc/generic/service.rb +1 -1
  81. data/src/ruby/lib/grpc/version.rb +1 -1
  82. data/src/ruby/pb/test/client.rb +25 -7
  83. data/src/ruby/pb/test/server.rb +7 -5
  84. data/src/ruby/spec/call_spec.rb +1 -2
  85. data/src/ruby/spec/channel_spec.rb +2 -3
  86. data/src/ruby/spec/client_server_spec.rb +74 -59
  87. data/src/ruby/spec/generic/active_call_spec.rb +66 -86
  88. data/src/ruby/spec/generic/client_stub_spec.rb +27 -48
  89. data/src/ruby/spec/generic/rpc_server_spec.rb +4 -34
  90. data/src/ruby/spec/pb/health/checker_spec.rb +0 -2
  91. data/src/ruby/spec/server_spec.rb +20 -24
  92. metadata +9 -8
  93. data/src/ruby/spec/completion_queue_spec.rb +0 -42
@@ -42,7 +42,7 @@
42
42
  grpc_call* grpc_rb_get_wrapped_call(VALUE v);
43
43
 
44
44
  /* Gets the VALUE corresponding to given grpc_call. */
45
- VALUE grpc_rb_wrap_call(grpc_call* c);
45
+ VALUE grpc_rb_wrap_call(grpc_call *c, grpc_completion_queue *q);
46
46
 
47
47
  /* Provides the details of an call error */
48
48
  const char* grpc_call_error_detail_of(grpc_call_error err);
@@ -211,35 +211,6 @@ VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c, VALUE mark) {
211
211
  return rb_wrapper;
212
212
  }
213
213
 
214
- /* Clones CallCredentials instances.
215
- Gives CallCredentials a consistent implementation of Ruby's object copy/dup
216
- protocol. */
217
- static VALUE grpc_rb_call_credentials_init_copy(VALUE copy, VALUE orig) {
218
- grpc_rb_call_credentials *orig_cred = NULL;
219
- grpc_rb_call_credentials *copy_cred = NULL;
220
-
221
- if (copy == orig) {
222
- return copy;
223
- }
224
-
225
- /* Raise an error if orig is not a credentials object or a subclass. */
226
- if (TYPE(orig) != T_DATA ||
227
- RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_call_credentials_free) {
228
- rb_raise(rb_eTypeError, "not a %s",
229
- rb_obj_classname(grpc_rb_cCallCredentials));
230
- }
231
-
232
- TypedData_Get_Struct(orig, grpc_rb_call_credentials,
233
- &grpc_rb_call_credentials_data_type, orig_cred);
234
- TypedData_Get_Struct(copy, grpc_rb_call_credentials,
235
- &grpc_rb_call_credentials_data_type, copy_cred);
236
-
237
- /* use ruby's MEMCPY to make a byte-for-byte copy of the credentials
238
- * wrapper object. */
239
- MEMCPY(copy_cred, orig_cred, grpc_rb_call_credentials, 1);
240
- return copy;
241
- }
242
-
243
214
  /* The attribute used on the mark object to hold the callback */
244
215
  static ID id_callback;
245
216
 
@@ -308,7 +279,7 @@ void Init_grpc_call_credentials() {
308
279
  rb_define_method(grpc_rb_cCallCredentials, "initialize",
309
280
  grpc_rb_call_credentials_init, 1);
310
281
  rb_define_method(grpc_rb_cCallCredentials, "initialize_copy",
311
- grpc_rb_call_credentials_init_copy, 1);
282
+ grpc_rb_cannot_init_copy, 1);
312
283
  rb_define_method(grpc_rb_cCallCredentials, "compose",
313
284
  grpc_rb_call_credentials_compose, -1);
314
285
 
@@ -39,6 +39,8 @@
39
39
  #include <grpc/grpc.h>
40
40
  #include <grpc/grpc_security.h>
41
41
  #include <grpc/support/alloc.h>
42
+ #include <grpc/support/log.h>
43
+ #include <grpc/support/time.h>
42
44
  #include "rb_grpc.h"
43
45
  #include "rb_call.h"
44
46
  #include "rb_channel_args.h"
@@ -55,11 +57,6 @@ static ID id_channel;
55
57
  * GCed before the channel */
56
58
  static ID id_target;
57
59
 
58
- /* id_cqueue is the name of the hidden ivar that preserves a reference to the
59
- * completion queue used to create the call, preserved so that it does not get
60
- * GCed before the channel */
61
- static ID id_cqueue;
62
-
63
60
  /* id_insecure_channel is used to indicate that a channel is insecure */
64
61
  static VALUE id_insecure_channel;
65
62
 
@@ -75,6 +72,7 @@ typedef struct grpc_rb_channel {
75
72
 
76
73
  /* The actual channel */
77
74
  grpc_channel *wrapped;
75
+ grpc_completion_queue *queue;
78
76
  } grpc_rb_channel;
79
77
 
80
78
  /* Destroys Channel instances. */
@@ -87,6 +85,7 @@ static void grpc_rb_channel_free(void *p) {
87
85
 
88
86
  if (ch->wrapped != NULL) {
89
87
  grpc_channel_destroy(ch->wrapped);
88
+ grpc_rb_completion_queue_destroy(ch->queue);
90
89
  }
91
90
 
92
91
  xfree(p);
@@ -169,6 +168,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
169
168
  }
170
169
  rb_ivar_set(self, id_target, target);
171
170
  wrapper->wrapped = ch;
171
+ wrapper->queue = grpc_completion_queue_create(NULL);
172
172
  return self;
173
173
  }
174
174
 
@@ -207,16 +207,18 @@ static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv,
207
207
  the completion queue with success=0 */
208
208
  static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self,
209
209
  VALUE last_state,
210
- VALUE cqueue,
211
- VALUE deadline,
212
- VALUE tag) {
210
+ VALUE deadline) {
213
211
  grpc_rb_channel *wrapper = NULL;
214
212
  grpc_channel *ch = NULL;
215
213
  grpc_completion_queue *cq = NULL;
216
214
 
217
- cq = grpc_rb_get_wrapped_completion_queue(cqueue);
215
+ void *tag = wrapper;
216
+
217
+ grpc_event event;
218
+
218
219
  TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
219
220
  ch = wrapper->wrapped;
221
+ cq = wrapper->queue;
220
222
  if (ch == NULL) {
221
223
  rb_raise(rb_eRuntimeError, "closed!");
222
224
  return Qnil;
@@ -226,45 +228,23 @@ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self,
226
228
  (grpc_connectivity_state)NUM2LONG(last_state),
227
229
  grpc_rb_time_timeval(deadline, /* absolute time */ 0),
228
230
  cq,
229
- ROBJECT(tag));
230
-
231
- return Qnil;
232
- }
233
-
234
- /* Clones Channel instances.
231
+ tag);
235
232
 
236
- Gives Channel a consistent implementation of Ruby's object copy/dup
237
- protocol. */
238
- static VALUE grpc_rb_channel_init_copy(VALUE copy, VALUE orig) {
239
- grpc_rb_channel *orig_ch = NULL;
240
- grpc_rb_channel *copy_ch = NULL;
233
+ event = rb_completion_queue_pluck(cq, tag,
234
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
241
235
 
242
- if (copy == orig) {
243
- return copy;
244
- }
245
-
246
- /* Raise an error if orig is not a channel object or a subclass. */
247
- if (TYPE(orig) != T_DATA ||
248
- RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_channel_free) {
249
- rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cChannel));
250
- return Qnil;
236
+ if (event.success) {
237
+ return Qtrue;
238
+ } else {
239
+ return Qfalse;
251
240
  }
252
-
253
- TypedData_Get_Struct(orig, grpc_rb_channel, &grpc_channel_data_type, orig_ch);
254
- TypedData_Get_Struct(copy, grpc_rb_channel, &grpc_channel_data_type, copy_ch);
255
-
256
- /* use ruby's MEMCPY to make a byte-for-byte copy of the channel wrapper
257
- * object. */
258
- MEMCPY(copy_ch, orig_ch, grpc_rb_channel, 1);
259
- return copy;
260
241
  }
261
242
 
262
243
  /* Create a call given a grpc_channel, in order to call method. The request
263
244
  is not sent until grpc_call_invoke is called. */
264
- static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue,
265
- VALUE parent, VALUE mask,
266
- VALUE method, VALUE host,
267
- VALUE deadline) {
245
+ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent,
246
+ VALUE mask, VALUE method,
247
+ VALUE host, VALUE deadline) {
268
248
  VALUE res = Qnil;
269
249
  grpc_rb_channel *wrapper = NULL;
270
250
  grpc_call *call = NULL;
@@ -284,7 +264,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue,
284
264
  parent_call = grpc_rb_get_wrapped_call(parent);
285
265
  }
286
266
 
287
- cq = grpc_rb_get_wrapped_completion_queue(cqueue);
267
+ cq = grpc_completion_queue_create(NULL);
288
268
  TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
289
269
  ch = wrapper->wrapped;
290
270
  if (ch == NULL) {
@@ -301,15 +281,11 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue,
301
281
  method_chars);
302
282
  return Qnil;
303
283
  }
304
- res = grpc_rb_wrap_call(call);
284
+ res = grpc_rb_wrap_call(call, cq);
305
285
 
306
286
  /* Make this channel an instance attribute of the call so that it is not GCed
307
287
  * before the call. */
308
288
  rb_ivar_set(res, id_channel, self);
309
-
310
- /* Make the completion queue an instance attribute of the call so that it is
311
- * not GCed before the call. */
312
- rb_ivar_set(res, id_cqueue, cqueue);
313
289
  return res;
314
290
  }
315
291
 
@@ -387,7 +363,7 @@ void Init_grpc_channel() {
387
363
  /* Provides a ruby constructor and support for dup/clone. */
388
364
  rb_define_method(grpc_rb_cChannel, "initialize", grpc_rb_channel_init, -1);
389
365
  rb_define_method(grpc_rb_cChannel, "initialize_copy",
390
- grpc_rb_channel_init_copy, 1);
366
+ grpc_rb_cannot_init_copy, 1);
391
367
 
392
368
  /* Add ruby analogues of the Channel methods. */
393
369
  rb_define_method(grpc_rb_cChannel, "connectivity_state",
@@ -396,13 +372,12 @@ void Init_grpc_channel() {
396
372
  rb_define_method(grpc_rb_cChannel, "watch_connectivity_state",
397
373
  grpc_rb_channel_watch_connectivity_state, 4);
398
374
  rb_define_method(grpc_rb_cChannel, "create_call",
399
- grpc_rb_channel_create_call, 6);
375
+ grpc_rb_channel_create_call, 5);
400
376
  rb_define_method(grpc_rb_cChannel, "target", grpc_rb_channel_get_target, 0);
401
377
  rb_define_method(grpc_rb_cChannel, "destroy", grpc_rb_channel_destroy, 0);
402
378
  rb_define_alias(grpc_rb_cChannel, "close", "destroy");
403
379
 
404
380
  id_channel = rb_intern("__channel");
405
- id_cqueue = rb_intern("__cqueue");
406
381
  id_target = rb_intern("__target");
407
382
  rb_define_const(grpc_rb_cChannel, "SSL_TARGET",
408
383
  ID2SYM(rb_intern(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)));
@@ -126,36 +126,6 @@ VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c, VALUE mark)
126
126
  return rb_wrapper;
127
127
  }
128
128
 
129
- /* Clones ChannelCredentials instances.
130
- Gives ChannelCredentials a consistent implementation of Ruby's object copy/dup
131
- protocol. */
132
- static VALUE grpc_rb_channel_credentials_init_copy(VALUE copy, VALUE orig) {
133
- grpc_rb_channel_credentials *orig_cred = NULL;
134
- grpc_rb_channel_credentials *copy_cred = NULL;
135
-
136
- if (copy == orig) {
137
- return copy;
138
- }
139
-
140
- /* Raise an error if orig is not a credentials object or a subclass. */
141
- if (TYPE(orig) != T_DATA ||
142
- RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_channel_credentials_free) {
143
- rb_raise(rb_eTypeError, "not a %s",
144
- rb_obj_classname(grpc_rb_cChannelCredentials));
145
- }
146
-
147
- TypedData_Get_Struct(orig, grpc_rb_channel_credentials,
148
- &grpc_rb_channel_credentials_data_type, orig_cred);
149
- TypedData_Get_Struct(copy, grpc_rb_channel_credentials,
150
- &grpc_rb_channel_credentials_data_type, copy_cred);
151
-
152
- /* use ruby's MEMCPY to make a byte-for-byte copy of the credentials
153
- * wrapper object. */
154
- MEMCPY(copy_cred, orig_cred, grpc_rb_channel_credentials, 1);
155
- return copy;
156
- }
157
-
158
-
159
129
  /* The attribute used on the mark object to hold the pem_root_certs. */
160
130
  static ID id_pem_root_certs;
161
131
 
@@ -271,7 +241,7 @@ void Init_grpc_channel_credentials() {
271
241
  rb_define_method(grpc_rb_cChannelCredentials, "initialize",
272
242
  grpc_rb_channel_credentials_init, -1);
273
243
  rb_define_method(grpc_rb_cChannelCredentials, "initialize_copy",
274
- grpc_rb_channel_credentials_init_copy, 1);
244
+ grpc_rb_cannot_init_copy, 1);
275
245
  rb_define_method(grpc_rb_cChannelCredentials, "compose",
276
246
  grpc_rb_channel_credentials_compose, -1);
277
247
  rb_define_module_function(grpc_rb_cChannelCredentials,
@@ -40,12 +40,9 @@
40
40
 
41
41
  #include <grpc/grpc.h>
42
42
  #include <grpc/support/time.h>
43
+ #include <grpc/support/log.h>
43
44
  #include "rb_grpc.h"
44
45
 
45
- /* grpc_rb_cCompletionQueue is the ruby class that proxies
46
- * grpc_completion_queue. */
47
- static VALUE grpc_rb_cCompletionQueue = Qnil;
48
-
49
46
  /* Used to allow grpc_completion_queue_next call to release the GIL */
50
47
  typedef struct next_call_stack {
51
48
  grpc_completion_queue *cq;
@@ -55,23 +52,6 @@ typedef struct next_call_stack {
55
52
  volatile int interrupted;
56
53
  } next_call_stack;
57
54
 
58
- /* Calls grpc_completion_queue_next without holding the ruby GIL */
59
- static void *grpc_rb_completion_queue_next_no_gil(void *param) {
60
- next_call_stack *const next_call = (next_call_stack*)param;
61
- gpr_timespec increment = gpr_time_from_millis(20, GPR_TIMESPAN);
62
- gpr_timespec deadline;
63
- do {
64
- deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), increment);
65
- next_call->event = grpc_completion_queue_next(next_call->cq,
66
- deadline, NULL);
67
- if (next_call->event.type != GRPC_QUEUE_TIMEOUT ||
68
- gpr_time_cmp(deadline, next_call->timeout) > 0) {
69
- break;
70
- }
71
- } while (!next_call->interrupted);
72
- return NULL;
73
- }
74
-
75
55
  /* Calls grpc_completion_queue_pluck without holding the ruby GIL */
76
56
  static void *grpc_rb_completion_queue_pluck_no_gil(void *param) {
77
57
  next_call_stack *const next_call = (next_call_stack*)param;
@@ -90,107 +70,32 @@ static void *grpc_rb_completion_queue_pluck_no_gil(void *param) {
90
70
  return NULL;
91
71
  }
92
72
 
93
- /* Shuts down and drains the completion queue if necessary.
94
- *
95
- * This is done when the ruby completion queue object is about to be GCed.
96
- */
97
- static void grpc_rb_completion_queue_shutdown_drain(grpc_completion_queue *cq) {
98
- next_call_stack next_call;
99
- grpc_completion_type type;
100
- int drained = 0;
101
- MEMZERO(&next_call, next_call_stack, 1);
102
-
103
- grpc_completion_queue_shutdown(cq);
104
- next_call.cq = cq;
105
- next_call.event.type = GRPC_QUEUE_TIMEOUT;
106
- /* TODO: the timeout should be a module level constant that defaults
107
- * to gpr_inf_future(GPR_CLOCK_REALTIME).
108
- *
109
- * - at the moment this does not work, it stalls. Using a small timeout like
110
- * this one works, and leads to fast test run times; a longer timeout was
111
- * causing unnecessary delays in the test runs.
112
- *
113
- * - investigate further, this is probably another example of C-level cleanup
114
- * not working consistently in all cases.
115
- */
116
- next_call.timeout = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
117
- gpr_time_from_micros(5e3, GPR_TIMESPAN));
118
- do {
119
- rb_thread_call_without_gvl(grpc_rb_completion_queue_next_no_gil,
120
- (void *)&next_call, NULL, NULL);
121
- type = next_call.event.type;
122
- if (type == GRPC_QUEUE_TIMEOUT) break;
123
- if (type != GRPC_QUEUE_SHUTDOWN) {
124
- ++drained;
125
- rb_warning("completion queue shutdown: %d undrained events", drained);
126
- }
127
- } while (type != GRPC_QUEUE_SHUTDOWN);
128
- }
129
-
130
73
  /* Helper function to free a completion queue. */
131
- static void grpc_rb_completion_queue_destroy(void *p) {
132
- grpc_completion_queue *cq = NULL;
133
- if (p == NULL) {
134
- return;
135
- }
136
- cq = (grpc_completion_queue *)p;
137
- grpc_rb_completion_queue_shutdown_drain(cq);
74
+ void grpc_rb_completion_queue_destroy(grpc_completion_queue *cq) {
75
+ /* Every function that adds an event to a queue also synchronously plucks
76
+ that event from the queue, and holds a reference to the Ruby object that
77
+ holds the queue, so we only get to this point if all of those functions
78
+ have completed, and the queue is empty */
79
+ grpc_completion_queue_shutdown(cq);
138
80
  grpc_completion_queue_destroy(cq);
139
81
  }
140
82
 
141
- static rb_data_type_t grpc_rb_completion_queue_data_type = {
142
- "grpc_completion_queue",
143
- {GRPC_RB_GC_NOT_MARKED, grpc_rb_completion_queue_destroy,
144
- GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
145
- NULL, NULL,
146
- #ifdef RUBY_TYPED_FREE_IMMEDIATELY
147
- /* cannot immediately free because grpc_rb_completion_queue_shutdown_drain
148
- * calls rb_thread_call_without_gvl. */
149
- 0,
150
- #endif
151
- };
152
-
153
- /* Releases the c-level resources associated with a completion queue */
154
- static VALUE grpc_rb_completion_queue_close(VALUE self) {
155
- grpc_completion_queue* cq = grpc_rb_get_wrapped_completion_queue(self);
156
- grpc_rb_completion_queue_destroy(cq);
157
- RTYPEDDATA_DATA(self) = NULL;
158
- return Qnil;
159
- }
160
-
161
- /* Allocates a completion queue. */
162
- static VALUE grpc_rb_completion_queue_alloc(VALUE cls) {
163
- grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
164
- if (cq == NULL) {
165
- rb_raise(rb_eArgError, "could not create a completion queue: not sure why");
166
- }
167
- return TypedData_Wrap_Struct(cls, &grpc_rb_completion_queue_data_type, cq);
168
- }
169
-
170
83
  static void unblock_func(void *param) {
171
84
  next_call_stack *const next_call = (next_call_stack*)param;
172
85
  next_call->interrupted = 1;
173
86
  }
174
87
 
175
- /* Blocks until the next event for given tag is available, and returns the
176
- * event. */
177
- grpc_event grpc_rb_completion_queue_pluck_event(VALUE self, VALUE tag,
178
- VALUE timeout) {
88
+ /* Does the same thing as grpc_completion_queue_pluck, while properly releasing
89
+ the GVL and handling interrupts */
90
+ grpc_event rb_completion_queue_pluck(grpc_completion_queue *queue, void *tag,
91
+ gpr_timespec deadline, void *reserved) {
179
92
  next_call_stack next_call;
180
93
  MEMZERO(&next_call, next_call_stack, 1);
181
- TypedData_Get_Struct(self, grpc_completion_queue,
182
- &grpc_rb_completion_queue_data_type, next_call.cq);
183
- if (TYPE(timeout) == T_NIL) {
184
- next_call.timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
185
- } else {
186
- next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0);
187
- }
188
- if (TYPE(tag) == T_NIL) {
189
- next_call.tag = NULL;
190
- } else {
191
- next_call.tag = ROBJECT(tag);
192
- }
94
+ next_call.cq = queue;
95
+ next_call.timeout = deadline;
96
+ next_call.tag = tag;
193
97
  next_call.event.type = GRPC_QUEUE_TIMEOUT;
98
+ (void)reserved;
194
99
  /* Loop until we finish a pluck without an interruption. The internal
195
100
  pluck function runs either until it is interrupted or it gets an
196
101
  event, or time runs out.
@@ -210,27 +115,3 @@ grpc_event grpc_rb_completion_queue_pluck_event(VALUE self, VALUE tag,
210
115
  next_call.event.type == GRPC_QUEUE_TIMEOUT);
211
116
  return next_call.event;
212
117
  }
213
-
214
- void Init_grpc_completion_queue() {
215
- grpc_rb_cCompletionQueue =
216
- rb_define_class_under(grpc_rb_mGrpcCore, "CompletionQueue", rb_cObject);
217
-
218
- /* constructor: uses an alloc func without an initializer. Using a simple
219
- alloc func works here as the grpc header does not specify any args for
220
- this func, so no separate initialization step is necessary. */
221
- rb_define_alloc_func(grpc_rb_cCompletionQueue,
222
- grpc_rb_completion_queue_alloc);
223
-
224
- /* close: Provides a way to close the underlying file descriptor without
225
- waiting for ruby garbage collection. */
226
- rb_define_method(grpc_rb_cCompletionQueue, "close",
227
- grpc_rb_completion_queue_close, 0);
228
- }
229
-
230
- /* Gets the wrapped completion queue from the ruby wrapper */
231
- grpc_completion_queue *grpc_rb_get_wrapped_completion_queue(VALUE v) {
232
- grpc_completion_queue *cq = NULL;
233
- TypedData_Get_Struct(v, grpc_completion_queue,
234
- &grpc_rb_completion_queue_data_type, cq);
235
- return cq;
236
- }