omq-backend-rust 0.1.7 → 0.2.0
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 +4 -4
- data/CHANGELOG.md +22 -0
- data/ext/omq_backend_rust/Cargo.toml +3 -4
- data/ext/omq_backend_rust/build.rs +23 -0
- data/ext/omq_backend_rust/src/error.rs +11 -10
- data/ext/omq_backend_rust/src/lib.rs +35 -10
- data/ext/omq_backend_rust/src/options.rs +117 -104
- data/ext/omq_backend_rust/src/rb.rs +433 -0
- data/ext/omq_backend_rust/src/runtime.rs +45 -99
- data/ext/omq_backend_rust/src/socket.rs +395 -166
- data/lib/omq/rust/engine.rb +64 -24
- data/lib/omq/rust/fd_watcher.rb +184 -0
- data/lib/omq/rust/version.rb +1 -1
- metadata +4 -1
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
use std::ffi::{CStr, CString, c_char, c_long, c_void};
|
|
2
|
+
use std::panic::{AssertUnwindSafe, catch_unwind};
|
|
3
|
+
use std::ptr;
|
|
4
|
+
|
|
5
|
+
use rb_sys::{VALUE, rb_data_type_t};
|
|
6
|
+
|
|
7
|
+
pub type RbResult<T = VALUE> = Result<T, RubyErr>;
|
|
8
|
+
|
|
9
|
+
#[derive(Debug)]
|
|
10
|
+
pub enum RubyErr {
|
|
11
|
+
Exception(VALUE),
|
|
12
|
+
Error { class: VALUE, message: String },
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
impl RubyErr {
|
|
16
|
+
pub fn new(class: VALUE, message: impl Into<String>) -> Self {
|
|
17
|
+
Self::Error {
|
|
18
|
+
class,
|
|
19
|
+
message: message.into(),
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pub fn arg(message: impl Into<String>) -> Self {
|
|
24
|
+
Self::new(unsafe { rb_sys::rb_eArgError }, message)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub fn io(message: impl Into<String>) -> Self {
|
|
28
|
+
Self::new(unsafe { rb_sys::rb_eIOError }, message)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pub fn runtime(message: impl Into<String>) -> Self {
|
|
32
|
+
Self::new(unsafe { rb_sys::rb_eRuntimeError }, message)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
pub fn type_error(message: impl Into<String>) -> Self {
|
|
36
|
+
Self::new(unsafe { rb_sys::rb_eTypeError }, message)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fn current_exception() -> Self {
|
|
40
|
+
let err = unsafe { rb_sys::rb_errinfo() };
|
|
41
|
+
if err == qnil() {
|
|
42
|
+
Self::runtime("Ruby exception")
|
|
43
|
+
} else {
|
|
44
|
+
Self::Exception(err)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub fn wrap<F>(f: F) -> VALUE
|
|
50
|
+
where
|
|
51
|
+
F: FnOnce() -> RbResult<VALUE>,
|
|
52
|
+
{
|
|
53
|
+
match catch_unwind(AssertUnwindSafe(f)) {
|
|
54
|
+
Ok(Ok(value)) => value,
|
|
55
|
+
Ok(Err(err)) => raise(err),
|
|
56
|
+
Err(_) => raise(RubyErr::runtime("native Rust panic")),
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
pub fn wrap_init<F>(f: F)
|
|
61
|
+
where
|
|
62
|
+
F: FnOnce() -> RbResult<()>,
|
|
63
|
+
{
|
|
64
|
+
match catch_unwind(AssertUnwindSafe(f)) {
|
|
65
|
+
Ok(Ok(())) => {}
|
|
66
|
+
Ok(Err(err)) => raise(err),
|
|
67
|
+
Err(_) => raise(RubyErr::runtime("native Rust panic")),
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pub fn raise(err: RubyErr) -> ! {
|
|
72
|
+
match err {
|
|
73
|
+
RubyErr::Exception(exc) => unsafe { rb_sys::rb_exc_raise(exc) },
|
|
74
|
+
RubyErr::Error { class, message } => {
|
|
75
|
+
let message = message.replace('\0', "\\0");
|
|
76
|
+
let c_message =
|
|
77
|
+
CString::new(message).unwrap_or_else(|_| CString::new("Ruby error").unwrap());
|
|
78
|
+
let exc = unsafe { rb_sys::rb_exc_new_cstr(class, c_message.as_ptr()) };
|
|
79
|
+
unsafe { rb_sys::rb_exc_raise(exc) }
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
struct ProtectData<F> {
|
|
85
|
+
func: Option<F>,
|
|
86
|
+
panicked: bool,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pub fn protect_value<F>(func: F) -> RbResult<VALUE>
|
|
90
|
+
where
|
|
91
|
+
F: FnOnce() -> VALUE,
|
|
92
|
+
{
|
|
93
|
+
unsafe extern "C" fn call<F>(arg: VALUE) -> VALUE
|
|
94
|
+
where
|
|
95
|
+
F: FnOnce() -> VALUE,
|
|
96
|
+
{
|
|
97
|
+
let data = unsafe { &mut *(arg as *mut ProtectData<F>) };
|
|
98
|
+
let Some(func) = data.func.take() else {
|
|
99
|
+
data.panicked = true;
|
|
100
|
+
return qnil();
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
match catch_unwind(AssertUnwindSafe(func)) {
|
|
104
|
+
Ok(value) => value,
|
|
105
|
+
Err(_) => {
|
|
106
|
+
data.panicked = true;
|
|
107
|
+
qnil()
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
let mut data = ProtectData {
|
|
113
|
+
func: Some(func),
|
|
114
|
+
panicked: false,
|
|
115
|
+
};
|
|
116
|
+
let mut state = 0;
|
|
117
|
+
let value = unsafe {
|
|
118
|
+
rb_sys::rb_protect(
|
|
119
|
+
Some(call::<F>),
|
|
120
|
+
&mut data as *mut ProtectData<F> as VALUE,
|
|
121
|
+
&mut state,
|
|
122
|
+
)
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
if state != 0 {
|
|
126
|
+
Err(RubyErr::current_exception())
|
|
127
|
+
} else if data.panicked {
|
|
128
|
+
Err(RubyErr::runtime("native Rust panic"))
|
|
129
|
+
} else {
|
|
130
|
+
Ok(value)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
pub fn protect_unit<F>(func: F) -> RbResult<()>
|
|
135
|
+
where
|
|
136
|
+
F: FnOnce(),
|
|
137
|
+
{
|
|
138
|
+
protect_value(|| {
|
|
139
|
+
func();
|
|
140
|
+
qnil()
|
|
141
|
+
})?;
|
|
142
|
+
Ok(())
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
pub const fn qnil() -> VALUE {
|
|
146
|
+
rb_sys::ruby_special_consts::RUBY_Qnil as VALUE
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
pub const fn qtrue() -> VALUE {
|
|
150
|
+
rb_sys::ruby_special_consts::RUBY_Qtrue as VALUE
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
pub const fn qfalse() -> VALUE {
|
|
154
|
+
rb_sys::ruby_special_consts::RUBY_Qfalse as VALUE
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
pub const fn qundef() -> VALUE {
|
|
158
|
+
rb_sys::ruby_special_consts::RUBY_Qundef as VALUE
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
pub fn bool_value(value: bool) -> VALUE {
|
|
162
|
+
if value { qtrue() } else { qfalse() }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
pub fn check_hash(value: VALUE) -> RbResult<()> {
|
|
166
|
+
let is_hash = unsafe { rb_sys::rb_obj_is_kind_of(value, rb_sys::rb_cHash) };
|
|
167
|
+
if is_hash == qtrue() {
|
|
168
|
+
Ok(())
|
|
169
|
+
} else {
|
|
170
|
+
Err(RubyErr::type_error("expected Hash"))
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
pub fn check_array(value: VALUE) -> RbResult<()> {
|
|
175
|
+
let is_array = unsafe { rb_sys::rb_obj_is_kind_of(value, rb_sys::rb_cArray) };
|
|
176
|
+
if is_array == qtrue() {
|
|
177
|
+
Ok(())
|
|
178
|
+
} else {
|
|
179
|
+
Err(RubyErr::type_error("expected Array"))
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
pub fn hash_get(hash: VALUE, key: &str) -> RbResult<Option<VALUE>> {
|
|
184
|
+
check_hash(hash)?;
|
|
185
|
+
let key = new_utf8_string(key)?;
|
|
186
|
+
let value = protect_value(|| unsafe { rb_sys::rb_hash_lookup2(hash, key, qundef()) })?;
|
|
187
|
+
if value == qundef() {
|
|
188
|
+
Ok(None)
|
|
189
|
+
} else {
|
|
190
|
+
Ok(Some(value))
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
pub fn hash_new() -> RbResult<VALUE> {
|
|
195
|
+
protect_value(|| unsafe { rb_sys::rb_hash_new() })
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
pub fn hash_aset(hash: VALUE, key: VALUE, value: VALUE) -> RbResult<()> {
|
|
199
|
+
protect_value(|| unsafe { rb_sys::rb_hash_aset(hash, key, value) })?;
|
|
200
|
+
Ok(())
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
pub fn array_new() -> RbResult<VALUE> {
|
|
204
|
+
protect_value(|| unsafe { rb_sys::rb_ary_new() })
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
pub fn array_new_capa(capacity: usize) -> RbResult<VALUE> {
|
|
208
|
+
let capacity = c_long_len(capacity)?;
|
|
209
|
+
protect_value(|| unsafe { rb_sys::rb_ary_new_capa(capacity) })
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
pub fn array_len(array: VALUE) -> RbResult<usize> {
|
|
213
|
+
check_array(array)?;
|
|
214
|
+
let len = unsafe { rb_sys::RARRAY_LEN(array) };
|
|
215
|
+
if len < 0 {
|
|
216
|
+
Err(RubyErr::runtime("negative Array length"))
|
|
217
|
+
} else {
|
|
218
|
+
Ok(len as usize)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
pub fn array_entry(array: VALUE, index: usize) -> RbResult<VALUE> {
|
|
223
|
+
check_array(array)?;
|
|
224
|
+
let index = c_long_len(index)?;
|
|
225
|
+
protect_value(|| unsafe { rb_sys::rb_ary_entry(array, index) })
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
pub fn array_push(array: VALUE, value: VALUE) -> RbResult<()> {
|
|
229
|
+
protect_value(|| unsafe { rb_sys::rb_ary_push(array, value) })?;
|
|
230
|
+
Ok(())
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
pub fn symbol(name: &str) -> RbResult<VALUE> {
|
|
234
|
+
let len = c_long_len(name.len())?;
|
|
235
|
+
protect_value(|| unsafe {
|
|
236
|
+
let id = rb_sys::rb_intern2(name.as_ptr() as *const c_char, len);
|
|
237
|
+
rb_sys::rb_id2sym(id)
|
|
238
|
+
})
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
pub fn new_binary_string(bytes: &[u8]) -> RbResult<VALUE> {
|
|
242
|
+
let len = c_long_len(bytes.len())?;
|
|
243
|
+
let ptr = if bytes.is_empty() {
|
|
244
|
+
ptr::null()
|
|
245
|
+
} else {
|
|
246
|
+
bytes.as_ptr() as *const c_char
|
|
247
|
+
};
|
|
248
|
+
let value = protect_value(|| unsafe { rb_sys::rb_str_new(ptr, len) })?;
|
|
249
|
+
protect_unit(|| unsafe { rb_sys::RB_OBJ_FREEZE(value) })?;
|
|
250
|
+
Ok(value)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
pub fn new_utf8_string(text: &str) -> RbResult<VALUE> {
|
|
254
|
+
let len = c_long_len(text.len())?;
|
|
255
|
+
protect_value(|| unsafe { rb_sys::rb_utf8_str_new(text.as_ptr() as *const c_char, len) })
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
pub fn string_value(value: VALUE) -> RbResult<VALUE> {
|
|
259
|
+
protect_value(|| unsafe { rb_sys::rb_str_to_str(value) })
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
pub fn value_to_bytes(value: VALUE) -> RbResult<Vec<u8>> {
|
|
263
|
+
let string = string_value(value)?;
|
|
264
|
+
let len = unsafe { rb_sys::RSTRING_LEN(string) };
|
|
265
|
+
if len < 0 {
|
|
266
|
+
return Err(RubyErr::runtime("negative String length"));
|
|
267
|
+
}
|
|
268
|
+
if len == 0 {
|
|
269
|
+
return Ok(Vec::new());
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
let ptr = unsafe { rb_sys::RSTRING_PTR(string) };
|
|
273
|
+
if ptr.is_null() {
|
|
274
|
+
return Err(RubyErr::runtime("null String pointer"));
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
let bytes = unsafe { std::slice::from_raw_parts(ptr as *const u8, len as usize) };
|
|
278
|
+
Ok(bytes.to_vec())
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
pub fn value_to_string(value: VALUE) -> RbResult<String> {
|
|
282
|
+
let bytes = value_to_bytes(value)?;
|
|
283
|
+
String::from_utf8(bytes).map_err(|_| RubyErr::type_error("expected UTF-8 String"))
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
pub fn value_to_i64(value: VALUE) -> RbResult<i64> {
|
|
287
|
+
let mut out = 0i64;
|
|
288
|
+
protect_value(|| {
|
|
289
|
+
out = unsafe { rb_sys::rb_num2long(value) as i64 };
|
|
290
|
+
qnil()
|
|
291
|
+
})?;
|
|
292
|
+
Ok(out)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
pub fn value_to_f64(value: VALUE) -> RbResult<f64> {
|
|
296
|
+
let mut out = 0.0f64;
|
|
297
|
+
protect_value(|| {
|
|
298
|
+
out = unsafe { rb_sys::rb_num2dbl(value) };
|
|
299
|
+
qnil()
|
|
300
|
+
})?;
|
|
301
|
+
Ok(out)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
pub fn value_to_bool(value: VALUE) -> RbResult<bool> {
|
|
305
|
+
if value == qtrue() {
|
|
306
|
+
Ok(true)
|
|
307
|
+
} else if value == qfalse() {
|
|
308
|
+
Ok(false)
|
|
309
|
+
} else {
|
|
310
|
+
Err(RubyErr::type_error("expected true or false"))
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
pub fn int_value(value: i32) -> VALUE {
|
|
315
|
+
unsafe { rb_sys::rb_int2inum(value as isize) }
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
pub unsafe fn wrap_typed_data<T>(
|
|
319
|
+
class: VALUE,
|
|
320
|
+
value: Box<T>,
|
|
321
|
+
data_type: *const rb_data_type_t,
|
|
322
|
+
) -> RbResult<VALUE> {
|
|
323
|
+
let raw = Box::into_raw(value);
|
|
324
|
+
match protect_value(|| unsafe {
|
|
325
|
+
rb_sys::rb_data_typed_object_wrap(class, raw as *mut c_void, data_type)
|
|
326
|
+
}) {
|
|
327
|
+
Ok(value) => Ok(value),
|
|
328
|
+
Err(err) => {
|
|
329
|
+
unsafe { drop(Box::from_raw(raw)) };
|
|
330
|
+
Err(err)
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
pub unsafe fn typed_data_ref<T>(
|
|
336
|
+
value: VALUE,
|
|
337
|
+
data_type: *const rb_data_type_t,
|
|
338
|
+
type_name: &str,
|
|
339
|
+
) -> RbResult<&'static T> {
|
|
340
|
+
let mut ptr = std::ptr::null_mut();
|
|
341
|
+
protect_unit(|| unsafe {
|
|
342
|
+
ptr = rb_sys::rb_check_typeddata(value, data_type);
|
|
343
|
+
})
|
|
344
|
+
.map_err(|_| RubyErr::type_error(format!("expected {type_name}")))?;
|
|
345
|
+
if ptr.is_null() {
|
|
346
|
+
return Err(RubyErr::runtime(format!(
|
|
347
|
+
"{type_name} data pointer is null"
|
|
348
|
+
)));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
Ok(unsafe { &*(ptr as *const T) })
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
pub unsafe fn define_module(name: &CStr) -> RbResult<VALUE> {
|
|
355
|
+
protect_value(|| unsafe { rb_sys::rb_define_module(name.as_ptr()) })
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
pub unsafe fn define_module_under(outer: VALUE, name: &CStr) -> RbResult<VALUE> {
|
|
359
|
+
protect_value(|| unsafe { rb_sys::rb_define_module_under(outer, name.as_ptr()) })
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
pub unsafe fn define_class_under(outer: VALUE, name: &CStr, superclass: VALUE) -> RbResult<VALUE> {
|
|
363
|
+
protect_value(|| unsafe { rb_sys::rb_define_class_under(outer, name.as_ptr(), superclass) })
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
pub unsafe fn undef_alloc_func(class: VALUE) -> RbResult<()> {
|
|
367
|
+
protect_unit(|| unsafe { rb_sys::rb_undef_alloc_func(class) })
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
pub unsafe fn define_module_function_1(
|
|
371
|
+
module: VALUE,
|
|
372
|
+
name: &CStr,
|
|
373
|
+
func: unsafe extern "C" fn(VALUE, VALUE) -> VALUE,
|
|
374
|
+
) -> RbResult<()> {
|
|
375
|
+
protect_unit(|| unsafe {
|
|
376
|
+
rb_sys::rb_define_module_function(module, name.as_ptr(), Some(transmute_1(func)), 1)
|
|
377
|
+
})
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
pub unsafe fn define_singleton_method_1(
|
|
381
|
+
object: VALUE,
|
|
382
|
+
name: &CStr,
|
|
383
|
+
func: unsafe extern "C" fn(VALUE, VALUE) -> VALUE,
|
|
384
|
+
) -> RbResult<()> {
|
|
385
|
+
protect_unit(|| unsafe {
|
|
386
|
+
rb_sys::rb_define_singleton_method(object, name.as_ptr(), Some(transmute_1(func)), 1)
|
|
387
|
+
})
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
pub unsafe fn define_method_0(
|
|
391
|
+
class: VALUE,
|
|
392
|
+
name: &CStr,
|
|
393
|
+
func: unsafe extern "C" fn(VALUE) -> VALUE,
|
|
394
|
+
) -> RbResult<()> {
|
|
395
|
+
protect_unit(|| unsafe {
|
|
396
|
+
rb_sys::rb_define_method(class, name.as_ptr(), Some(transmute_0(func)), 0)
|
|
397
|
+
})
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
pub unsafe fn define_method_1(
|
|
401
|
+
class: VALUE,
|
|
402
|
+
name: &CStr,
|
|
403
|
+
func: unsafe extern "C" fn(VALUE, VALUE) -> VALUE,
|
|
404
|
+
) -> RbResult<()> {
|
|
405
|
+
protect_unit(|| unsafe {
|
|
406
|
+
rb_sys::rb_define_method(class, name.as_ptr(), Some(transmute_1(func)), 1)
|
|
407
|
+
})
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
unsafe fn transmute_0(
|
|
411
|
+
func: unsafe extern "C" fn(VALUE) -> VALUE,
|
|
412
|
+
) -> unsafe extern "C" fn() -> VALUE {
|
|
413
|
+
unsafe {
|
|
414
|
+
std::mem::transmute::<unsafe extern "C" fn(VALUE) -> VALUE, unsafe extern "C" fn() -> VALUE>(
|
|
415
|
+
func,
|
|
416
|
+
)
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
unsafe fn transmute_1(
|
|
421
|
+
func: unsafe extern "C" fn(VALUE, VALUE) -> VALUE,
|
|
422
|
+
) -> unsafe extern "C" fn() -> VALUE {
|
|
423
|
+
unsafe {
|
|
424
|
+
std::mem::transmute::<
|
|
425
|
+
unsafe extern "C" fn(VALUE, VALUE) -> VALUE,
|
|
426
|
+
unsafe extern "C" fn() -> VALUE,
|
|
427
|
+
>(func)
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
fn c_long_len(len: usize) -> RbResult<c_long> {
|
|
432
|
+
c_long::try_from(len).map_err(|_| RubyErr::arg("length too large"))
|
|
433
|
+
}
|
|
@@ -27,10 +27,10 @@ pub fn ensure_runtime(io_threads: usize) -> Handle {
|
|
|
27
27
|
}
|
|
28
28
|
let mut guard = RUNTIME.lock().unwrap();
|
|
29
29
|
let pid = std::process::id();
|
|
30
|
-
if let Some(ref rt) = *guard
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
if let Some(ref rt) = *guard
|
|
31
|
+
&& rt.pid == pid
|
|
32
|
+
{
|
|
33
|
+
return rt.handle.clone();
|
|
34
34
|
}
|
|
35
35
|
let (tx, rx) = flume::unbounded::<Job>();
|
|
36
36
|
let (handle_tx, handle_rx) = flume::bounded::<Handle>(1);
|
|
@@ -69,28 +69,18 @@ pub fn ensure_runtime(io_threads: usize) -> Handle {
|
|
|
69
69
|
|
|
70
70
|
fn submit_job(io_threads: usize) -> flume::Sender<Job> {
|
|
71
71
|
let guard = RUNTIME.lock().unwrap();
|
|
72
|
-
if let Some(ref rt) = *guard
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
if let Some(ref rt) = *guard
|
|
73
|
+
&& rt.pid == std::process::id()
|
|
74
|
+
{
|
|
75
|
+
return rt.submit.clone();
|
|
76
76
|
}
|
|
77
77
|
drop(guard);
|
|
78
78
|
ensure_runtime(io_threads);
|
|
79
79
|
RUNTIME.lock().unwrap().as_ref().unwrap().submit.clone()
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
F: Future<Output = T> + Send + 'static,
|
|
85
|
-
T: Send + 'static,
|
|
86
|
-
{
|
|
87
|
-
let handle = ensure_runtime(io_threads);
|
|
88
|
-
let (otx, orx) = flume::bounded::<T>(1);
|
|
89
|
-
handle.spawn(async move {
|
|
90
|
-
let out = fut.await;
|
|
91
|
-
let _ = otx.send(out);
|
|
92
|
-
});
|
|
93
|
-
|
|
82
|
+
#[cfg(ruby_engine = "mri")]
|
|
83
|
+
fn recv_blocking<T>(rx: flume::Receiver<T>, missing: &'static str) -> T {
|
|
94
84
|
struct RecvBox<U> {
|
|
95
85
|
rx: flume::Receiver<U>,
|
|
96
86
|
result: Option<U>,
|
|
@@ -102,10 +92,7 @@ where
|
|
|
102
92
|
std::ptr::null_mut()
|
|
103
93
|
}
|
|
104
94
|
|
|
105
|
-
let mut rd = RecvBox {
|
|
106
|
-
rx: orx,
|
|
107
|
-
result: None,
|
|
108
|
-
};
|
|
95
|
+
let mut rd = RecvBox { rx, result: None };
|
|
109
96
|
unsafe {
|
|
110
97
|
rb_sys::rb_thread_call_without_gvl(
|
|
111
98
|
Some(blocking_recv::<T>),
|
|
@@ -114,7 +101,27 @@ where
|
|
|
114
101
|
std::ptr::null_mut(),
|
|
115
102
|
);
|
|
116
103
|
}
|
|
117
|
-
rd.result.expect(
|
|
104
|
+
rd.result.expect(missing)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#[cfg(not(ruby_engine = "mri"))]
|
|
108
|
+
fn recv_blocking<T>(rx: flume::Receiver<T>, missing: &'static str) -> T {
|
|
109
|
+
rx.recv().expect(missing)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
pub fn spawn_blocking<F, T>(io_threads: usize, fut: F) -> T
|
|
113
|
+
where
|
|
114
|
+
F: Future<Output = T> + Send + 'static,
|
|
115
|
+
T: Send + 'static,
|
|
116
|
+
{
|
|
117
|
+
let handle = ensure_runtime(io_threads);
|
|
118
|
+
let (otx, orx) = flume::bounded::<T>(1);
|
|
119
|
+
handle.spawn(async move {
|
|
120
|
+
let out = fut.await;
|
|
121
|
+
let _ = otx.send(out);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
recv_blocking(orx, "omq-backend-rust: runtime dropped result")
|
|
118
125
|
}
|
|
119
126
|
|
|
120
127
|
pub struct Materialized {
|
|
@@ -171,10 +178,10 @@ fn convert_monitor_event(event: &omq_tokio::MonitorEvent) -> MonitorEventData {
|
|
|
171
178
|
},
|
|
172
179
|
HandshakeSucceeded { endpoint, peer } => {
|
|
173
180
|
let mut detail = vec![("connection_id", peer.connection_id.to_string())];
|
|
174
|
-
if let Some(ref ident) = peer.peer_identity
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
181
|
+
if let Some(ref ident) = peer.peer_identity
|
|
182
|
+
&& !ident.is_empty()
|
|
183
|
+
{
|
|
184
|
+
detail.push(("identity", format!("{:?}", ident)));
|
|
178
185
|
}
|
|
179
186
|
MonitorEventData {
|
|
180
187
|
event_type: "handshake_succeeded",
|
|
@@ -365,17 +372,12 @@ pub fn materialize(
|
|
|
365
372
|
all_peers_gone_notify.force_wake();
|
|
366
373
|
}
|
|
367
374
|
}
|
|
368
|
-
omq_tokio::MonitorEvent::SubscribeReceived { .. }
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
omq_tokio::MonitorEvent::JoinReceived { .. } => {
|
|
375
|
-
if !subscriber_joined_fired {
|
|
376
|
-
subscriber_joined_fired = true;
|
|
377
|
-
subscriber_joined_notify.force_wake();
|
|
378
|
-
}
|
|
375
|
+
omq_tokio::MonitorEvent::SubscribeReceived { .. }
|
|
376
|
+
| omq_tokio::MonitorEvent::JoinReceived { .. }
|
|
377
|
+
if !subscriber_joined_fired =>
|
|
378
|
+
{
|
|
379
|
+
subscriber_joined_fired = true;
|
|
380
|
+
subscriber_joined_notify.force_wake();
|
|
379
381
|
}
|
|
380
382
|
_ => {}
|
|
381
383
|
}
|
|
@@ -395,40 +397,7 @@ pub fn materialize(
|
|
|
395
397
|
});
|
|
396
398
|
tx.send(job).expect("omq-backend-rust: tokio runtime gone");
|
|
397
399
|
|
|
398
|
-
|
|
399
|
-
rx: flume::Receiver<(
|
|
400
|
-
Arc<InnerSocket>,
|
|
401
|
-
JoinHandle<()>,
|
|
402
|
-
JoinHandle<()>,
|
|
403
|
-
JoinHandle<()>,
|
|
404
|
-
)>,
|
|
405
|
-
result: Option<(
|
|
406
|
-
Arc<InnerSocket>,
|
|
407
|
-
JoinHandle<()>,
|
|
408
|
-
JoinHandle<()>,
|
|
409
|
-
JoinHandle<()>,
|
|
410
|
-
)>,
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
extern "C" fn blocking_recv(data: *mut libc::c_void) -> *mut libc::c_void {
|
|
414
|
-
let rd = unsafe { &mut *(data as *mut RecvBox) };
|
|
415
|
-
rd.result = rd.rx.recv().ok();
|
|
416
|
-
std::ptr::null_mut()
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
let mut rd = RecvBox {
|
|
420
|
-
rx: orx,
|
|
421
|
-
result: None,
|
|
422
|
-
};
|
|
423
|
-
unsafe {
|
|
424
|
-
rb_sys::rb_thread_call_without_gvl(
|
|
425
|
-
Some(blocking_recv),
|
|
426
|
-
&mut rd as *mut RecvBox as *mut libc::c_void,
|
|
427
|
-
None,
|
|
428
|
-
std::ptr::null_mut(),
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
rd.result.expect("omq-backend-rust: materialize failed")
|
|
400
|
+
recv_blocking(orx, "omq-backend-rust: materialize failed")
|
|
432
401
|
}
|
|
433
402
|
|
|
434
403
|
pub fn destroy_socket(
|
|
@@ -442,12 +411,7 @@ pub fn destroy_socket(
|
|
|
442
411
|
) {
|
|
443
412
|
recv_pump.abort();
|
|
444
413
|
monitor_pump.abort();
|
|
445
|
-
let
|
|
446
|
-
else {
|
|
447
|
-
send_pump.abort();
|
|
448
|
-
drop(send_prod);
|
|
449
|
-
return;
|
|
450
|
-
};
|
|
414
|
+
let handle = ensure_runtime(io_threads);
|
|
451
415
|
let close_timeout = linger
|
|
452
416
|
.unwrap_or(Duration::from_secs(30))
|
|
453
417
|
.max(Duration::from_millis(10));
|
|
@@ -471,23 +435,5 @@ pub fn destroy_socket(
|
|
|
471
435
|
let _ = otx.send(());
|
|
472
436
|
});
|
|
473
437
|
|
|
474
|
-
|
|
475
|
-
rx: flume::Receiver<()>,
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
extern "C" fn blocking_recv(data: *mut libc::c_void) -> *mut libc::c_void {
|
|
479
|
-
let rd = unsafe { &mut *(data as *mut RecvBox) };
|
|
480
|
-
let _ = rd.rx.recv();
|
|
481
|
-
std::ptr::null_mut()
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
let mut rd = RecvBox { rx: orx };
|
|
485
|
-
unsafe {
|
|
486
|
-
rb_sys::rb_thread_call_without_gvl(
|
|
487
|
-
Some(blocking_recv),
|
|
488
|
-
&mut rd as *mut RecvBox as *mut libc::c_void,
|
|
489
|
-
None,
|
|
490
|
-
std::ptr::null_mut(),
|
|
491
|
-
);
|
|
492
|
-
}
|
|
438
|
+
recv_blocking(orx, "omq-backend-rust: close failed")
|
|
493
439
|
}
|