grpc 1.60.0.pre1-aarch64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/etc/roots.pem +4337 -0
  3. data/grpc_c.32-msvcrt.ruby +0 -0
  4. data/grpc_c.64-msvcrt.ruby +0 -0
  5. data/grpc_c.64-ucrt.ruby +0 -0
  6. data/src/ruby/bin/math_client.rb +140 -0
  7. data/src/ruby/bin/math_pb.rb +40 -0
  8. data/src/ruby/bin/math_server.rb +191 -0
  9. data/src/ruby/bin/math_services_pb.rb +51 -0
  10. data/src/ruby/bin/noproto_client.rb +93 -0
  11. data/src/ruby/bin/noproto_server.rb +97 -0
  12. data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.clang +2 -0
  13. data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.gcc +7 -0
  14. data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.clang +2 -0
  15. data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.gcc +7 -0
  16. data/src/ruby/ext/grpc/ext-export.clang +1 -0
  17. data/src/ruby/ext/grpc/ext-export.gcc +6 -0
  18. data/src/ruby/ext/grpc/extconf.rb +270 -0
  19. data/src/ruby/ext/grpc/rb_byte_buffer.c +65 -0
  20. data/src/ruby/ext/grpc/rb_byte_buffer.h +35 -0
  21. data/src/ruby/ext/grpc/rb_call.c +1075 -0
  22. data/src/ruby/ext/grpc/rb_call.h +57 -0
  23. data/src/ruby/ext/grpc/rb_call_credentials.c +340 -0
  24. data/src/ruby/ext/grpc/rb_call_credentials.h +31 -0
  25. data/src/ruby/ext/grpc/rb_channel.c +875 -0
  26. data/src/ruby/ext/grpc/rb_channel.h +35 -0
  27. data/src/ruby/ext/grpc/rb_channel_args.c +172 -0
  28. data/src/ruby/ext/grpc/rb_channel_args.h +42 -0
  29. data/src/ruby/ext/grpc/rb_channel_credentials.c +285 -0
  30. data/src/ruby/ext/grpc/rb_channel_credentials.h +37 -0
  31. data/src/ruby/ext/grpc/rb_completion_queue.c +101 -0
  32. data/src/ruby/ext/grpc/rb_completion_queue.h +36 -0
  33. data/src/ruby/ext/grpc/rb_compression_options.c +470 -0
  34. data/src/ruby/ext/grpc/rb_compression_options.h +29 -0
  35. data/src/ruby/ext/grpc/rb_enable_cpp.cc +22 -0
  36. data/src/ruby/ext/grpc/rb_event_thread.c +161 -0
  37. data/src/ruby/ext/grpc/rb_event_thread.h +22 -0
  38. data/src/ruby/ext/grpc/rb_grpc.c +496 -0
  39. data/src/ruby/ext/grpc/rb_grpc.h +83 -0
  40. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +603 -0
  41. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +910 -0
  42. data/src/ruby/ext/grpc/rb_loader.c +61 -0
  43. data/src/ruby/ext/grpc/rb_loader.h +25 -0
  44. data/src/ruby/ext/grpc/rb_server.c +405 -0
  45. data/src/ruby/ext/grpc/rb_server.h +32 -0
  46. data/src/ruby/ext/grpc/rb_server_credentials.c +258 -0
  47. data/src/ruby/ext/grpc/rb_server_credentials.h +37 -0
  48. data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +217 -0
  49. data/src/ruby/ext/grpc/rb_xds_channel_credentials.h +37 -0
  50. data/src/ruby/ext/grpc/rb_xds_server_credentials.c +169 -0
  51. data/src/ruby/ext/grpc/rb_xds_server_credentials.h +37 -0
  52. data/src/ruby/lib/grpc/2.7/grpc_c.so +0 -0
  53. data/src/ruby/lib/grpc/3.0/grpc_c.so +0 -0
  54. data/src/ruby/lib/grpc/3.1/grpc_c.so +0 -0
  55. data/src/ruby/lib/grpc/3.2/grpc_c.so +0 -0
  56. data/src/ruby/lib/grpc/core/status_codes.rb +135 -0
  57. data/src/ruby/lib/grpc/core/time_consts.rb +56 -0
  58. data/src/ruby/lib/grpc/errors.rb +277 -0
  59. data/src/ruby/lib/grpc/generic/active_call.rb +670 -0
  60. data/src/ruby/lib/grpc/generic/bidi_call.rb +237 -0
  61. data/src/ruby/lib/grpc/generic/client_stub.rb +503 -0
  62. data/src/ruby/lib/grpc/generic/interceptor_registry.rb +53 -0
  63. data/src/ruby/lib/grpc/generic/interceptors.rb +186 -0
  64. data/src/ruby/lib/grpc/generic/rpc_desc.rb +204 -0
  65. data/src/ruby/lib/grpc/generic/rpc_server.rb +551 -0
  66. data/src/ruby/lib/grpc/generic/service.rb +211 -0
  67. data/src/ruby/lib/grpc/google_rpc_status_utils.rb +40 -0
  68. data/src/ruby/lib/grpc/grpc.rb +24 -0
  69. data/src/ruby/lib/grpc/logconfig.rb +44 -0
  70. data/src/ruby/lib/grpc/notifier.rb +45 -0
  71. data/src/ruby/lib/grpc/structs.rb +15 -0
  72. data/src/ruby/lib/grpc/version.rb +18 -0
  73. data/src/ruby/lib/grpc.rb +37 -0
  74. data/src/ruby/pb/README.md +42 -0
  75. data/src/ruby/pb/generate_proto_ruby.sh +46 -0
  76. data/src/ruby/pb/grpc/health/checker.rb +75 -0
  77. data/src/ruby/pb/grpc/health/v1/health_pb.rb +42 -0
  78. data/src/ruby/pb/grpc/health/v1/health_services_pb.rb +62 -0
  79. data/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb +44 -0
  80. data/src/ruby/pb/grpc/testing/metrics_pb.rb +28 -0
  81. data/src/ruby/pb/grpc/testing/metrics_services_pb.rb +49 -0
  82. data/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb +38 -0
  83. data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +71 -0
  84. data/src/ruby/pb/src/proto/grpc/testing/test_pb.rb +40 -0
  85. data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +174 -0
  86. data/src/ruby/pb/test/client.rb +785 -0
  87. data/src/ruby/pb/test/server.rb +252 -0
  88. data/src/ruby/pb/test/xds_client.rb +415 -0
  89. data/src/ruby/spec/call_credentials_spec.rb +42 -0
  90. data/src/ruby/spec/call_spec.rb +180 -0
  91. data/src/ruby/spec/channel_connection_spec.rb +126 -0
  92. data/src/ruby/spec/channel_credentials_spec.rb +124 -0
  93. data/src/ruby/spec/channel_spec.rb +207 -0
  94. data/src/ruby/spec/client_auth_spec.rb +152 -0
  95. data/src/ruby/spec/client_server_spec.rb +676 -0
  96. data/src/ruby/spec/compression_options_spec.rb +149 -0
  97. data/src/ruby/spec/debug_message_spec.rb +134 -0
  98. data/src/ruby/spec/error_sanity_spec.rb +49 -0
  99. data/src/ruby/spec/errors_spec.rb +142 -0
  100. data/src/ruby/spec/generic/active_call_spec.rb +692 -0
  101. data/src/ruby/spec/generic/client_interceptors_spec.rb +153 -0
  102. data/src/ruby/spec/generic/client_stub_spec.rb +1083 -0
  103. data/src/ruby/spec/generic/interceptor_registry_spec.rb +65 -0
  104. data/src/ruby/spec/generic/rpc_desc_spec.rb +374 -0
  105. data/src/ruby/spec/generic/rpc_server_pool_spec.rb +127 -0
  106. data/src/ruby/spec/generic/rpc_server_spec.rb +748 -0
  107. data/src/ruby/spec/generic/server_interceptors_spec.rb +218 -0
  108. data/src/ruby/spec/generic/service_spec.rb +263 -0
  109. data/src/ruby/spec/google_rpc_status_utils_spec.rb +282 -0
  110. data/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto +28 -0
  111. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import.proto +22 -0
  112. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import2.proto +23 -0
  113. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_ruby_style.proto +41 -0
  114. data/src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto +27 -0
  115. data/src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto +29 -0
  116. data/src/ruby/spec/pb/codegen/package_option_spec.rb +98 -0
  117. data/src/ruby/spec/pb/duplicate/codegen_spec.rb +57 -0
  118. data/src/ruby/spec/pb/health/checker_spec.rb +236 -0
  119. data/src/ruby/spec/server_credentials_spec.rb +104 -0
  120. data/src/ruby/spec/server_spec.rb +231 -0
  121. data/src/ruby/spec/spec_helper.rb +61 -0
  122. data/src/ruby/spec/support/helpers.rb +107 -0
  123. data/src/ruby/spec/support/services.rb +160 -0
  124. data/src/ruby/spec/testdata/README +1 -0
  125. data/src/ruby/spec/testdata/ca.pem +20 -0
  126. data/src/ruby/spec/testdata/client.key +28 -0
  127. data/src/ruby/spec/testdata/client.pem +20 -0
  128. data/src/ruby/spec/testdata/server1.key +28 -0
  129. data/src/ruby/spec/testdata/server1.pem +22 -0
  130. data/src/ruby/spec/time_consts_spec.rb +74 -0
  131. data/src/ruby/spec/user_agent_spec.rb +74 -0
  132. metadata +405 -0
