rb_grpc.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <ruby/ruby.h>
20 
21 #include "rb_grpc.h"
22 
23 #include <math.h>
24 #include <ruby/vm.h>
25 #include <stdbool.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 
30 #include "rb_call.h"
31 #include "rb_call_credentials.h"
32 #include "rb_channel.h"
33 #include "rb_channel_credentials.h"
34 #include "rb_compression_options.h"
35 #include "rb_event_thread.h"
37 #include "rb_loader.h"
38 #include "rb_server.h"
39 #include "rb_server_credentials.h"
42 
43 #include <grpc/grpc.h>
44 #include <grpc/support/log.h>
45 #include <grpc/support/time.h>
46 
47 static VALUE grpc_rb_cTimeVal = Qnil;
48 
49 static rb_data_type_t grpc_rb_timespec_data_type = {
50  "gpr_timespec",
54  {NULL, NULL}},
55  NULL,
56  NULL,
57 #ifdef RUBY_TYPED_FREE_IMMEDIATELY
58  RUBY_TYPED_FREE_IMMEDIATELY
59 #endif
60 };
61 
62 /* Alloc func that blocks allocation of a given object by raising an
63  * exception. */
64 VALUE grpc_rb_cannot_alloc(VALUE cls) {
65  rb_raise(rb_eTypeError,
66  "allocation of %s only allowed from the gRPC native layer",
67  rb_class2name(cls));
68  return Qnil;
69 }
70 
71 /* Init func that fails by raising an exception. */
72 VALUE grpc_rb_cannot_init(VALUE self) {
73  rb_raise(rb_eTypeError,
74  "initialization of %s only allowed from the gRPC native layer",
75  rb_obj_classname(self));
76  return Qnil;
77 }
78 
79 /* Init/Clone func that fails by raising an exception. */
80 VALUE grpc_rb_cannot_init_copy(VALUE copy, VALUE self) {
81  (void)self;
82  rb_raise(rb_eTypeError, "Copy initialization of %s is not supported",
83  rb_obj_classname(copy));
84  return Qnil;
85 }
86 
87 /* id_tv_{,u}sec are accessor methods on Ruby Time instances. */
88 static ID id_tv_sec;
89 static ID id_tv_nsec;
90 
98 gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
99  gpr_timespec t;
100  gpr_timespec* time_const;
101  const char* tstr = interval ? "time interval" : "time";
102  const char* want = " want <secs from epoch>|<Time>|<GRPC::TimeConst.*>";
103 
104  t.clock_type = GPR_CLOCK_REALTIME;
105  switch (TYPE(time)) {
106  case T_DATA:
107  if (CLASS_OF(time) == grpc_rb_cTimeVal) {
108  TypedData_Get_Struct(time, gpr_timespec, &grpc_rb_timespec_data_type,
109  time_const);
110  t = *time_const;
111  } else if (CLASS_OF(time) == rb_cTime) {
112  t.tv_sec = NUM2INT(rb_funcall(time, id_tv_sec, 0));
113  t.tv_nsec = NUM2INT(rb_funcall(time, id_tv_nsec, 0));
114  } else {
115  rb_raise(rb_eTypeError, "bad input: (%s)->c_timeval, got <%s>,%s", tstr,
116  rb_obj_classname(time), want);
117  }
118  break;
119 
120  case T_FIXNUM:
121  t.tv_sec = FIX2LONG(time);
122  if (interval && t.tv_sec < 0)
123  rb_raise(rb_eArgError, "%s must be positive", tstr);
124  t.tv_nsec = 0;
125  break;
126 
127  case T_FLOAT:
128  if (interval && RFLOAT_VALUE(time) < 0.0)
129  rb_raise(rb_eArgError, "%s must be positive", tstr);
130  else {
131  double f, d;
132 
133  d = modf(RFLOAT_VALUE(time), &f);
134  if (d < 0) {
135  d += 1;
136  f -= 1;
137  }
138  t.tv_sec = (int64_t)f;
139  if (f != t.tv_sec) {
140  rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT_VALUE(time));
141  }
142  t.tv_nsec = (int)(d * 1e9 + 0.5);
143  }
144  break;
145 
146  case T_BIGNUM:
147  t.tv_sec = NUM2LONG(time);
148  if (interval && t.tv_sec < 0)
149  rb_raise(rb_eArgError, "%s must be positive", tstr);
150  t.tv_nsec = 0;
151  break;
152 
153  default:
154  rb_raise(rb_eTypeError, "bad input: (%s)->c_timeval, got <%s>,%s", tstr,
155  rb_obj_classname(time), want);
156  break;
157  }
158  return t;
159 }
160 
161 /* id_at is the constructor method of the ruby standard Time class. */
162 static ID id_at;
163 
164 /* id_inspect is the inspect method found on various ruby objects. */
165 static ID id_inspect;
166 
167 /* id_to_s is the to_s method found on various ruby objects. */
168 static ID id_to_s;
169 
170 /* Converts a wrapped time constant to a standard time. */
171 static VALUE grpc_rb_time_val_to_time(VALUE self) {
172  gpr_timespec* time_const = NULL;
173  gpr_timespec real_time;
174  TypedData_Get_Struct(self, gpr_timespec, &grpc_rb_timespec_data_type,
175  time_const);
176  real_time = gpr_convert_clock_type(*time_const, GPR_CLOCK_REALTIME);
177  return rb_funcall(rb_cTime, id_at, 2, INT2NUM(real_time.tv_sec),
178  INT2NUM(real_time.tv_nsec / 1000));
179 }
180 
181 /* Invokes inspect on the ctime version of the time val. */
182 static VALUE grpc_rb_time_val_inspect(VALUE self) {
183  return rb_funcall(grpc_rb_time_val_to_time(self), id_inspect, 0);
184 }
185 
186 /* Invokes to_s on the ctime version of the time val. */
187 static VALUE grpc_rb_time_val_to_s(VALUE self) {
188  return rb_funcall(grpc_rb_time_val_to_time(self), id_to_s, 0);
189 }
190 
194 
195 /* Adds a module with constants that map to gpr's static timeval structs. */
196 static void Init_grpc_time_consts() {
197  VALUE grpc_rb_mTimeConsts =
198  rb_define_module_under(grpc_rb_mGrpcCore, "TimeConsts");
200  rb_define_class_under(grpc_rb_mGrpcCore, "TimeSpec", rb_cObject);
204  rb_define_const(
205  grpc_rb_mTimeConsts, "ZERO",
206  TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
207  (void*)&zero_realtime));
208  rb_define_const(
209  grpc_rb_mTimeConsts, "INFINITE_FUTURE",
210  TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
211  (void*)&inf_future_realtime));
212  rb_define_const(
213  grpc_rb_mTimeConsts, "INFINITE_PAST",
214  TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
215  (void*)&inf_past_realtime));
216  rb_define_method(grpc_rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0);
217  rb_define_method(grpc_rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0);
218  rb_define_method(grpc_rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0);
219  id_at = rb_intern("at");
220  id_inspect = rb_intern("inspect");
221  id_to_s = rb_intern("to_s");
222  id_tv_sec = rb_intern("tv_sec");
223  id_tv_nsec = rb_intern("tv_nsec");
224 }
225 
226 #if GPR_WINDOWS
227 static void grpc_ruby_set_init_pid(void) {}
228 static bool grpc_ruby_forked_after_init(void) { return false; }
229 #else
230 static pid_t grpc_init_pid;
231 
232 static void grpc_ruby_set_init_pid(void) {
234  grpc_init_pid = getpid();
235 }
236 
237 static bool grpc_ruby_forked_after_init(void) {
239  return grpc_init_pid != getpid();
240 }
241 #endif
242 
243 /* Initialize the GRPC module structs */
244 
245 /* grpc_rb_sNewServerRpc is the struct that holds new server rpc details. */
247 /* grpc_rb_sStatus is the struct that holds status details. */
248 VALUE grpc_rb_sStatus = Qnil;
249 
250 /* Initialize the GRPC module. */
251 VALUE grpc_rb_mGRPC = Qnil;
252 VALUE grpc_rb_mGrpcCore = Qnil;
253 
254 /* cached Symbols for members in Status struct */
255 VALUE sym_code = Qundef;
256 VALUE sym_details = Qundef;
257 VALUE sym_metadata = Qundef;
258 
260 
263  rb_raise(rb_eRuntimeError, "grpc cannot be used before and after forking");
264  }
265 }
266 
267 static VALUE bg_thread_init_rb_mu = Qundef;
268 static int bg_thread_init_done = 0;
269 
270 static void grpc_ruby_init_threads() {
271  // Avoid calling into ruby library (when creating threads here)
272  // in gpr_once_init. In general, it appears to be unsafe to call
273  // into the ruby library while holding a non-ruby mutex, because a gil yield
274  // could end up trying to lock onto that same mutex and deadlocking.
275  rb_mutex_lock(bg_thread_init_rb_mu);
276  if (!bg_thread_init_done) {
280  }
281  rb_mutex_unlock(bg_thread_init_rb_mu);
282 }
283 
285 
288  grpc_init();
290  // (only gpr_log after logging has been initialized)
292  "GRPC_RUBY: grpc_ruby_init - prev g_grpc_ruby_init_count:%" PRId64,
294 }
295 
299  gpr_log(
300  GPR_DEBUG,
301  "GRPC_RUBY: grpc_ruby_shutdown - prev g_grpc_ruby_init_count:%" PRId64,
303 }
304 
305 void Init_grpc_c() {
306  if (!grpc_rb_load_core()) {
307  rb_raise(rb_eLoadError, "Couldn't find or load gRPC's dynamic C core");
308  return;
309  }
310 
311  rb_global_variable(&bg_thread_init_rb_mu);
312  bg_thread_init_rb_mu = rb_mutex_new();
313 
314  grpc_rb_mGRPC = rb_define_module("GRPC");
315  grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core");
316  grpc_rb_sNewServerRpc = rb_struct_define(
317  "NewServerRpc", "method", "host", "deadline", "metadata", "call", NULL);
318  grpc_rb_sStatus = rb_const_get(rb_cStruct, rb_intern("Status"));
319  sym_code = ID2SYM(rb_intern("code"));
320  sym_details = ID2SYM(rb_intern("details"));
321  sym_metadata = ID2SYM(rb_intern("metadata"));
322 
324  Init_grpc_call();
333 }
gpr_timespec::tv_nsec
int32_t tv_nsec
Definition: gpr_types.h:52
gpr_timespec::tv_sec
int64_t tv_sec
Definition: gpr_types.h:51
rb_xds_server_credentials.h
grpc_rb_sStatus
VALUE grpc_rb_sStatus
Definition: rb_grpc.c:248
log.h
rb_grpc_imports.generated.h
grpc_rb_cannot_alloc
VALUE grpc_rb_cannot_alloc(VALUE cls)
Definition: rb_grpc.c:64
grpc_rb_mGRPC
VALUE grpc_rb_mGRPC
Definition: rb_grpc.c:251
GRPC_RB_MEMSIZE_UNAVAILABLE
#define GRPC_RB_MEMSIZE_UNAVAILABLE
Definition: rb_grpc.h:57
grpc_init_pid
static pid_t grpc_init_pid
Definition: rb_grpc.c:230
gpr_once
pthread_once_t gpr_once
Definition: impl/codegen/sync_posix.h:50
grpc_ruby_shutdown
void grpc_ruby_shutdown()
Definition: rb_grpc.c:296
GRPC_RB_GC_NOT_MARKED
#define GRPC_RB_GC_NOT_MARKED
Definition: rb_grpc.h:48
gpr_time_0
GPRAPI gpr_timespec gpr_time_0(gpr_clock_type type)
Definition: src/core/lib/gpr/time.cc:47
bg_thread_init_done
static int bg_thread_init_done
Definition: rb_grpc.c:268
grpc_rb_timespec_data_type
static rb_data_type_t grpc_rb_timespec_data_type
Definition: rb_grpc.c:49
copy
static int copy(grpc_slice_buffer *input, grpc_slice_buffer *output)
Definition: message_compress.cc:145
gpr_inf_future
GPRAPI gpr_timespec gpr_inf_future(gpr_clock_type type)
Definition: src/core/lib/gpr/time.cc:55
GPR_ONCE_INIT
#define GPR_ONCE_INIT
Definition: impl/codegen/sync_posix.h:52
time.h
grpc_rb_cTimeVal
static VALUE grpc_rb_cTimeVal
Definition: rb_grpc.c:47
sym_metadata
VALUE sym_metadata
Definition: rb_grpc.c:257
gpr_once_init
GPRAPI void gpr_once_init(gpr_once *once, void(*init_function)(void))
grpc_rb_event_queue_thread_start
void grpc_rb_event_queue_thread_start()
Definition: rb_event_thread.c:138
grpc_rb_time_val_to_time
static VALUE grpc_rb_time_val_to_time(VALUE self)
Definition: rb_grpc.c:171
g_grpc_ruby_init_count
static int64_t g_grpc_ruby_init_count
Definition: rb_grpc.c:284
grpc_rb_channel_polling_thread_start
void grpc_rb_channel_polling_thread_start()
Definition: rb_channel.c:753
autogen_x86imm.f
f
Definition: autogen_x86imm.py:9
xds_interop_client.int
int
Definition: xds_interop_client.py:113
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
inf_past_realtime
static gpr_timespec inf_past_realtime
Definition: rb_grpc.c:193
grpc_ruby_set_init_pid
static void grpc_ruby_set_init_pid(void)
Definition: rb_grpc.c:232
inf_future_realtime
static gpr_timespec inf_future_realtime
Definition: rb_grpc.c:192
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
grpc_rb_sNewServerRpc
VALUE grpc_rb_sNewServerRpc
Definition: rb_grpc.c:246
grpc.h
Init_grpc_channel
void Init_grpc_channel()
Definition: rb_channel.c:805
id_inspect
static ID id_inspect
Definition: rb_grpc.c:165
rb_loader.h
Init_grpc_channel_credentials
void Init_grpc_channel_credentials()
Definition: rb_channel_credentials.c:248
GRPC_RB_GC_DONT_FREE
#define GRPC_RB_GC_DONT_FREE
Definition: rb_grpc.h:53
d
static const fe d
Definition: curve25519_tables.h:19
rb_server_credentials.h
Init_grpc_c
void Init_grpc_c()
Definition: rb_grpc.c:305
rb_call_credentials.h
bg_thread_init_rb_mu
static VALUE bg_thread_init_rb_mu
Definition: rb_grpc.c:267
rb_xds_channel_credentials.h
gpr_inf_past
GPRAPI gpr_timespec gpr_inf_past(gpr_clock_type type)
Definition: src/core/lib/gpr/time.cc:63
rb_grpc.h
grpc_ruby_forked_after_init
static bool grpc_ruby_forked_after_init(void)
Definition: rb_grpc.c:237
grpc_rb_mGrpcCore
VALUE grpc_rb_mGrpcCore
Definition: rb_grpc.c:252
rb_compression_options.h
grpc_rb_time_timeval
gpr_timespec grpc_rb_time_timeval(VALUE time, int interval)
Definition: rb_grpc.c:98
gpr_convert_clock_type
GPRAPI gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type)
Definition: src/core/lib/gpr/time.cc:241
grpc_rb_cannot_init_copy
VALUE grpc_rb_cannot_init_copy(VALUE copy, VALUE self)
Definition: rb_grpc.c:80
Init_grpc_call
void Init_grpc_call()
Definition: rb_call.c:967
id_tv_sec
static ID id_tv_sec
Definition: rb_grpc.c:88
Init_grpc_xds_server_credentials
void Init_grpc_xds_server_credentials()
Definition: rb_xds_server_credentials.c:141
grpc_rb_time_val_to_s
static VALUE grpc_rb_time_val_to_s(VALUE self)
Definition: rb_grpc.c:187
Init_grpc_call_credentials
void Init_grpc_call_credentials()
Definition: rb_call_credentials.c:316
rb_call.h
grpc_rb_cannot_init
VALUE grpc_rb_cannot_init(VALUE self)
Definition: rb_grpc.c:72
grpc_ruby_fork_guard
void grpc_ruby_fork_guard()
Definition: rb_grpc.c:261
sym_code
VALUE sym_code
Definition: rb_grpc.c:255
Init_grpc_server
void Init_grpc_server()
Definition: rb_server.c:357
rb_channel_credentials.h
rb_channel.h
TYPE
#define TYPE(u, l)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:8202
grpc_ruby_init_threads
static void grpc_ruby_init_threads()
Definition: rb_grpc.c:270
grpc_rb_load_core
int grpc_rb_load_core()
Definition: rb_loader.c:55
Init_grpc_xds_channel_credentials
void Init_grpc_xds_channel_credentials()
Definition: rb_xds_channel_credentials.c:188
Init_grpc_time_consts
static void Init_grpc_time_consts()
Definition: rb_grpc.c:196
GPR_DEBUG
#define GPR_DEBUG
Definition: include/grpc/impl/codegen/log.h:55
Init_grpc_server_credentials
void Init_grpc_server_credentials()
Definition: rb_server_credentials.c:227
g_once_init
static gpr_once g_once_init
Definition: rb_grpc.c:259
id_to_s
static ID id_to_s
Definition: rb_grpc.c:168
gpr_timespec
Definition: gpr_types.h:50
sym_details
VALUE sym_details
Definition: rb_grpc.c:256
grpc_rb_time_val_inspect
static VALUE grpc_rb_time_val_inspect(VALUE self)
Definition: rb_grpc.c:182
grpc_init
GRPCAPI void grpc_init(void)
Definition: init.cc:146
rb_event_thread.h
Init_grpc_compression_options
void Init_grpc_compression_options()
Definition: rb_compression_options.c:432
GPR_CLOCK_REALTIME
@ GPR_CLOCK_REALTIME
Definition: gpr_types.h:39
id_tv_nsec
static ID id_tv_nsec
Definition: rb_grpc.c:89
rb_server.h
grpc_shutdown
GRPCAPI void grpc_shutdown(void)
Definition: init.cc:209
grpc_ruby_init
void grpc_ruby_init()
Definition: rb_grpc.c:286
zero_realtime
static gpr_timespec zero_realtime
Definition: rb_grpc.c:191
id_at
static ID id_at
Definition: rb_grpc.c:162


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:59