grpc 1.56.2-x86_64-linux → 1.57.0-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
@@ -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_ */
@@ -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
@@ -141,6 +141,7 @@ module GRPC
141
141
  # set_output_stream_done is relevant on client-side
142
142
  # rubocop:disable Metrics/PerceivedComplexity
143
143
  def write_loop(requests, is_client: true, set_output_stream_done: nil)
144
+ GRPC::Core.fork_unsafe_begin
144
145
  GRPC.logger.debug('bidi-write-loop: starting')
145
146
  count = 0
146
147
  requests.each do |req|
@@ -181,6 +182,7 @@ module GRPC
181
182
  raise e
182
183
  end
183
184
  ensure
185
+ GRPC::Core.fork_unsafe_end
184
186
  set_output_stream_done.call if is_client
185
187
  end
186
188
  # rubocop:enable Metrics/PerceivedComplexity
@@ -14,5 +14,5 @@
14
14
 
15
15
  # GRPC contains the General RPC module.
16
16
  module GRPC
17
- VERSION = '1.56.2'
17
+ VERSION = '1.57.0'
18
18
  end
@@ -1,23 +1,34 @@
1
+ # frozen_string_literal: true
1
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
2
3
  # source: grpc/health/v1/health.proto
3
4
 
4
5
  require 'google/protobuf'
5
6
 
6
- Google::Protobuf::DescriptorPool.generated_pool.build do
7
- add_file("grpc/health/v1/health.proto", :syntax => :proto3) do
8
- add_message "grpc.health.v1.HealthCheckRequest" do
9
- optional :service, :string, 1
10
- end
11
- add_message "grpc.health.v1.HealthCheckResponse" do
12
- optional :status, :enum, 1, "grpc.health.v1.HealthCheckResponse.ServingStatus"
13
- end
14
- add_enum "grpc.health.v1.HealthCheckResponse.ServingStatus" do
15
- value :UNKNOWN, 0
16
- value :SERVING, 1
17
- value :NOT_SERVING, 2
18
- value :SERVICE_UNKNOWN, 3
7
+
8
+ descriptor_data = "\n\x1bgrpc/health/v1/health.proto\x12\x0egrpc.health.v1\"%\n\x12HealthCheckRequest\x12\x0f\n\x07service\x18\x01 \x01(\t\"\xa9\x01\n\x13HealthCheckResponse\x12\x41\n\x06status\x18\x01 \x01(\x0e\x32\x31.grpc.health.v1.HealthCheckResponse.ServingStatus\"O\n\rServingStatus\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0b\n\x07SERVING\x10\x01\x12\x0f\n\x0bNOT_SERVING\x10\x02\x12\x13\n\x0fSERVICE_UNKNOWN\x10\x03\x32\xae\x01\n\x06Health\x12P\n\x05\x43heck\x12\".grpc.health.v1.HealthCheckRequest\x1a#.grpc.health.v1.HealthCheckResponse\x12R\n\x05Watch\x12\".grpc.health.v1.HealthCheckRequest\x1a#.grpc.health.v1.HealthCheckResponse0\x01\x42\x61\n\x11io.grpc.health.v1B\x0bHealthProtoP\x01Z,google.golang.org/grpc/health/grpc_health_v1\xaa\x02\x0eGrpc.Health.V1b\x06proto3"
9
+
10
+ pool = Google::Protobuf::DescriptorPool.generated_pool
11
+
12
+ begin
13
+ pool.add_serialized_file(descriptor_data)
14
+ rescue TypeError => e
15
+ # Compatibility code: will be removed in the next major version.
16
+ require 'google/protobuf/descriptor_pb'
17
+ parsed = Google::Protobuf::FileDescriptorProto.decode(descriptor_data)
18
+ parsed.clear_dependency
19
+ serialized = parsed.class.encode(parsed)
20
+ file = pool.add_serialized_file(serialized)
21
+ warn "Warning: Protobuf detected an import path issue while loading generated file #{__FILE__}"
22
+ imports = [
23
+ ]
24
+ imports.each do |type_name, expected_filename|
25
+ import_file = pool.lookup(type_name).file_descriptor
26
+ if import_file.name != expected_filename
27
+ warn "- #{file.name} imports #{expected_filename}, but that import was loaded as #{import_file.name}"
19
28
  end
20
29
  end
30
+ warn "Each proto file must use a consistent fully-qualified name."
31
+ warn "This will become an error in the next major version."
21
32
  end
22
33
 
23
34
  module Grpc
@@ -1,13 +1,34 @@
1
+ # frozen_string_literal: true
1
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
2
3
  # source: src/proto/grpc/testing/empty.proto
3
4
 
4
5
  require 'google/protobuf'
5
6
 
6
- Google::Protobuf::DescriptorPool.generated_pool.build do
7
- add_file("src/proto/grpc/testing/empty.proto", :syntax => :proto3) do
8
- add_message "grpc.testing.Empty" do
7
+
8
+ descriptor_data = "\n\"src/proto/grpc/testing/empty.proto\x12\x0cgrpc.testing\"\x07\n\x05\x45mptyb\x06proto3"
9
+
10
+ pool = Google::Protobuf::DescriptorPool.generated_pool
11
+
12
+ begin
13
+ pool.add_serialized_file(descriptor_data)
14
+ rescue TypeError => e
15
+ # Compatibility code: will be removed in the next major version.
16
+ require 'google/protobuf/descriptor_pb'
17
+ parsed = Google::Protobuf::FileDescriptorProto.decode(descriptor_data)
18
+ parsed.clear_dependency
19
+ serialized = parsed.class.encode(parsed)
20
+ file = pool.add_serialized_file(serialized)
21
+ warn "Warning: Protobuf detected an import path issue while loading generated file #{__FILE__}"
22
+ imports = [
23
+ ]
24
+ imports.each do |type_name, expected_filename|
25
+ import_file = pool.lookup(type_name).file_descriptor
26
+ if import_file.name != expected_filename
27
+ warn "- #{file.name} imports #{expected_filename}, but that import was loaded as #{import_file.name}"
9
28
  end
10
29
  end
30
+ warn "Each proto file must use a consistent fully-qualified name."
31
+ warn "This will become an error in the next major version."
11
32
  end
12
33
 
13
34
  module Grpc