@@ -0,0 +1,161 @@
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
+ #include <ruby/ruby.h>
20
+
21
+ #include "rb_event_thread.h"
22
+
23
+ #include <ruby/thread.h>
24
+ #include <stdbool.h>
25
+
26
+ #include "rb_grpc.h"
27
+ #include "rb_grpc_imports.generated.h"
28
+
29
+ #include <grpc/support/alloc.h>
30
+ #include <grpc/support/log.h>
31
+ #include <grpc/support/sync.h>
32
+ #include <grpc/support/time.h>
33
+
34
+ typedef struct grpc_rb_event {
35
+ // callback will be called with argument while holding the GVL
36
+ void (*callback)(void*);
37
+ void* argument;
38
+
39
+ struct grpc_rb_event* next;
40
+ } grpc_rb_event;
41
+
42
+ typedef struct grpc_rb_event_queue {
43
+ grpc_rb_event* head;
44
+ grpc_rb_event* tail;
45
+
46
+ gpr_mu mu;
47
+ gpr_cv cv;
48
+
49
+ // Indicates that the thread should stop waiting
50
+ bool abort;
51
+ } grpc_rb_event_queue;
52
+
53
+ static grpc_rb_event_queue event_queue;
54
+ static VALUE g_event_thread = Qnil;
55
+ static bool g_one_time_init_done = false;
56
+
57
+ void grpc_rb_event_queue_enqueue(void (*callback)(void*), void* argument) {
58
+ grpc_rb_event* event = gpr_malloc(sizeof(grpc_rb_event));
59
+ event->callback = callback;
60
+ event->argument = argument;
61
+ event->next = NULL;
62
+ gpr_mu_lock(&event_queue.mu);
63
+ if (event_queue.tail == NULL) {
64
+ event_queue.head = event_queue.tail = event;
65
+ } else {
66
+ event_queue.tail->next = event;
67
+ event_queue.tail = event;
68
+ }
69
+ gpr_cv_signal(&event_queue.cv);
70
+ gpr_mu_unlock(&event_queue.mu);
71
+ }
72
+
73
+ static grpc_rb_event* grpc_rb_event_queue_dequeue() {
74
+ grpc_rb_event* event;
75
+ if (event_queue.head == NULL) {
76
+ event = NULL;
77
+ } else {
78
+ event = event_queue.head;
79
+ if (event_queue.head->next == NULL) {
80
+ event_queue.head = event_queue.tail = NULL;
81
+ } else {
82
+ event_queue.head = event_queue.head->next;
83
+ }
84
+ }
85
+ return event;
86
+ }
87
+
88
+ static void grpc_rb_event_queue_destroy() {
89
+ gpr_mu_destroy(&event_queue.mu);
90
+ gpr_cv_destroy(&event_queue.cv);
91
+ }
92
+
93
+ static void* grpc_rb_wait_for_event_no_gil(void* param) {
94
+ grpc_rb_event* event = NULL;
95
+ (void)param;
96
+ gpr_mu_lock(&event_queue.mu);
97
+ while (!event_queue.abort) {
98
+ if ((event = grpc_rb_event_queue_dequeue()) != NULL) {
99
+ gpr_mu_unlock(&event_queue.mu);
100
+ return event;
101
+ }
102
+ gpr_cv_wait(&event_queue.cv, &event_queue.mu,
103
+ gpr_inf_future(GPR_CLOCK_REALTIME));
104
+ }
105
+ gpr_mu_unlock(&event_queue.mu);
106
+ return NULL;
107
+ }
108
+
109
+ static void grpc_rb_event_unblocking_func(void* arg) {
110
+ (void)arg;
111
+ gpr_mu_lock(&event_queue.mu);
112
+ event_queue.abort = true;
113
+ gpr_cv_signal(&event_queue.cv);
114
+ gpr_mu_unlock(&event_queue.mu);
115
+ }
116
+
117
+ /* This is the implementation of the thread that handles auth metadata plugin
118
+ * events */
119
+ static VALUE grpc_rb_event_thread(VALUE arg) {
120
+ grpc_rb_event* event;
121
+ (void)arg;
122
+ while (true) {
123
+ event = (grpc_rb_event*)rb_thread_call_without_gvl(
124
+ grpc_rb_wait_for_event_no_gil, NULL, grpc_rb_event_unblocking_func,
125
+ NULL);
126
+ if (event == NULL) {
127
+ // Indicates that the thread needs to shut down
128
+ break;
129
+ } else {
130
+ event->callback(event->argument);
131
+ gpr_free(event);
132
+ }
133
+ }
134
+ grpc_rb_event_queue_destroy();
135
+ return Qnil;
136
+ }
137
+
138
+ void grpc_rb_event_queue_thread_start() {
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
+ }
146
+ event_queue.abort = false;
147
+ GPR_ASSERT(!RTEST(g_event_thread));
148
+ g_event_thread = rb_thread_create(grpc_rb_event_thread, NULL);
149
+ }
150
+
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;
161
+ }
@@ -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,496 @@
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"
36
+ #include "rb_grpc_imports.generated.h"
37
+ #include "rb_loader.h"
38
+ #include "rb_server.h"
39
+ #include "rb_server_credentials.h"
40
+ #include "rb_xds_channel_credentials.h"
41
+ #include "rb_xds_server_credentials.h"
42
+
43
+ #include <grpc/grpc.h>
44
+ #include <grpc/support/log.h>
45
+ #include <grpc/support/time.h>
46
+
47
+ #ifdef GPR_LINUX
48
+ #include <sys/syscall.h>
49
+ #include <unistd.h>
50
+ #endif
51
+
52
+ static VALUE grpc_rb_cTimeVal = Qnil;
53
+
54
+ static rb_data_type_t grpc_rb_timespec_data_type = {
55
+ "gpr_timespec",
56
+ {GRPC_RB_GC_NOT_MARKED,
57
+ GRPC_RB_GC_DONT_FREE,
58
+ GRPC_RB_MEMSIZE_UNAVAILABLE,
59
+ {NULL, NULL}},
60
+ NULL,
61
+ NULL,
62
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
63
+ RUBY_TYPED_FREE_IMMEDIATELY
64
+ #endif
65
+ };
66
+
67
+ /* Alloc func that blocks allocation of a given object by raising an
68
+ * exception. */
69
+ VALUE grpc_rb_cannot_alloc(VALUE cls) {
70
+ rb_raise(rb_eTypeError,
71
+ "allocation of %s only allowed from the gRPC native layer",
72
+ rb_class2name(cls));
73
+ return Qnil;
74
+ }
75
+
76
+ /* Init func that fails by raising an exception. */
77
+ VALUE grpc_rb_cannot_init(VALUE self) {
78
+ rb_raise(rb_eTypeError,
79
+ "initialization of %s only allowed from the gRPC native layer",
80
+ rb_obj_classname(self));
81
+ return Qnil;
82
+ }
83
+
84
+ /* Init/Clone func that fails by raising an exception. */
85
+ VALUE grpc_rb_cannot_init_copy(VALUE copy, VALUE self) {
86
+ (void)self;
87
+ rb_raise(rb_eTypeError, "Copy initialization of %s is not supported",
88
+ rb_obj_classname(copy));
89
+ return Qnil;
90
+ }
91
+
92
+ /* id_tv_{,u}sec are accessor methods on Ruby Time instances. */
93
+ static ID id_tv_sec;
94
+ static ID id_tv_nsec;
95
+
96
+ /**
97
+ * grpc_rb_time_timeval creates a timeval from a ruby time object.
98
+ *
99
+ * This func is copied from ruby source, MRI/source/time.c, which is published
100
+ * under the same license as the ruby.h, on which the entire extensions is
101
+ * based.
102
+ */
103
+ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
104
+ gpr_timespec t;
105
+ gpr_timespec* time_const;
106
+ const char* tstr = interval ? "time interval" : "time";
107
+ const char* want = " want <secs from epoch>|<Time>|<GRPC::TimeConst.*>";
108
+
109
+ t.clock_type = GPR_CLOCK_REALTIME;
110
+ switch (TYPE(time)) {
111
+ case T_DATA:
112
+ if (CLASS_OF(time) == grpc_rb_cTimeVal) {
113
+ TypedData_Get_Struct(time, gpr_timespec, &grpc_rb_timespec_data_type,
114
+ time_const);
115
+ t = *time_const;
116
+ } else if (CLASS_OF(time) == rb_cTime) {
117
+ t.tv_sec = NUM2INT(rb_funcall(time, id_tv_sec, 0));
118
+ t.tv_nsec = NUM2INT(rb_funcall(time, id_tv_nsec, 0));
119
+ } else {
120
+ rb_raise(rb_eTypeError, "bad input: (%s)->c_timeval, got <%s>,%s", tstr,
121
+ rb_obj_classname(time), want);
122
+ }
123
+ break;
124
+
125
+ case T_FIXNUM:
126
+ t.tv_sec = FIX2LONG(time);
127
+ if (interval && t.tv_sec < 0)
128
+ rb_raise(rb_eArgError, "%s must be positive", tstr);
129
+ t.tv_nsec = 0;
130
+ break;
131
+
132
+ case T_FLOAT:
133
+ if (interval && RFLOAT_VALUE(time) < 0.0)
134
+ rb_raise(rb_eArgError, "%s must be positive", tstr);
135
+ else {
136
+ double f, d;
137
+
138
+ d = modf(RFLOAT_VALUE(time), &f);
139
+ if (d < 0) {
140
+ d += 1;
141
+ f -= 1;
142
+ }
143
+ t.tv_sec = (int64_t)f;
144
+ if (f != t.tv_sec) {
145
+ rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT_VALUE(time));
146
+ }
147
+ t.tv_nsec = (int)(d * 1e9 + 0.5);
148
+ }
149
+ break;
150
+
151
+ case T_BIGNUM:
152
+ t.tv_sec = NUM2LONG(time);
153
+ if (interval && t.tv_sec < 0)
154
+ rb_raise(rb_eArgError, "%s must be positive", tstr);
155
+ t.tv_nsec = 0;
156
+ break;
157
+
158
+ default:
159
+ rb_raise(rb_eTypeError, "bad input: (%s)->c_timeval, got <%s>,%s", tstr,
160
+ rb_obj_classname(time), want);
161
+ break;
162
+ }
163
+ return t;
164
+ }
165
+
166
+ /* id_at is the constructor method of the ruby standard Time class. */
167
+ static ID id_at;
168
+
169
+ /* id_inspect is the inspect method found on various ruby objects. */
170
+ static ID id_inspect;
171
+
172
+ /* id_to_s is the to_s method found on various ruby objects. */
173
+ static ID id_to_s;
174
+
175
+ /* Converts a wrapped time constant to a standard time. */
176
+ static VALUE grpc_rb_time_val_to_time(VALUE self) {
177
+ gpr_timespec* time_const = NULL;
178
+ gpr_timespec real_time;
179
+ TypedData_Get_Struct(self, gpr_timespec, &grpc_rb_timespec_data_type,
180
+ time_const);
181
+ real_time = gpr_convert_clock_type(*time_const, GPR_CLOCK_REALTIME);
182
+ return rb_funcall(rb_cTime, id_at, 2, INT2NUM(real_time.tv_sec),
183
+ INT2NUM(real_time.tv_nsec / 1000));
184
+ }
185
+
186
+ /* Invokes inspect on the ctime version of the time val. */
187
+ static VALUE grpc_rb_time_val_inspect(VALUE self) {
188
+ return rb_funcall(grpc_rb_time_val_to_time(self), id_inspect, 0);
189
+ }
190
+
191
+ /* Invokes to_s on the ctime version of the time val. */
192
+ static VALUE grpc_rb_time_val_to_s(VALUE self) {
193
+ return rb_funcall(grpc_rb_time_val_to_time(self), id_to_s, 0);
194
+ }
195
+
196
+ static gpr_timespec zero_realtime;
197
+ static gpr_timespec inf_future_realtime;
198
+ static gpr_timespec inf_past_realtime;
199
+
200
+ /* Adds a module with constants that map to gpr's static timeval structs. */
201
+ static void Init_grpc_time_consts() {
202
+ VALUE grpc_rb_mTimeConsts =
203
+ rb_define_module_under(grpc_rb_mGrpcCore, "TimeConsts");
204
+ grpc_rb_cTimeVal =
205
+ rb_define_class_under(grpc_rb_mGrpcCore, "TimeSpec", rb_cObject);
206
+ rb_undef_alloc_func(grpc_rb_cTimeVal);
207
+ zero_realtime = gpr_time_0(GPR_CLOCK_REALTIME);
208
+ inf_future_realtime = gpr_inf_future(GPR_CLOCK_REALTIME);
209
+ inf_past_realtime = gpr_inf_past(GPR_CLOCK_REALTIME);
210
+ rb_define_const(
211
+ grpc_rb_mTimeConsts, "ZERO",
212
+ TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
213
+ (void*)&zero_realtime));
214
+ rb_define_const(
215
+ grpc_rb_mTimeConsts, "INFINITE_FUTURE",
216
+ TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
217
+ (void*)&inf_future_realtime));
218
+ rb_define_const(
219
+ grpc_rb_mTimeConsts, "INFINITE_PAST",
220
+ TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
221
+ (void*)&inf_past_realtime));
222
+ rb_define_method(grpc_rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0);
223
+ rb_define_method(grpc_rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0);
224
+ rb_define_method(grpc_rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0);
225
+ id_at = rb_intern("at");
226
+ id_inspect = rb_intern("inspect");
227
+ id_to_s = rb_intern("to_s");
228
+ id_tv_sec = rb_intern("tv_sec");
229
+ id_tv_nsec = rb_intern("tv_nsec");
230
+ }
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
+
242
+ #if GPR_WINDOWS
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) {}
247
+ #else
248
+ static pid_t g_init_pid;
249
+ static long g_init_tid;
250
+
251
+ static bool grpc_ruby_initial_pid(void) {
252
+ GPR_ASSERT(g_init_pid != 0);
253
+ return g_init_pid == getpid();
254
+ }
255
+
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
+ }
277
+ }
278
+ #endif
279
+
280
+ /* Initialize the GRPC module structs */
281
+
282
+ /* grpc_rb_sNewServerRpc is the struct that holds new server rpc details. */
283
+ VALUE grpc_rb_sNewServerRpc = Qnil;
284
+ /* grpc_rb_sStatus is the struct that holds status details. */
285
+ VALUE grpc_rb_sStatus = Qnil;
286
+
287
+ /* Initialize the GRPC module. */
288
+ VALUE grpc_rb_mGRPC = Qnil;
289
+ VALUE grpc_rb_mGrpcCore = Qnil;
290
+
291
+ /* cached Symbols for members in Status struct */
292
+ VALUE sym_code = Qundef;
293
+ VALUE sym_details = Qundef;
294
+ VALUE sym_metadata = Qundef;
295
+
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
299
+
300
+ void grpc_ruby_fork_guard() {
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
+ }
321
+ }
322
+ }
323
+
324
+ static VALUE g_bg_thread_init_rb_mu = Qundef;
325
+ static bool g_bg_thread_init_done;
326
+
327
+ static void grpc_ruby_init_threads() {
328
+ // Avoid calling into ruby library (when creating threads here)
329
+ // in gpr_once_init. In general, it appears to be unsafe to call
330
+ // into the ruby library while holding a non-ruby mutex, because a gil yield
331
+ // could end up trying to lock onto that same mutex and deadlocking.
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) {
337
+ grpc_rb_event_queue_thread_start();
338
+ grpc_rb_channel_polling_thread_start();
339
+ g_bg_thread_init_done = true;
340
+ }
341
+ rb_mutex_unlock(g_bg_thread_init_rb_mu);
342
+ }
343
+
344
+ static int64_t g_grpc_ruby_init_count;
345
+
346
+ void grpc_ruby_init() {
347
+ gpr_once_init(&g_once_init, grpc_ruby_basic_init);
348
+ grpc_ruby_fork_guard();
349
+ grpc_init();
350
+ grpc_ruby_init_threads();
351
+ // (only gpr_log after logging has been initialized)
352
+ gpr_log(GPR_DEBUG,
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;
406
+ }
407
+
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;
423
+ }
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
458
+ void Init_grpc_c() {
459
+ if (!grpc_rb_load_core()) {
460
+ rb_raise(rb_eLoadError, "Couldn't find or load gRPC's dynamic C core");
461
+ return;
462
+ }
463
+
464
+ rb_global_variable(&g_bg_thread_init_rb_mu);
465
+ g_bg_thread_init_rb_mu = rb_mutex_new();
466
+
467
+ grpc_rb_mGRPC = rb_define_module("GRPC");
468
+ grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core");
469
+ grpc_rb_sNewServerRpc = rb_struct_define(
470
+ "NewServerRpc", "method", "host", "deadline", "metadata", "call", NULL);
471
+ grpc_rb_sStatus = rb_const_get(rb_cStruct, rb_intern("Status"));
472
+ sym_code = ID2SYM(rb_intern("code"));
473
+ sym_details = ID2SYM(rb_intern("details"));
474
+ sym_metadata = ID2SYM(rb_intern("metadata"));
475
+ // init C-defined classes
476
+ Init_grpc_channel();
477
+ Init_grpc_call();
478
+ Init_grpc_call_credentials();
479
+ Init_grpc_channel_credentials();
480
+ Init_grpc_xds_channel_credentials();
481
+ Init_grpc_server();
482
+ Init_grpc_server_credentials();
483
+ Init_grpc_xds_server_credentials();
484
+ Init_grpc_time_consts();
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);
496
+ }