grpc 1.74.0.pre2-x86-linux-musl
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.
- checksums.yaml +7 -0
- data/etc/roots.pem +4337 -0
- data/grpc_c.32-msvcrt.ruby +0 -0
- data/grpc_c.64-ucrt.ruby +0 -0
- data/src/ruby/bin/math_client.rb +140 -0
- data/src/ruby/bin/math_pb.rb +19 -0
- data/src/ruby/bin/math_server.rb +191 -0
- data/src/ruby/bin/math_services_pb.rb +51 -0
- data/src/ruby/bin/noproto_client.rb +93 -0
- data/src/ruby/bin/noproto_server.rb +97 -0
- data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.clang +2 -0
- data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.gcc +7 -0
- data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.clang +2 -0
- data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.gcc +7 -0
- data/src/ruby/ext/grpc/ext-export.clang +1 -0
- data/src/ruby/ext/grpc/ext-export.gcc +6 -0
- data/src/ruby/ext/grpc/extconf.rb +269 -0
- data/src/ruby/ext/grpc/rb_byte_buffer.c +65 -0
- data/src/ruby/ext/grpc/rb_byte_buffer.h +35 -0
- data/src/ruby/ext/grpc/rb_call.c +1075 -0
- data/src/ruby/ext/grpc/rb_call.h +57 -0
- data/src/ruby/ext/grpc/rb_call_credentials.c +347 -0
- data/src/ruby/ext/grpc/rb_call_credentials.h +32 -0
- data/src/ruby/ext/grpc/rb_channel.c +391 -0
- data/src/ruby/ext/grpc/rb_channel.h +32 -0
- data/src/ruby/ext/grpc/rb_channel_args.c +174 -0
- data/src/ruby/ext/grpc/rb_channel_args.h +42 -0
- data/src/ruby/ext/grpc/rb_channel_credentials.c +285 -0
- data/src/ruby/ext/grpc/rb_channel_credentials.h +36 -0
- data/src/ruby/ext/grpc/rb_completion_queue.c +95 -0
- data/src/ruby/ext/grpc/rb_completion_queue.h +36 -0
- data/src/ruby/ext/grpc/rb_compression_options.c +469 -0
- data/src/ruby/ext/grpc/rb_compression_options.h +29 -0
- data/src/ruby/ext/grpc/rb_enable_cpp.cc +22 -0
- data/src/ruby/ext/grpc/rb_event_thread.c +167 -0
- data/src/ruby/ext/grpc/rb_event_thread.h +22 -0
- data/src/ruby/ext/grpc/rb_grpc.c +500 -0
- data/src/ruby/ext/grpc/rb_grpc.h +88 -0
- data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +597 -0
- data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +902 -0
- data/src/ruby/ext/grpc/rb_loader.c +57 -0
- data/src/ruby/ext/grpc/rb_loader.h +25 -0
- data/src/ruby/ext/grpc/rb_server.c +406 -0
- data/src/ruby/ext/grpc/rb_server.h +32 -0
- data/src/ruby/ext/grpc/rb_server_credentials.c +259 -0
- data/src/ruby/ext/grpc/rb_server_credentials.h +37 -0
- data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +217 -0
- data/src/ruby/ext/grpc/rb_xds_channel_credentials.h +36 -0
- data/src/ruby/ext/grpc/rb_xds_server_credentials.c +170 -0
- data/src/ruby/ext/grpc/rb_xds_server_credentials.h +37 -0
- data/src/ruby/lib/grpc/3.1/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/3.2/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/3.3/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/3.4/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/core/status_codes.rb +135 -0
- data/src/ruby/lib/grpc/core/time_consts.rb +56 -0
- data/src/ruby/lib/grpc/errors.rb +277 -0
- data/src/ruby/lib/grpc/generic/active_call.rb +679 -0
- data/src/ruby/lib/grpc/generic/bidi_call.rb +237 -0
- data/src/ruby/lib/grpc/generic/client_stub.rb +503 -0
- data/src/ruby/lib/grpc/generic/interceptor_registry.rb +53 -0
- data/src/ruby/lib/grpc/generic/interceptors.rb +186 -0
- data/src/ruby/lib/grpc/generic/rpc_desc.rb +204 -0
- data/src/ruby/lib/grpc/generic/rpc_server.rb +551 -0
- data/src/ruby/lib/grpc/generic/service.rb +211 -0
- data/src/ruby/lib/grpc/google_rpc_status_utils.rb +40 -0
- data/src/ruby/lib/grpc/grpc.rb +24 -0
- data/src/ruby/lib/grpc/logconfig.rb +57 -0
- data/src/ruby/lib/grpc/notifier.rb +45 -0
- data/src/ruby/lib/grpc/structs.rb +15 -0
- data/src/ruby/lib/grpc/version.rb +18 -0
- data/src/ruby/lib/grpc.rb +37 -0
- data/src/ruby/pb/README.md +42 -0
- data/src/ruby/pb/generate_proto_ruby.sh +46 -0
- data/src/ruby/pb/grpc/health/checker.rb +75 -0
- data/src/ruby/pb/grpc/health/v1/health_pb.rb +21 -0
- data/src/ruby/pb/grpc/health/v1/health_services_pb.rb +62 -0
- data/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb +44 -0
- data/src/ruby/pb/grpc/testing/metrics_pb.rb +19 -0
- data/src/ruby/pb/grpc/testing/metrics_services_pb.rb +49 -0
- data/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb +17 -0
- data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +50 -0
- data/src/ruby/pb/src/proto/grpc/testing/test_pb.rb +19 -0
- data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +174 -0
- data/src/ruby/pb/test/client.rb +785 -0
- data/src/ruby/pb/test/server.rb +252 -0
- data/src/ruby/pb/test/xds_client.rb +415 -0
- data/src/ruby/spec/call_credentials_spec.rb +42 -0
- data/src/ruby/spec/call_spec.rb +193 -0
- data/src/ruby/spec/channel_connection_spec.rb +126 -0
- data/src/ruby/spec/channel_credentials_spec.rb +124 -0
- data/src/ruby/spec/channel_spec.rb +209 -0
- data/src/ruby/spec/client_auth_spec.rb +152 -0
- data/src/ruby/spec/client_server_spec.rb +317 -0
- data/src/ruby/spec/compression_options_spec.rb +149 -0
- data/src/ruby/spec/core_spec.rb +22 -0
- data/src/ruby/spec/debug_message_spec.rb +134 -0
- data/src/ruby/spec/error_sanity_spec.rb +49 -0
- data/src/ruby/spec/errors_spec.rb +142 -0
- data/src/ruby/spec/generic/active_call_spec.rb +670 -0
- data/src/ruby/spec/generic/client_interceptors_spec.rb +153 -0
- data/src/ruby/spec/generic/client_stub_spec.rb +1079 -0
- data/src/ruby/spec/generic/interceptor_registry_spec.rb +65 -0
- data/src/ruby/spec/generic/rpc_desc_spec.rb +374 -0
- data/src/ruby/spec/generic/rpc_server_pool_spec.rb +127 -0
- data/src/ruby/spec/generic/rpc_server_spec.rb +773 -0
- data/src/ruby/spec/generic/server_interceptors_spec.rb +218 -0
- data/src/ruby/spec/generic/service_spec.rb +263 -0
- data/src/ruby/spec/google_rpc_status_utils_spec.rb +282 -0
- data/src/ruby/spec/logconfig_spec.rb +30 -0
- data/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto +28 -0
- data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import.proto +22 -0
- data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import2.proto +23 -0
- data/src/ruby/spec/pb/codegen/grpc/testing/package_options_ruby_style.proto +41 -0
- data/src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto +27 -0
- data/src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto +29 -0
- data/src/ruby/spec/pb/codegen/package_option_spec.rb +98 -0
- data/src/ruby/spec/pb/duplicate/codegen_spec.rb +57 -0
- data/src/ruby/spec/pb/health/checker_spec.rb +236 -0
- data/src/ruby/spec/server_credentials_spec.rb +104 -0
- data/src/ruby/spec/server_spec.rb +231 -0
- data/src/ruby/spec/spec_helper.rb +61 -0
- data/src/ruby/spec/support/helpers.rb +107 -0
- data/src/ruby/spec/support/services.rb +163 -0
- data/src/ruby/spec/testdata/README +1 -0
- data/src/ruby/spec/testdata/ca.pem +20 -0
- data/src/ruby/spec/testdata/client.key +28 -0
- data/src/ruby/spec/testdata/client.pem +20 -0
- data/src/ruby/spec/testdata/server1.key +28 -0
- data/src/ruby/spec/testdata/server1.pem +22 -0
- data/src/ruby/spec/time_consts_spec.rb +74 -0
- data/src/ruby/spec/user_agent_spec.rb +74 -0
- metadata +411 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
/*
|
2
|
+
*
|
3
|
+
* Copyright 2016 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
|
+
void grpc_rb_event_queue_thread_start();
|
20
|
+
void grpc_rb_event_queue_thread_stop();
|
21
|
+
|
22
|
+
void grpc_rb_event_queue_enqueue(void (*callback)(void*), void* argument);
|
@@ -0,0 +1,500 @@
|
|
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 <grpc/grpc.h>
|
24
|
+
#include <grpc/support/log.h>
|
25
|
+
#include <grpc/support/time.h>
|
26
|
+
#include <math.h>
|
27
|
+
#include <ruby/vm.h>
|
28
|
+
#include <stdbool.h>
|
29
|
+
#include <sys/types.h>
|
30
|
+
#include <unistd.h>
|
31
|
+
|
32
|
+
#include "rb_call.h"
|
33
|
+
#include "rb_call_credentials.h"
|
34
|
+
#include "rb_channel.h"
|
35
|
+
#include "rb_channel_credentials.h"
|
36
|
+
#include "rb_compression_options.h"
|
37
|
+
#include "rb_event_thread.h"
|
38
|
+
#include "rb_grpc_imports.generated.h"
|
39
|
+
#include "rb_loader.h"
|
40
|
+
#include "rb_server.h"
|
41
|
+
#include "rb_server_credentials.h"
|
42
|
+
#include "rb_xds_channel_credentials.h"
|
43
|
+
#include "rb_xds_server_credentials.h"
|
44
|
+
|
45
|
+
#ifdef GPR_LINUX
|
46
|
+
#include <sys/syscall.h>
|
47
|
+
#include <unistd.h>
|
48
|
+
#endif
|
49
|
+
|
50
|
+
static VALUE grpc_rb_cTimeVal = Qnil;
|
51
|
+
|
52
|
+
static rb_data_type_t grpc_rb_timespec_data_type = {
|
53
|
+
"gpr_timespec",
|
54
|
+
{GRPC_RB_GC_NOT_MARKED,
|
55
|
+
GRPC_RB_GC_DONT_FREE,
|
56
|
+
GRPC_RB_MEMSIZE_UNAVAILABLE,
|
57
|
+
{NULL, NULL}},
|
58
|
+
NULL,
|
59
|
+
NULL,
|
60
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
61
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
62
|
+
#endif
|
63
|
+
};
|
64
|
+
|
65
|
+
/* Alloc func that blocks allocation of a given object by raising an
|
66
|
+
* exception. */
|
67
|
+
VALUE grpc_rb_cannot_alloc(VALUE cls) {
|
68
|
+
rb_raise(rb_eTypeError,
|
69
|
+
"allocation of %s only allowed from the gRPC native layer",
|
70
|
+
rb_class2name(cls));
|
71
|
+
return Qnil;
|
72
|
+
}
|
73
|
+
|
74
|
+
/* Init func that fails by raising an exception. */
|
75
|
+
VALUE grpc_rb_cannot_init(VALUE self) {
|
76
|
+
rb_raise(rb_eTypeError,
|
77
|
+
"initialization of %s only allowed from the gRPC native layer",
|
78
|
+
rb_obj_classname(self));
|
79
|
+
return Qnil;
|
80
|
+
}
|
81
|
+
|
82
|
+
/* Init/Clone func that fails by raising an exception. */
|
83
|
+
VALUE grpc_rb_cannot_init_copy(VALUE copy, VALUE self) {
|
84
|
+
(void)self;
|
85
|
+
rb_raise(rb_eTypeError, "Copy initialization of %s is not supported",
|
86
|
+
rb_obj_classname(copy));
|
87
|
+
return Qnil;
|
88
|
+
}
|
89
|
+
|
90
|
+
/* id_tv_{,u}sec are accessor methods on Ruby Time instances. */
|
91
|
+
static ID id_tv_sec;
|
92
|
+
static ID id_tv_nsec;
|
93
|
+
|
94
|
+
/**
|
95
|
+
* grpc_rb_time_timeval creates a timeval from a ruby time object.
|
96
|
+
*
|
97
|
+
* This func is copied from ruby source, MRI/source/time.c, which is published
|
98
|
+
* under the same license as the ruby.h, on which the entire extensions is
|
99
|
+
* based.
|
100
|
+
*/
|
101
|
+
gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
|
102
|
+
gpr_timespec t;
|
103
|
+
gpr_timespec* time_const;
|
104
|
+
const char* tstr = interval ? "time interval" : "time";
|
105
|
+
const char* want = " want <secs from epoch>|<Time>|<GRPC::TimeConst.*>";
|
106
|
+
|
107
|
+
t.clock_type = GPR_CLOCK_REALTIME;
|
108
|
+
switch (TYPE(time)) {
|
109
|
+
case T_DATA:
|
110
|
+
if (CLASS_OF(time) == grpc_rb_cTimeVal) {
|
111
|
+
TypedData_Get_Struct(time, gpr_timespec, &grpc_rb_timespec_data_type,
|
112
|
+
time_const);
|
113
|
+
t = *time_const;
|
114
|
+
} else if (CLASS_OF(time) == rb_cTime) {
|
115
|
+
t.tv_sec = NUM2INT(rb_funcall(time, id_tv_sec, 0));
|
116
|
+
t.tv_nsec = NUM2INT(rb_funcall(time, id_tv_nsec, 0));
|
117
|
+
} else {
|
118
|
+
rb_raise(rb_eTypeError, "bad input: (%s)->c_timeval, got <%s>,%s", tstr,
|
119
|
+
rb_obj_classname(time), want);
|
120
|
+
}
|
121
|
+
break;
|
122
|
+
|
123
|
+
case T_FIXNUM:
|
124
|
+
t.tv_sec = FIX2LONG(time);
|
125
|
+
if (interval && t.tv_sec < 0)
|
126
|
+
rb_raise(rb_eArgError, "%s must be positive", tstr);
|
127
|
+
t.tv_nsec = 0;
|
128
|
+
break;
|
129
|
+
|
130
|
+
case T_FLOAT:
|
131
|
+
if (interval && RFLOAT_VALUE(time) < 0.0)
|
132
|
+
rb_raise(rb_eArgError, "%s must be positive", tstr);
|
133
|
+
else {
|
134
|
+
double f, d;
|
135
|
+
|
136
|
+
d = modf(RFLOAT_VALUE(time), &f);
|
137
|
+
if (d < 0) {
|
138
|
+
d += 1;
|
139
|
+
f -= 1;
|
140
|
+
}
|
141
|
+
t.tv_sec = (int64_t)f;
|
142
|
+
if (f != t.tv_sec) {
|
143
|
+
rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT_VALUE(time));
|
144
|
+
}
|
145
|
+
t.tv_nsec = (int)(d * 1e9 + 0.5);
|
146
|
+
}
|
147
|
+
break;
|
148
|
+
|
149
|
+
case T_BIGNUM:
|
150
|
+
t.tv_sec = NUM2LONG(time);
|
151
|
+
if (interval && t.tv_sec < 0)
|
152
|
+
rb_raise(rb_eArgError, "%s must be positive", tstr);
|
153
|
+
t.tv_nsec = 0;
|
154
|
+
break;
|
155
|
+
|
156
|
+
default:
|
157
|
+
rb_raise(rb_eTypeError, "bad input: (%s)->c_timeval, got <%s>,%s", tstr,
|
158
|
+
rb_obj_classname(time), want);
|
159
|
+
break;
|
160
|
+
}
|
161
|
+
return t;
|
162
|
+
}
|
163
|
+
|
164
|
+
/* id_at is the constructor method of the ruby standard Time class. */
|
165
|
+
static ID id_at;
|
166
|
+
|
167
|
+
/* id_inspect is the inspect method found on various ruby objects. */
|
168
|
+
static ID id_inspect;
|
169
|
+
|
170
|
+
/* id_to_s is the to_s method found on various ruby objects. */
|
171
|
+
static ID id_to_s;
|
172
|
+
|
173
|
+
/* Converts a wrapped time constant to a standard time. */
|
174
|
+
static VALUE grpc_rb_time_val_to_time(VALUE self) {
|
175
|
+
gpr_timespec* time_const = NULL;
|
176
|
+
gpr_timespec real_time;
|
177
|
+
TypedData_Get_Struct(self, gpr_timespec, &grpc_rb_timespec_data_type,
|
178
|
+
time_const);
|
179
|
+
real_time = gpr_convert_clock_type(*time_const, GPR_CLOCK_REALTIME);
|
180
|
+
return rb_funcall(rb_cTime, id_at, 2, INT2NUM(real_time.tv_sec),
|
181
|
+
INT2NUM(real_time.tv_nsec / 1000));
|
182
|
+
}
|
183
|
+
|
184
|
+
/* Invokes inspect on the ctime version of the time val. */
|
185
|
+
static VALUE grpc_rb_time_val_inspect(VALUE self) {
|
186
|
+
return rb_funcall(grpc_rb_time_val_to_time(self), id_inspect, 0);
|
187
|
+
}
|
188
|
+
|
189
|
+
/* Invokes to_s on the ctime version of the time val. */
|
190
|
+
static VALUE grpc_rb_time_val_to_s(VALUE self) {
|
191
|
+
return rb_funcall(grpc_rb_time_val_to_time(self), id_to_s, 0);
|
192
|
+
}
|
193
|
+
|
194
|
+
static gpr_timespec zero_realtime;
|
195
|
+
static gpr_timespec inf_future_realtime;
|
196
|
+
static gpr_timespec inf_past_realtime;
|
197
|
+
|
198
|
+
/* Adds a module with constants that map to gpr's static timeval structs. */
|
199
|
+
static void Init_grpc_time_consts() {
|
200
|
+
VALUE grpc_rb_mTimeConsts =
|
201
|
+
rb_define_module_under(grpc_rb_mGrpcCore, "TimeConsts");
|
202
|
+
grpc_rb_cTimeVal =
|
203
|
+
rb_define_class_under(grpc_rb_mGrpcCore, "TimeSpec", rb_cObject);
|
204
|
+
rb_undef_alloc_func(grpc_rb_cTimeVal);
|
205
|
+
zero_realtime = gpr_time_0(GPR_CLOCK_REALTIME);
|
206
|
+
inf_future_realtime = gpr_inf_future(GPR_CLOCK_REALTIME);
|
207
|
+
inf_past_realtime = gpr_inf_past(GPR_CLOCK_REALTIME);
|
208
|
+
rb_define_const(
|
209
|
+
grpc_rb_mTimeConsts, "ZERO",
|
210
|
+
TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
|
211
|
+
(void*)&zero_realtime));
|
212
|
+
rb_define_const(
|
213
|
+
grpc_rb_mTimeConsts, "INFINITE_FUTURE",
|
214
|
+
TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
|
215
|
+
(void*)&inf_future_realtime));
|
216
|
+
rb_define_const(
|
217
|
+
grpc_rb_mTimeConsts, "INFINITE_PAST",
|
218
|
+
TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
|
219
|
+
(void*)&inf_past_realtime));
|
220
|
+
rb_define_method(grpc_rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0);
|
221
|
+
rb_define_method(grpc_rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0);
|
222
|
+
rb_define_method(grpc_rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0);
|
223
|
+
id_at = rb_intern("at");
|
224
|
+
id_inspect = rb_intern("inspect");
|
225
|
+
id_to_s = rb_intern("to_s");
|
226
|
+
id_tv_sec = rb_intern("tv_sec");
|
227
|
+
id_tv_nsec = rb_intern("tv_nsec");
|
228
|
+
}
|
229
|
+
|
230
|
+
static bool g_enable_fork_support;
|
231
|
+
|
232
|
+
#ifdef GPR_LINUX
|
233
|
+
static long sys_gettid() { return syscall(__NR_gettid); }
|
234
|
+
static bool can_enable_fork_support() { return true; }
|
235
|
+
#else
|
236
|
+
static long sys_gettid() { return 0; }
|
237
|
+
static bool can_enable_fork_support() { return false; }
|
238
|
+
#endif
|
239
|
+
|
240
|
+
#if GPR_WINDOWS
|
241
|
+
static void grpc_ruby_basic_init(void) {}
|
242
|
+
static bool grpc_ruby_initial_pid(void) { return true; }
|
243
|
+
static bool grpc_ruby_initial_thread(void) { return true; }
|
244
|
+
static void grpc_ruby_reset_init_state(void) {}
|
245
|
+
#else
|
246
|
+
static pid_t g_init_pid;
|
247
|
+
static long g_init_tid;
|
248
|
+
|
249
|
+
static bool grpc_ruby_initial_pid(void) {
|
250
|
+
GRPC_RUBY_ASSERT(g_init_pid != 0);
|
251
|
+
return g_init_pid == getpid();
|
252
|
+
}
|
253
|
+
|
254
|
+
static bool grpc_ruby_initial_thread(void) {
|
255
|
+
GRPC_RUBY_ASSERT(g_init_tid != 0);
|
256
|
+
return sys_gettid() == g_init_tid;
|
257
|
+
}
|
258
|
+
|
259
|
+
static void grpc_ruby_reset_init_state(void) {
|
260
|
+
g_init_pid = getpid();
|
261
|
+
g_init_tid = sys_gettid();
|
262
|
+
}
|
263
|
+
|
264
|
+
static void grpc_ruby_basic_init(void) {
|
265
|
+
GRPC_RUBY_ASSERT(g_init_pid == 0);
|
266
|
+
GRPC_RUBY_ASSERT(g_init_tid == 0);
|
267
|
+
grpc_ruby_reset_init_state();
|
268
|
+
// TODO(apolcyn): ideally, we should share logic with C-core
|
269
|
+
// for determining whether or not fork support is enabled, rather
|
270
|
+
// than parsing the environment variable ourselves.
|
271
|
+
const char* res = getenv("GRPC_ENABLE_FORK_SUPPORT");
|
272
|
+
if (res != NULL && strcmp(res, "1") == 0) {
|
273
|
+
g_enable_fork_support = can_enable_fork_support();
|
274
|
+
}
|
275
|
+
}
|
276
|
+
#endif
|
277
|
+
|
278
|
+
/* Initialize the GRPC module structs */
|
279
|
+
|
280
|
+
/* grpc_rb_sNewServerRpc is the struct that holds new server rpc details. */
|
281
|
+
VALUE grpc_rb_sNewServerRpc = Qnil;
|
282
|
+
/* grpc_rb_sStatus is the struct that holds status details. */
|
283
|
+
VALUE grpc_rb_sStatus = Qnil;
|
284
|
+
|
285
|
+
/* Initialize the GRPC module. */
|
286
|
+
VALUE grpc_rb_mGRPC = Qnil;
|
287
|
+
VALUE grpc_rb_mGrpcCore = Qnil;
|
288
|
+
|
289
|
+
/* cached Symbols for members in Status struct */
|
290
|
+
VALUE sym_code = Qundef;
|
291
|
+
VALUE sym_details = Qundef;
|
292
|
+
VALUE sym_metadata = Qundef;
|
293
|
+
|
294
|
+
static gpr_once g_once_init = GPR_ONCE_INIT;
|
295
|
+
static int64_t g_grpc_rb_prefork_pending; // synchronized by the GIL
|
296
|
+
static int64_t g_grpc_rb_num_fork_unsafe_threads; // synchronized by the GIL
|
297
|
+
|
298
|
+
void grpc_ruby_fork_guard() {
|
299
|
+
// Check if we're using gRPC between prefork and postfork
|
300
|
+
gpr_once_init(&g_once_init, grpc_ruby_basic_init);
|
301
|
+
if (g_grpc_rb_prefork_pending) {
|
302
|
+
rb_raise(rb_eRuntimeError,
|
303
|
+
"grpc cannot be used between calls to GRPC.prefork and "
|
304
|
+
"GRPC.postfork_child or GRPC.postfork_parent");
|
305
|
+
}
|
306
|
+
if (!grpc_ruby_initial_pid()) {
|
307
|
+
if (g_enable_fork_support) {
|
308
|
+
// Only way we can get here is by enabling for support and forking but not
|
309
|
+
// calling prefork
|
310
|
+
rb_raise(rb_eRuntimeError,
|
311
|
+
"grpc is in a broken state: GRPC.prefork must be called before "
|
312
|
+
"calling fork from a process using grpc");
|
313
|
+
} else {
|
314
|
+
rb_raise(rb_eRuntimeError,
|
315
|
+
"grpc cannot be used before and after forking unless the "
|
316
|
+
"GRPC_ENABLE_FORK_SUPPORT env var is set to \"1\" and the "
|
317
|
+
"platform supports it (linux only)");
|
318
|
+
}
|
319
|
+
}
|
320
|
+
}
|
321
|
+
|
322
|
+
static VALUE g_bg_thread_init_rb_mu = Qundef;
|
323
|
+
static bool g_bg_thread_init_done;
|
324
|
+
|
325
|
+
static void grpc_ruby_init_threads() {
|
326
|
+
// Avoid calling into ruby library (when creating threads here)
|
327
|
+
// in gpr_once_init. In general, it appears to be unsafe to call
|
328
|
+
// into the ruby library while holding a non-ruby mutex, because a gil yield
|
329
|
+
// could end up trying to lock onto that same mutex and deadlocking.
|
330
|
+
grpc_absl_log_int(GPR_DEBUG,
|
331
|
+
"GRPC_RUBY: grpc_ruby_init_threads g_bg_thread_init_done=",
|
332
|
+
g_bg_thread_init_done);
|
333
|
+
rb_mutex_lock(g_bg_thread_init_rb_mu);
|
334
|
+
if (!g_bg_thread_init_done) {
|
335
|
+
grpc_rb_event_queue_thread_start();
|
336
|
+
g_bg_thread_init_done = true;
|
337
|
+
}
|
338
|
+
rb_mutex_unlock(g_bg_thread_init_rb_mu);
|
339
|
+
}
|
340
|
+
|
341
|
+
static int64_t g_grpc_ruby_init_count;
|
342
|
+
|
343
|
+
void grpc_ruby_init() {
|
344
|
+
gpr_once_init(&g_once_init, grpc_ruby_basic_init);
|
345
|
+
grpc_ruby_fork_guard();
|
346
|
+
grpc_init();
|
347
|
+
grpc_ruby_init_threads();
|
348
|
+
// (only log after logging has been initialized)
|
349
|
+
grpc_absl_log_int(GPR_DEBUG,
|
350
|
+
"GRPC_RUBY: grpc_ruby_init - g_enable_fork_support=",
|
351
|
+
g_enable_fork_support);
|
352
|
+
grpc_absl_log_int(GPR_DEBUG,
|
353
|
+
"prev g_grpc_ruby_init_count:", g_grpc_ruby_init_count++);
|
354
|
+
}
|
355
|
+
|
356
|
+
// fork APIs, useable on linux with env var: GRPC_ENABLE_FORK_SUPPORT=1
|
357
|
+
//
|
358
|
+
// Must be called once and only once before forking. Must be called on the
|
359
|
+
// same threads that gRPC was (lazy-)initialized on. One must not call
|
360
|
+
// into the gRPC library during or after prefork has been called, until
|
361
|
+
// the corresponding postfork_{parent,child} APIs have been called.
|
362
|
+
static VALUE grpc_rb_prefork(VALUE self) {
|
363
|
+
// This might be the first time we've called into the grpc library, so make
|
364
|
+
// sure basic one-time initialization is taken care of. Note that if this is
|
365
|
+
// the case, then grpc_init() will start up c-core threads; that's OK since
|
366
|
+
// they will be shut down in C-core's pthread_atfork handler.
|
367
|
+
gpr_once_init(&g_once_init, grpc_ruby_basic_init);
|
368
|
+
grpc_init();
|
369
|
+
if (!g_enable_fork_support) {
|
370
|
+
rb_raise(rb_eRuntimeError,
|
371
|
+
"forking with gRPC/Ruby is only supported on linux with env var: "
|
372
|
+
"GRPC_ENABLE_FORK_SUPPORT=1");
|
373
|
+
}
|
374
|
+
if (g_grpc_rb_prefork_pending) {
|
375
|
+
rb_raise(rb_eRuntimeError,
|
376
|
+
"GRPC.prefork already called without a matching "
|
377
|
+
"GRPC.postfork_{parent,child}");
|
378
|
+
}
|
379
|
+
if (!grpc_ruby_initial_thread()) {
|
380
|
+
rb_raise(rb_eRuntimeError,
|
381
|
+
"GRPC.prefork and fork need to be called from the same thread "
|
382
|
+
"that GRPC was initialized on (GRPC lazy-initializes when when "
|
383
|
+
"the first GRPC object is created)");
|
384
|
+
}
|
385
|
+
if (g_grpc_rb_num_fork_unsafe_threads > 0) {
|
386
|
+
rb_raise(
|
387
|
+
rb_eRuntimeError,
|
388
|
+
"Detected at least %ld threads actively using grpc, so it is not safe "
|
389
|
+
"call GRPC.prefork or fork. Note that grpc-ruby servers and "
|
390
|
+
"bidirectional "
|
391
|
+
"streams manage background threads and are not fork safe.",
|
392
|
+
g_grpc_rb_num_fork_unsafe_threads);
|
393
|
+
}
|
394
|
+
g_grpc_rb_prefork_pending = true;
|
395
|
+
rb_mutex_lock(g_bg_thread_init_rb_mu);
|
396
|
+
if (g_bg_thread_init_done) {
|
397
|
+
grpc_rb_event_queue_thread_stop();
|
398
|
+
// all ruby-level background threads joined at this point
|
399
|
+
g_bg_thread_init_done = false;
|
400
|
+
}
|
401
|
+
rb_mutex_unlock(g_bg_thread_init_rb_mu);
|
402
|
+
return Qnil;
|
403
|
+
}
|
404
|
+
|
405
|
+
static VALUE grpc_rb_postfork_child(VALUE self) {
|
406
|
+
if (!g_grpc_rb_prefork_pending) {
|
407
|
+
rb_raise(rb_eRuntimeError,
|
408
|
+
"GRPC::postfork_child can only be called once following a "
|
409
|
+
"GRPC::prefork");
|
410
|
+
}
|
411
|
+
if (grpc_ruby_initial_pid()) {
|
412
|
+
rb_raise(rb_eRuntimeError,
|
413
|
+
"GRPC.postfork_child must be called only from the child process "
|
414
|
+
"after a fork");
|
415
|
+
}
|
416
|
+
grpc_ruby_reset_init_state();
|
417
|
+
grpc_ruby_init_threads();
|
418
|
+
g_grpc_rb_prefork_pending = false;
|
419
|
+
return Qnil;
|
420
|
+
}
|
421
|
+
|
422
|
+
static VALUE grpc_rb_postfork_parent(VALUE self) {
|
423
|
+
// TODO(apolcyn): check calling thread vs. thread that gRPC was initialized on
|
424
|
+
if (!g_grpc_rb_prefork_pending) {
|
425
|
+
rb_raise(rb_eRuntimeError,
|
426
|
+
"GRPC::postfork_parent can only be called once following a "
|
427
|
+
"GRPC::prefork");
|
428
|
+
}
|
429
|
+
if (!grpc_ruby_initial_pid()) {
|
430
|
+
rb_raise(rb_eRuntimeError,
|
431
|
+
"GRPC.postfork_parent must be called only from the parent process "
|
432
|
+
"after a fork");
|
433
|
+
}
|
434
|
+
if (!grpc_ruby_initial_thread()) {
|
435
|
+
rb_raise(rb_eRuntimeError,
|
436
|
+
"GRPC.postfork_parent needs to be called from the same thread "
|
437
|
+
"that GRPC.prefork (and fork) was called from");
|
438
|
+
}
|
439
|
+
grpc_ruby_init_threads();
|
440
|
+
g_grpc_rb_prefork_pending = false;
|
441
|
+
return Qnil;
|
442
|
+
}
|
443
|
+
|
444
|
+
// APIs to mark fork-unsafe sections from C-extension code
|
445
|
+
void grpc_rb_fork_unsafe_begin() { g_grpc_rb_num_fork_unsafe_threads++; }
|
446
|
+
|
447
|
+
void grpc_rb_fork_unsafe_end() { g_grpc_rb_num_fork_unsafe_threads--; }
|
448
|
+
|
449
|
+
// APIs to mark fork-unsafe sections from ruby code
|
450
|
+
static VALUE grpc_rb_fork_unsafe_begin_api() {
|
451
|
+
grpc_rb_fork_unsafe_begin();
|
452
|
+
return Qnil;
|
453
|
+
}
|
454
|
+
|
455
|
+
static VALUE grpc_rb_fork_unsafe_end_api() {
|
456
|
+
grpc_rb_fork_unsafe_end();
|
457
|
+
return Qnil;
|
458
|
+
}
|
459
|
+
|
460
|
+
// One-time initialization
|
461
|
+
void Init_grpc_c() {
|
462
|
+
if (!grpc_rb_load_core()) {
|
463
|
+
rb_raise(rb_eLoadError, "Couldn't find or load gRPC's dynamic C core");
|
464
|
+
return;
|
465
|
+
}
|
466
|
+
|
467
|
+
rb_global_variable(&g_bg_thread_init_rb_mu);
|
468
|
+
g_bg_thread_init_rb_mu = rb_mutex_new();
|
469
|
+
|
470
|
+
grpc_rb_mGRPC = rb_define_module("GRPC");
|
471
|
+
grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core");
|
472
|
+
grpc_rb_sNewServerRpc = rb_struct_define(
|
473
|
+
"NewServerRpc", "method", "host", "deadline", "metadata", "call", NULL);
|
474
|
+
rb_global_variable(&grpc_rb_sStatus);
|
475
|
+
grpc_rb_sStatus = rb_const_get(rb_cStruct, rb_intern("Status"));
|
476
|
+
sym_code = ID2SYM(rb_intern("code"));
|
477
|
+
sym_details = ID2SYM(rb_intern("details"));
|
478
|
+
sym_metadata = ID2SYM(rb_intern("metadata"));
|
479
|
+
// init C-defined classes
|
480
|
+
Init_grpc_channel();
|
481
|
+
Init_grpc_call();
|
482
|
+
Init_grpc_call_credentials();
|
483
|
+
Init_grpc_channel_credentials();
|
484
|
+
Init_grpc_xds_channel_credentials();
|
485
|
+
Init_grpc_server();
|
486
|
+
Init_grpc_server_credentials();
|
487
|
+
Init_grpc_xds_server_credentials();
|
488
|
+
Init_grpc_time_consts();
|
489
|
+
Init_grpc_compression_options();
|
490
|
+
// define fork APIs
|
491
|
+
rb_define_module_function(grpc_rb_mGRPC, "prefork", grpc_rb_prefork, 0);
|
492
|
+
rb_define_module_function(grpc_rb_mGRPC, "postfork_child",
|
493
|
+
grpc_rb_postfork_child, 0);
|
494
|
+
rb_define_module_function(grpc_rb_mGRPC, "postfork_parent",
|
495
|
+
grpc_rb_postfork_parent, 0);
|
496
|
+
rb_define_module_function(grpc_rb_mGrpcCore, "fork_unsafe_begin",
|
497
|
+
grpc_rb_fork_unsafe_begin_api, 0);
|
498
|
+
rb_define_module_function(grpc_rb_mGrpcCore, "fork_unsafe_end",
|
499
|
+
grpc_rb_fork_unsafe_end_api, 0);
|
500
|
+
}
|
@@ -0,0 +1,88 @@
|
|
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
|
+
#ifndef GRPC_RB_H_
|
20
|
+
#define GRPC_RB_H_
|
21
|
+
|
22
|
+
#include <ruby/ruby.h>
|
23
|
+
|
24
|
+
#include <grpc/support/time.h>
|
25
|
+
#include <stdlib.h>
|
26
|
+
|
27
|
+
/* grpc_rb_mGrpcCore is the module containing the ruby wrapper GRPC classes. */
|
28
|
+
extern VALUE grpc_rb_mGrpcCore;
|
29
|
+
|
30
|
+
/* grpc_rb_sNewServerRpc is the struct that holds new server rpc details. */
|
31
|
+
extern VALUE grpc_rb_sNewServerRpc;
|
32
|
+
|
33
|
+
/* grpc_rb_sStruct is the struct that holds status details. */
|
34
|
+
extern VALUE grpc_rb_sStatus;
|
35
|
+
|
36
|
+
/* sym_code is the symbol for the code attribute of grpc_rb_sStatus. */
|
37
|
+
extern VALUE sym_code;
|
38
|
+
|
39
|
+
/* sym_details is the symbol for the details attribute of grpc_rb_sStatus. */
|
40
|
+
extern VALUE sym_details;
|
41
|
+
|
42
|
+
/* sym_metadata is the symbol for the metadata attribute of grpc_rb_sStatus. */
|
43
|
+
extern VALUE sym_metadata;
|
44
|
+
|
45
|
+
/* GC_NOT_MARKED is used in calls to Data_Wrap_Struct to indicate that the
|
46
|
+
wrapped struct does not need to participate in ruby gc. */
|
47
|
+
#define GRPC_RB_GC_NOT_MARKED (RUBY_DATA_FUNC)(NULL)
|
48
|
+
|
49
|
+
/* GC_DONT_FREED is used in calls to Data_Wrap_Struct to indicate that the
|
50
|
+
wrapped struct should not be freed the wrapped ruby object is released by
|
51
|
+
the garbage collector. */
|
52
|
+
#define GRPC_RB_GC_DONT_FREE (RUBY_DATA_FUNC)(NULL)
|
53
|
+
|
54
|
+
/* GRPC_RB_MEMSIZE_UNAVAILABLE is used in rb_data_type_t to indicate that the
|
55
|
+
* number of bytes used by the wrapped struct is not available. */
|
56
|
+
#define GRPC_RB_MEMSIZE_UNAVAILABLE (size_t (*)(const void*))(NULL)
|
57
|
+
|
58
|
+
/* A ruby object alloc func that fails by raising an exception. */
|
59
|
+
VALUE grpc_rb_cannot_alloc(VALUE cls);
|
60
|
+
|
61
|
+
/* A ruby object init func that fails by raising an exception. */
|
62
|
+
VALUE grpc_rb_cannot_init(VALUE self);
|
63
|
+
|
64
|
+
/* A ruby object clone init func that fails by raising an exception. */
|
65
|
+
VALUE grpc_rb_cannot_init_copy(VALUE copy, VALUE self);
|
66
|
+
|
67
|
+
/* grpc_rb_time_timeval creates a gpr_timespec from a ruby time object. */
|
68
|
+
gpr_timespec grpc_rb_time_timeval(VALUE time, int interval);
|
69
|
+
|
70
|
+
void grpc_ruby_fork_guard();
|
71
|
+
|
72
|
+
/* To be called once and only once before entering code section that is
|
73
|
+
* definitely not fork-safe. Used in conjunction with GRPC.prefork
|
74
|
+
* to catch for-unsafe processes and raise errors. */
|
75
|
+
void grpc_rb_fork_unsafe_begin();
|
76
|
+
|
77
|
+
/* To be called once and only once after each grpc_rb_fork_unsafe_begin*/
|
78
|
+
void grpc_rb_fork_unsafe_end();
|
79
|
+
|
80
|
+
void grpc_ruby_init();
|
81
|
+
|
82
|
+
#define GRPC_RUBY_ASSERT(x) \
|
83
|
+
if (!(x)) { \
|
84
|
+
fprintf(stderr, "%s:%d assert failed\n", __FILE__, __LINE__); \
|
85
|
+
abort(); \
|
86
|
+
}
|
87
|
+
|
88
|
+
#endif /* GRPC_RB_H_ */
|