grpc 1.56.0-x86_64-linux → 1.57.0.pre1-x86_64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/src/ruby/bin/math_pb.rb +24 -18
  3. data/src/ruby/ext/grpc/extconf.rb +19 -18
  4. data/src/ruby/ext/grpc/rb_call.c +62 -39
  5. data/src/ruby/ext/grpc/rb_call_credentials.c +0 -1
  6. data/src/ruby/ext/grpc/rb_channel.c +126 -49
  7. data/src/ruby/ext/grpc/rb_channel.h +1 -0
  8. data/src/ruby/ext/grpc/rb_channel_args.c +16 -2
  9. data/src/ruby/ext/grpc/rb_channel_args.h +4 -0
  10. data/src/ruby/ext/grpc/rb_channel_credentials.c +0 -1
  11. data/src/ruby/ext/grpc/rb_compression_options.c +0 -1
  12. data/src/ruby/ext/grpc/rb_event_thread.c +22 -6
  13. data/src/ruby/ext/grpc/rb_event_thread.h +1 -0
  14. data/src/ruby/ext/grpc/rb_grpc.c +192 -30
  15. data/src/ruby/ext/grpc/rb_grpc.h +8 -2
  16. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +2 -0
  17. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +3 -0
  18. data/src/ruby/ext/grpc/rb_server.c +62 -45
  19. data/src/ruby/ext/grpc/rb_server_credentials.c +0 -1
  20. data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +0 -1
  21. data/src/ruby/ext/grpc/rb_xds_server_credentials.c +0 -1
  22. data/src/ruby/lib/grpc/2.6/grpc_c.so +0 -0
  23. data/src/ruby/lib/grpc/2.7/grpc_c.so +0 -0
  24. data/src/ruby/lib/grpc/3.0/grpc_c.so +0 -0
  25. data/src/ruby/lib/grpc/3.1/grpc_c.so +0 -0
  26. data/src/ruby/lib/grpc/3.2/grpc_c.so +0 -0
  27. data/src/ruby/lib/grpc/generic/bidi_call.rb +2 -0
  28. data/src/ruby/lib/grpc/version.rb +1 -1
  29. data/src/ruby/pb/grpc/health/v1/health_pb.rb +24 -13
  30. data/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb +24 -3
  31. data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +25 -111
  32. data/src/ruby/pb/src/proto/grpc/testing/test_pb.rb +25 -2
  33. metadata +5 -5
@@ -24,6 +24,7 @@
24
24
  #include "rb_grpc_imports.generated.h"
25
25
 
26
26
  #include <grpc/grpc.h>
27
+ #include <grpc/support/log.h>
27
28
 
28
29
  static rb_data_type_t grpc_rb_channel_args_data_type = {
29
30
  "grpc_channel_args",
@@ -73,13 +74,14 @@ static int grpc_rb_channel_create_in_process_add_args_hash_cb(VALUE key,
73
74
  case T_SYMBOL:
74
75
  args->args[args->num_args - 1].type = GRPC_ARG_STRING;
75
76
  args->args[args->num_args - 1].value.string =
76
- (char*)rb_id2name(SYM2ID(val));
77
+ strdup(rb_id2name(SYM2ID(val)));
77
78
  --args->num_args;
78
79
  return ST_CONTINUE;
79
80
 
80
81
  case T_STRING:
81
82
  args->args[args->num_args - 1].type = GRPC_ARG_STRING;
82
- args->args[args->num_args - 1].value.string = StringValueCStr(val);
83
+ args->args[args->num_args - 1].value.string =
84
+ strdup(StringValueCStr(val));
83
85
  --args->num_args;
84
86
  return ST_CONTINUE;
85
87
 
@@ -154,3 +156,15 @@ void grpc_rb_hash_convert_to_channel_args(VALUE src_hash,
154
156
  rb_jump_tag(status);
155
157
  }
156
158
  }
159
+
160
+ void grpc_rb_channel_args_destroy(grpc_channel_args* args) {
161
+ GPR_ASSERT(args != NULL);
162
+ if (args->args == NULL) return;
163
+ for (int i = 0; i < args->num_args; i++) {
164
+ if (args->args[i].type == GRPC_ARG_STRING) {
165
+ // we own string pointers, which were created with strdup
166
+ free(args->args[i].value.string);
167
+ }
168
+ }
169
+ xfree(args->args);
170
+ }
@@ -35,4 +35,8 @@
35
35
  void grpc_rb_hash_convert_to_channel_args(VALUE src_hash,
36
36
  grpc_channel_args* dst);
37
37
 
38
+ /* Destroys inner fields of args (does not deallocate the args pointer itself)
39
+ */
40
+ void grpc_rb_channel_args_destroy(grpc_channel_args* args);
41
+
38
42
  #endif /* GRPC_RB_CHANNEL_ARGS_H_ */
@@ -63,7 +63,6 @@ static void grpc_rb_channel_credentials_free_internal(void* p) {
63
63
  /* Destroys the credentials instances. */
64
64
  static void grpc_rb_channel_credentials_free(void* p) {
65
65
  grpc_rb_channel_credentials_free_internal(p);
66
- grpc_ruby_shutdown();
67
66
  }
68
67
 
69
68
  /* Protects the mark object from GC */
@@ -70,7 +70,6 @@ static void grpc_rb_compression_options_free_internal(void* p) {
70
70
  * wrapped grpc compression options. */
71
71
  static void grpc_rb_compression_options_free(void* p) {
72
72
  grpc_rb_compression_options_free_internal(p);
73
- grpc_ruby_shutdown();
74
73
  }
75
74
 
76
75
  /* Ruby recognized data type for the CompressionOptions class. */
@@ -51,6 +51,8 @@ typedef struct grpc_rb_event_queue {
51
51
  } grpc_rb_event_queue;
52
52
 
53
53
  static grpc_rb_event_queue event_queue;
54
+ static VALUE g_event_thread = Qnil;
55
+ static bool g_one_time_init_done = false;
54
56
 
55
57
  void grpc_rb_event_queue_enqueue(void (*callback)(void*), void* argument) {
56
58
  grpc_rb_event* event = gpr_malloc(sizeof(grpc_rb_event));
@@ -117,7 +119,6 @@ static void grpc_rb_event_unblocking_func(void* arg) {
117
119
  static VALUE grpc_rb_event_thread(VALUE arg) {
118
120
  grpc_rb_event* event;
119
121
  (void)arg;
120
- grpc_ruby_init();
121
122
  while (true) {
122
123
  event = (grpc_rb_event*)rb_thread_call_without_gvl(
123
124
  grpc_rb_wait_for_event_no_gil, NULL, grpc_rb_event_unblocking_func,
@@ -131,15 +132,30 @@ static VALUE grpc_rb_event_thread(VALUE arg) {
131
132
  }
132
133
  }
133
134
  grpc_rb_event_queue_destroy();
134
- grpc_ruby_shutdown();
135
135
  return Qnil;
136
136
  }
137
137
 
138
138
  void grpc_rb_event_queue_thread_start() {
139
- event_queue.head = event_queue.tail = NULL;
139
+ if (!g_one_time_init_done) {
140
+ g_one_time_init_done = true;
141
+ gpr_mu_init(&event_queue.mu);
142
+ gpr_cv_init(&event_queue.cv);
143
+ rb_global_variable(&g_event_thread);
144
+ event_queue.head = event_queue.tail = NULL;
145
+ }
140
146
  event_queue.abort = false;
141
- gpr_mu_init(&event_queue.mu);
142
- gpr_cv_init(&event_queue.cv);
147
+ GPR_ASSERT(!RTEST(g_event_thread));
148
+ g_event_thread = rb_thread_create(grpc_rb_event_thread, NULL);
149
+ }
143
150
 
144
- rb_thread_create(grpc_rb_event_thread, NULL);
151
+ void grpc_rb_event_queue_thread_stop() {
152
+ GPR_ASSERT(g_one_time_init_done);
153
+ if (!RTEST(g_event_thread)) {
154
+ gpr_log(GPR_ERROR,
155
+ "GRPC_RUBY: call credentials thread stop: thread not running");
156
+ return;
157
+ }
158
+ rb_thread_call_without_gvl(grpc_rb_event_unblocking_func, NULL, NULL, NULL);
159
+ rb_funcall(g_event_thread, rb_intern("join"), 0);
160
+ g_event_thread = Qnil;
145
161
  }
@@ -17,5 +17,6 @@
17
17
  */
18
18
 
19
19
  void grpc_rb_event_queue_thread_start();
20
+ void grpc_rb_event_queue_thread_stop();
20
21
 
21
22
  void grpc_rb_event_queue_enqueue(void (*callback)(void*), void* argument);
@@ -44,6 +44,11 @@
44
44
  #include <grpc/support/log.h>
45
45
  #include <grpc/support/time.h>
46
46
 
47
+ #ifdef GPR_LINUX
48
+ #include <sys/syscall.h>
49
+ #include <unistd.h>
50
+ #endif
51
+
47
52
  static VALUE grpc_rb_cTimeVal = Qnil;
48
53
 
49
54
  static rb_data_type_t grpc_rb_timespec_data_type = {
@@ -224,20 +229,51 @@ static void Init_grpc_time_consts() {
224
229
  id_tv_nsec = rb_intern("tv_nsec");
225
230
  }
226
231
 
232
+ static bool g_enable_fork_support;
233
+
234
+ #ifdef GPR_LINUX
235
+ static long sys_gettid() { return syscall(__NR_gettid); }
236
+ static bool can_enable_fork_support() { return true; }
237
+ #else
238
+ static long sys_gettid() { return 0; }
239
+ static bool can_enable_fork_support() { return false; }
240
+ #endif
241
+
227
242
  #if GPR_WINDOWS
228
- static void grpc_ruby_set_init_pid(void) {}
229
- static bool grpc_ruby_forked_after_init(void) { return false; }
243
+ static void grpc_ruby_basic_init(void) {}
244
+ static bool grpc_ruby_initial_pid(void) { return true; }
245
+ static bool grpc_ruby_initial_thread(void) { return true; }
246
+ static void grpc_ruby_reset_init_state(void) {}
230
247
  #else
231
- static pid_t grpc_init_pid;
248
+ static pid_t g_init_pid;
249
+ static long g_init_tid;
232
250
 
233
- static void grpc_ruby_set_init_pid(void) {
234
- GPR_ASSERT(grpc_init_pid == 0);
235
- grpc_init_pid = getpid();
251
+ static bool grpc_ruby_initial_pid(void) {
252
+ GPR_ASSERT(g_init_pid != 0);
253
+ return g_init_pid == getpid();
236
254
  }
237
255
 
238
- static bool grpc_ruby_forked_after_init(void) {
239
- GPR_ASSERT(grpc_init_pid != 0);
240
- return grpc_init_pid != getpid();
256
+ static bool grpc_ruby_initial_thread(void) {
257
+ GPR_ASSERT(g_init_tid != 0);
258
+ return sys_gettid() == g_init_tid;
259
+ }
260
+
261
+ static void grpc_ruby_reset_init_state(void) {
262
+ g_init_pid = getpid();
263
+ g_init_tid = sys_gettid();
264
+ }
265
+
266
+ static void grpc_ruby_basic_init(void) {
267
+ GPR_ASSERT(g_init_pid == 0);
268
+ GPR_ASSERT(g_init_tid == 0);
269
+ grpc_ruby_reset_init_state();
270
+ // TODO(apolcyn): ideally, we should share logic with C-core
271
+ // for determining whether or not fork support is enabled, rather
272
+ // than parsing the environment variable ourselves.
273
+ const char* res = getenv("GRPC_ENABLE_FORK_SUPPORT");
274
+ if (res != NULL && strcmp(res, "1") == 0) {
275
+ g_enable_fork_support = can_enable_fork_support();
276
+ }
241
277
  }
242
278
  #endif
243
279
 
@@ -258,59 +294,175 @@ VALUE sym_details = Qundef;
258
294
  VALUE sym_metadata = Qundef;
259
295
 
260
296
  static gpr_once g_once_init = GPR_ONCE_INIT;
297
+ static int64_t g_grpc_rb_prefork_pending; // synchronized by the GIL
298
+ static int64_t g_grpc_rb_num_fork_unsafe_threads; // synchronized by the GIL
261
299
 
262
300
  void grpc_ruby_fork_guard() {
263
- if (grpc_ruby_forked_after_init()) {
264
- rb_raise(rb_eRuntimeError, "grpc cannot be used before and after forking");
301
+ // Check if we're using gRPC between prefork and postfork
302
+ gpr_once_init(&g_once_init, grpc_ruby_basic_init);
303
+ if (g_grpc_rb_prefork_pending) {
304
+ rb_raise(rb_eRuntimeError,
305
+ "grpc cannot be used between calls to GRPC.prefork and "
306
+ "GRPC.postfork_child or GRPC.postfork_parent");
307
+ }
308
+ if (!grpc_ruby_initial_pid()) {
309
+ if (g_enable_fork_support) {
310
+ // Only way we can get here is by enabling for support and forking but not
311
+ // calling prefork
312
+ rb_raise(rb_eRuntimeError,
313
+ "grpc is in a broken state: GRPC.prefork must be called before "
314
+ "calling fork from a process using grpc");
315
+ } else {
316
+ rb_raise(rb_eRuntimeError,
317
+ "grpc cannot be used before and after forking unless the "
318
+ "GRPC_ENABLE_FORK_SUPPORT env var is set to \"1\" and the "
319
+ "platform supports it (linux only)");
320
+ }
265
321
  }
266
322
  }
267
323
 
268
- static VALUE bg_thread_init_rb_mu = Qundef;
269
- static int bg_thread_init_done = 0;
324
+ static VALUE g_bg_thread_init_rb_mu = Qundef;
325
+ static bool g_bg_thread_init_done;
270
326
 
271
327
  static void grpc_ruby_init_threads() {
272
328
  // Avoid calling into ruby library (when creating threads here)
273
329
  // in gpr_once_init. In general, it appears to be unsafe to call
274
330
  // into the ruby library while holding a non-ruby mutex, because a gil yield
275
331
  // could end up trying to lock onto that same mutex and deadlocking.
276
- rb_mutex_lock(bg_thread_init_rb_mu);
277
- if (!bg_thread_init_done) {
332
+ gpr_log(GPR_INFO,
333
+ "GRPC_RUBY: grpc_ruby_init_threads g_bg_thread_init_done=%d",
334
+ g_bg_thread_init_done);
335
+ rb_mutex_lock(g_bg_thread_init_rb_mu);
336
+ if (!g_bg_thread_init_done) {
278
337
  grpc_rb_event_queue_thread_start();
279
338
  grpc_rb_channel_polling_thread_start();
280
- bg_thread_init_done = 1;
339
+ g_bg_thread_init_done = true;
281
340
  }
282
- rb_mutex_unlock(bg_thread_init_rb_mu);
341
+ rb_mutex_unlock(g_bg_thread_init_rb_mu);
283
342
  }
284
343
 
285
344
  static int64_t g_grpc_ruby_init_count;
286
345
 
287
346
  void grpc_ruby_init() {
288
- gpr_once_init(&g_once_init, grpc_ruby_set_init_pid);
347
+ gpr_once_init(&g_once_init, grpc_ruby_basic_init);
348
+ grpc_ruby_fork_guard();
289
349
  grpc_init();
290
350
  grpc_ruby_init_threads();
291
351
  // (only gpr_log after logging has been initialized)
292
352
  gpr_log(GPR_DEBUG,
293
- "GRPC_RUBY: grpc_ruby_init - prev g_grpc_ruby_init_count:%" PRId64,
294
- g_grpc_ruby_init_count++);
353
+ "GRPC_RUBY: grpc_ruby_init - g_enable_fork_support=%d prev "
354
+ "g_grpc_ruby_init_count:%" PRId64,
355
+ g_enable_fork_support, g_grpc_ruby_init_count++);
356
+ }
357
+
358
+ // fork APIs, useable on linux with env var: GRPC_ENABLE_FORK_SUPPORT=1
359
+ //
360
+ // Must be called once and only once before forking. Must be called on the
361
+ // same threads that gRPC was (lazy-)initialized on. One must not call
362
+ // into the gRPC library during or after prefork has been called, until
363
+ // the corresponding postfork_{parent,child} APIs have been called.
364
+ static VALUE grpc_rb_prefork(VALUE self) {
365
+ // This might be the first time we've called into the grpc library, so make
366
+ // sure basic one-time initialization is taken care of. Note that if this is
367
+ // the case, then grpc_init() will start up c-core threads; that's OK since
368
+ // they will be shut down in C-core's pthread_atfork handler.
369
+ gpr_once_init(&g_once_init, grpc_ruby_basic_init);
370
+ grpc_init();
371
+ if (!g_enable_fork_support) {
372
+ rb_raise(rb_eRuntimeError,
373
+ "forking with gRPC/Ruby is only supported on linux with env var: "
374
+ "GRPC_ENABLE_FORK_SUPPORT=1");
375
+ }
376
+ if (g_grpc_rb_prefork_pending) {
377
+ rb_raise(rb_eRuntimeError,
378
+ "GRPC.prefork already called without a matching "
379
+ "GRPC.postfork_{parent,child}");
380
+ }
381
+ if (!grpc_ruby_initial_thread()) {
382
+ rb_raise(rb_eRuntimeError,
383
+ "GRPC.prefork and fork need to be called from the same thread "
384
+ "that GRPC was initialized on (GRPC lazy-initializes when when "
385
+ "the first GRPC object is created");
386
+ }
387
+ if (g_grpc_rb_num_fork_unsafe_threads > 0) {
388
+ rb_raise(
389
+ rb_eRuntimeError,
390
+ "Detected at least %ld threads actively using grpc, so it is not safe "
391
+ "call GRPC.prefork or fork. Note that grpc-ruby servers and "
392
+ "bidirectional "
393
+ "streams manage background threads and are not fork safe.",
394
+ g_grpc_rb_num_fork_unsafe_threads);
395
+ }
396
+ g_grpc_rb_prefork_pending = true;
397
+ rb_mutex_lock(g_bg_thread_init_rb_mu);
398
+ if (g_bg_thread_init_done) {
399
+ grpc_rb_channel_polling_thread_stop();
400
+ grpc_rb_event_queue_thread_stop();
401
+ // all ruby-level background threads joined at this point
402
+ g_bg_thread_init_done = false;
403
+ }
404
+ rb_mutex_unlock(g_bg_thread_init_rb_mu);
405
+ return Qnil;
295
406
  }
296
407
 
297
- void grpc_ruby_shutdown() {
298
- GPR_ASSERT(g_grpc_ruby_init_count > 0);
299
- if (!grpc_ruby_forked_after_init()) grpc_shutdown();
300
- gpr_log(
301
- GPR_DEBUG,
302
- "GRPC_RUBY: grpc_ruby_shutdown - prev g_grpc_ruby_init_count:%" PRId64,
303
- g_grpc_ruby_init_count--);
408
+ static VALUE grpc_rb_postfork_child(VALUE self) {
409
+ if (!g_grpc_rb_prefork_pending) {
410
+ rb_raise(rb_eRuntimeError,
411
+ "GRPC::postfork_child can only be called once following a "
412
+ "GRPC::prefork");
413
+ }
414
+ if (grpc_ruby_initial_pid()) {
415
+ rb_raise(rb_eRuntimeError,
416
+ "GRPC.postfork_child must be called only from the child process "
417
+ "after a fork");
418
+ }
419
+ grpc_ruby_reset_init_state();
420
+ grpc_ruby_init_threads();
421
+ g_grpc_rb_prefork_pending = false;
422
+ return Qnil;
304
423
  }
305
424
 
425
+ static VALUE grpc_rb_postfork_parent(VALUE self) {
426
+ // TODO(apolcyn): check calling thread vs. thread that gRPC was initialized on
427
+ if (!g_grpc_rb_prefork_pending) {
428
+ rb_raise(rb_eRuntimeError,
429
+ "GRPC::postfork_parent can only be called once following a "
430
+ "GRPC::prefork");
431
+ }
432
+ if (!grpc_ruby_initial_pid()) {
433
+ rb_raise(rb_eRuntimeError,
434
+ "GRPC.postfork_parent must be called only from the parent process "
435
+ "after a fork");
436
+ }
437
+ if (!grpc_ruby_initial_thread()) {
438
+ rb_raise(rb_eRuntimeError,
439
+ "GRPC.postfork_parent needs to be called from the same thread "
440
+ "that GRPC.prefork (and fork) was called from");
441
+ }
442
+ grpc_ruby_init_threads();
443
+ g_grpc_rb_prefork_pending = false;
444
+ return Qnil;
445
+ }
446
+
447
+ // APIs to mark fork-unsafe sections from C-extension code
448
+ void grpc_rb_fork_unsafe_begin() { g_grpc_rb_num_fork_unsafe_threads++; }
449
+
450
+ void grpc_rb_fork_unsafe_end() { g_grpc_rb_num_fork_unsafe_threads--; }
451
+
452
+ // APIs to mark fork-unsafe sections from ruby code
453
+ static VALUE grpc_rb_fork_unsafe_begin_api() { grpc_rb_fork_unsafe_begin(); }
454
+
455
+ static VALUE grpc_rb_fork_unsafe_end_api() { grpc_rb_fork_unsafe_end(); }
456
+
457
+ // One-time initialization
306
458
  void Init_grpc_c() {
307
459
  if (!grpc_rb_load_core()) {
308
460
  rb_raise(rb_eLoadError, "Couldn't find or load gRPC's dynamic C core");
309
461
  return;
310
462
  }
311
463
 
312
- rb_global_variable(&bg_thread_init_rb_mu);
313
- bg_thread_init_rb_mu = rb_mutex_new();
464
+ rb_global_variable(&g_bg_thread_init_rb_mu);
465
+ g_bg_thread_init_rb_mu = rb_mutex_new();
314
466
 
315
467
  grpc_rb_mGRPC = rb_define_module("GRPC");
316
468
  grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core");
@@ -320,7 +472,7 @@ void Init_grpc_c() {
320
472
  sym_code = ID2SYM(rb_intern("code"));
321
473
  sym_details = ID2SYM(rb_intern("details"));
322
474
  sym_metadata = ID2SYM(rb_intern("metadata"));
323
-
475
+ // init C-defined classes
324
476
  Init_grpc_channel();
325
477
  Init_grpc_call();
326
478
  Init_grpc_call_credentials();
@@ -331,4 +483,14 @@ void Init_grpc_c() {
331
483
  Init_grpc_xds_server_credentials();
332
484
  Init_grpc_time_consts();
333
485
  Init_grpc_compression_options();
486
+ // define fork APIs
487
+ rb_define_module_function(grpc_rb_mGRPC, "prefork", grpc_rb_prefork, 0);
488
+ rb_define_module_function(grpc_rb_mGRPC, "postfork_child",
489
+ grpc_rb_postfork_child, 0);
490
+ rb_define_module_function(grpc_rb_mGRPC, "postfork_parent",
491
+ grpc_rb_postfork_parent, 0);
492
+ rb_define_module_function(grpc_rb_mGrpcCore, "fork_unsafe_begin",
493
+ grpc_rb_fork_unsafe_begin_api, 0);
494
+ rb_define_module_function(grpc_rb_mGrpcCore, "fork_unsafe_end",
495
+ grpc_rb_fork_unsafe_end_api, 0);
334
496
  }
@@ -70,8 +70,14 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval);
70
70
 
71
71
  void grpc_ruby_fork_guard();
72
72
 
73
- void grpc_ruby_init();
73
+ /* To be called once and only once before entering code section that is
74
+ * definitely not fork-safe. Used in conjunction with GRPC.prefork
75
+ * to catch for-unsafe processes and raise errors. */
76
+ void grpc_rb_fork_unsafe_begin();
77
+
78
+ /* To be called once and only once after each grpc_rb_fork_unsafe_begin*/
79
+ void grpc_rb_fork_unsafe_end();
74
80
 
75
- void grpc_ruby_shutdown();
81
+ void grpc_ruby_init();
76
82
 
77
83
  #endif /* GRPC_RB_H_ */
@@ -188,6 +188,7 @@ grpc_tls_credentials_options_set_identity_cert_name_type grpc_tls_credentials_op
188
188
  grpc_tls_credentials_options_set_cert_request_type_type grpc_tls_credentials_options_set_cert_request_type_import;
189
189
  grpc_tls_credentials_options_set_crl_directory_type grpc_tls_credentials_options_set_crl_directory_import;
190
190
  grpc_tls_credentials_options_set_verify_server_cert_type grpc_tls_credentials_options_set_verify_server_cert_import;
191
+ grpc_tls_credentials_options_set_send_client_ca_list_type grpc_tls_credentials_options_set_send_client_ca_list_import;
191
192
  grpc_tls_credentials_options_set_check_call_host_type grpc_tls_credentials_options_set_check_call_host_import;
192
193
  grpc_insecure_credentials_create_type grpc_insecure_credentials_create_import;
193
194
  grpc_insecure_server_credentials_create_type grpc_insecure_server_credentials_create_import;
@@ -474,6 +475,7 @@ void grpc_rb_load_imports(HMODULE library) {
474
475
  grpc_tls_credentials_options_set_cert_request_type_import = (grpc_tls_credentials_options_set_cert_request_type_type) GetProcAddress(library, "grpc_tls_credentials_options_set_cert_request_type");
475
476
  grpc_tls_credentials_options_set_crl_directory_import = (grpc_tls_credentials_options_set_crl_directory_type) GetProcAddress(library, "grpc_tls_credentials_options_set_crl_directory");
476
477
  grpc_tls_credentials_options_set_verify_server_cert_import = (grpc_tls_credentials_options_set_verify_server_cert_type) GetProcAddress(library, "grpc_tls_credentials_options_set_verify_server_cert");
478
+ grpc_tls_credentials_options_set_send_client_ca_list_import = (grpc_tls_credentials_options_set_send_client_ca_list_type) GetProcAddress(library, "grpc_tls_credentials_options_set_send_client_ca_list");
477
479
  grpc_tls_credentials_options_set_check_call_host_import = (grpc_tls_credentials_options_set_check_call_host_type) GetProcAddress(library, "grpc_tls_credentials_options_set_check_call_host");
478
480
  grpc_insecure_credentials_create_import = (grpc_insecure_credentials_create_type) GetProcAddress(library, "grpc_insecure_credentials_create");
479
481
  grpc_insecure_server_credentials_create_import = (grpc_insecure_server_credentials_create_type) GetProcAddress(library, "grpc_insecure_server_credentials_create");
@@ -539,6 +539,9 @@ extern grpc_tls_credentials_options_set_crl_directory_type grpc_tls_credentials_
539
539
  typedef void(*grpc_tls_credentials_options_set_verify_server_cert_type)(grpc_tls_credentials_options* options, int verify_server_cert);
540
540
  extern grpc_tls_credentials_options_set_verify_server_cert_type grpc_tls_credentials_options_set_verify_server_cert_import;
541
541
  #define grpc_tls_credentials_options_set_verify_server_cert grpc_tls_credentials_options_set_verify_server_cert_import
542
+ typedef void(*grpc_tls_credentials_options_set_send_client_ca_list_type)(grpc_tls_credentials_options* options, bool send_client_ca_list);
543
+ extern grpc_tls_credentials_options_set_send_client_ca_list_type grpc_tls_credentials_options_set_send_client_ca_list_import;
544
+ #define grpc_tls_credentials_options_set_send_client_ca_list grpc_tls_credentials_options_set_send_client_ca_list_import
542
545
  typedef void(*grpc_tls_credentials_options_set_check_call_host_type)(grpc_tls_credentials_options* options, int check_call_host);
543
546
  extern grpc_tls_credentials_options_set_check_call_host_type grpc_tls_credentials_options_set_check_call_host_import;
544
547
  #define grpc_tls_credentials_options_set_check_call_host grpc_tls_credentials_options_set_check_call_host_import
@@ -106,10 +106,7 @@ static void grpc_rb_server_free_internal(void* p) {
106
106
  }
107
107
 
108
108
  /* Destroys server instances. */
109
- static void grpc_rb_server_free(void* p) {
110
- grpc_rb_server_free_internal(p);
111
- grpc_ruby_shutdown();
112
- }
109
+ static void grpc_rb_server_free(void* p) { grpc_rb_server_free_internal(p); }
113
110
 
114
111
  static const rb_data_type_t grpc_rb_server_data_type = {
115
112
  "grpc_server",
@@ -155,10 +152,7 @@ static VALUE grpc_rb_server_init(VALUE self, VALUE channel_args) {
155
152
  wrapper);
156
153
  grpc_rb_hash_convert_to_channel_args(channel_args, &args);
157
154
  srv = grpc_server_create(&args, NULL);
158
-
159
- if (args.args != NULL) {
160
- xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
161
- }
155
+ grpc_rb_channel_args_destroy(&args);
162
156
  if (srv == NULL) {
163
157
  rb_raise(rb_eRuntimeError, "could not create a gRPC server, not sure why");
164
158
  }
@@ -191,65 +185,88 @@ static void grpc_request_call_stack_cleanup(request_call_stack* st) {
191
185
  grpc_call_details_destroy(&st->details);
192
186
  }
193
187
 
194
- /* call-seq:
195
- server.request_call
188
+ struct server_request_call_args {
189
+ grpc_rb_server* server;
190
+ grpc_completion_queue* call_queue;
191
+ request_call_stack st;
192
+ };
193
+
194
+ static VALUE grpc_rb_server_request_call_try(VALUE value_args) {
195
+ grpc_rb_fork_unsafe_begin();
196
+ struct server_request_call_args* args =
197
+ (struct server_request_call_args*)value_args;
196
198
 
197
- Requests notification of a new call on a server. */
198
- static VALUE grpc_rb_server_request_call(VALUE self) {
199
- grpc_rb_server* s = NULL;
200
199
  grpc_call* call = NULL;
201
- grpc_event ev;
202
- grpc_call_error err;
203
- request_call_stack st;
204
- VALUE result;
205
- void* tag = (void*)&st;
206
- grpc_completion_queue* call_queue =
207
- grpc_completion_queue_create_for_pluck(NULL);
208
- gpr_timespec deadline;
200
+ void* tag = (void*)&args->st;
201
+
202
+ args->call_queue = grpc_completion_queue_create_for_pluck(NULL);
203
+ grpc_request_call_stack_init(&args->st);
209
204
 
210
- TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
211
- if (s->wrapped == NULL) {
212
- rb_raise(rb_eRuntimeError, "destroyed!");
213
- return Qnil;
214
- }
215
- grpc_request_call_stack_init(&st);
216
205
  /* call grpc_server_request_call, then wait for it to complete using
217
206
  * pluck_event */
218
- err = grpc_server_request_call(s->wrapped, &call, &st.details, &st.md_ary,
219
- call_queue, s->queue, tag);
207
+ grpc_call_error err = grpc_server_request_call(
208
+ args->server->wrapped, &call, &args->st.details, &args->st.md_ary,
209
+ args->call_queue, args->server->queue, tag);
220
210
  if (err != GRPC_CALL_OK) {
221
- grpc_request_call_stack_cleanup(&st);
222
211
  rb_raise(grpc_rb_eCallError,
223
212
  "grpc_server_request_call failed: %s (code=%d)",
224
213
  grpc_call_error_detail_of(err), err);
225
- return Qnil;
226
214
  }
227
215
 
228
- ev = rb_completion_queue_pluck(s->queue, tag,
229
- gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
216
+ grpc_event ev = rb_completion_queue_pluck(
217
+ args->server->queue, tag, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
230
218
  if (!ev.success) {
231
- grpc_request_call_stack_cleanup(&st);
232
219
  rb_raise(grpc_rb_eCallError, "request_call completion failed");
233
- return Qnil;
234
220
  }
235
221
 
236
222
  /* build the NewServerRpc struct result */
237
- deadline = gpr_convert_clock_type(st.details.deadline, GPR_CLOCK_REALTIME);
238
- result = rb_struct_new(
239
- grpc_rb_sNewServerRpc, grpc_rb_slice_to_ruby_string(st.details.method),
240
- grpc_rb_slice_to_ruby_string(st.details.host),
241
- rb_funcall(rb_cTime, id_at, 2, INT2NUM(deadline.tv_sec),
242
- INT2NUM(deadline.tv_nsec / 1000)),
243
- grpc_rb_md_ary_to_h(&st.md_ary), grpc_rb_wrap_call(call, call_queue),
244
- NULL);
245
- grpc_request_call_stack_cleanup(&st);
223
+ gpr_timespec deadline =
224
+ gpr_convert_clock_type(args->st.details.deadline, GPR_CLOCK_REALTIME);
225
+ VALUE result =
226
+ rb_struct_new(grpc_rb_sNewServerRpc,
227
+ grpc_rb_slice_to_ruby_string(args->st.details.method),
228
+ grpc_rb_slice_to_ruby_string(args->st.details.host),
229
+ rb_funcall(rb_cTime, id_at, 2, INT2NUM(deadline.tv_sec),
230
+ INT2NUM(deadline.tv_nsec / 1000)),
231
+ grpc_rb_md_ary_to_h(&args->st.md_ary),
232
+ grpc_rb_wrap_call(call, args->call_queue), NULL);
233
+ args->call_queue = NULL;
246
234
  return result;
247
235
  }
248
236
 
237
+ static VALUE grpc_rb_server_request_call_ensure(VALUE value_args) {
238
+ grpc_rb_fork_unsafe_end();
239
+ struct server_request_call_args* args =
240
+ (struct server_request_call_args*)value_args;
241
+
242
+ if (args->call_queue) {
243
+ grpc_rb_completion_queue_destroy(args->call_queue);
244
+ }
245
+
246
+ grpc_request_call_stack_cleanup(&args->st);
247
+
248
+ return Qnil;
249
+ }
250
+
251
+ /* call-seq:
252
+ server.request_call
253
+
254
+ Requests notification of a new call on a server. */
255
+ static VALUE grpc_rb_server_request_call(VALUE self) {
256
+ grpc_rb_server* s;
257
+ TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
258
+ grpc_ruby_fork_guard();
259
+ if (s->wrapped == NULL) {
260
+ rb_raise(rb_eRuntimeError, "destroyed!");
261
+ }
262
+ struct server_request_call_args args = {.server = s, .call_queue = NULL};
263
+ return rb_ensure(grpc_rb_server_request_call_try, (VALUE)&args,
264
+ grpc_rb_server_request_call_ensure, (VALUE)&args);
265
+ }
266
+
249
267
  static VALUE grpc_rb_server_start(VALUE self) {
250
268
  grpc_rb_server* s = NULL;
251
269
  TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
252
-
253
270
  grpc_ruby_fork_guard();
254
271
  if (s->wrapped == NULL) {
255
272
  rb_raise(rb_eRuntimeError, "destroyed!");
@@ -62,7 +62,6 @@ static void grpc_rb_server_credentials_free_internal(void* p) {
62
62
  /* Destroys the server credentials instances. */
63
63
  static void grpc_rb_server_credentials_free(void* p) {
64
64
  grpc_rb_server_credentials_free_internal(p);
65
- grpc_ruby_shutdown();
66
65
  }
67
66
 
68
67
  /* Protects the mark object from GC */
@@ -62,7 +62,6 @@ static void grpc_rb_xds_channel_credentials_free_internal(void* p) {
62
62
  /* Destroys the credentials instances. */
63
63
  static void grpc_rb_xds_channel_credentials_free(void* p) {
64
64
  grpc_rb_xds_channel_credentials_free_internal(p);
65
- grpc_ruby_shutdown();
66
65
  }
67
66
 
68
67
  /* Protects the mark object from GC */
@@ -63,7 +63,6 @@ static void grpc_rb_xds_server_credentials_free_internal(void* p) {
63
63
  /* Destroys the server credentials instances. */
64
64
  static void grpc_rb_xds_server_credentials_free(void* p) {
65
65
  grpc_rb_xds_server_credentials_free_internal(p);
66
- grpc_ruby_shutdown();
67
66
  }
68
67
 
69
68
  /* Protects the mark object from GC */
Binary file
Binary file
Binary file
Binary file
Binary file