1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use crate::rubysys::types::{c_void, Value};
// void (*)(void *ptr)
pub type RactorLocalStorageFunction = rutie_callback!(type fn(ptr: *mut c_void));
// struct rb_ractor_local_storage_type
//
// How Ruby marks and frees the pointers kept under a key made by
// `rb_ractor_local_storage_ptr_newkey`, each of which may be null.
#[repr(C)]
pub struct RbRactorLocalStorageType {
pub mark: Option<RactorLocalStorageFunction>,
pub free: Option<RactorLocalStorageFunction>,
}
unsafe impl Send for RbRactorLocalStorageType {}
unsafe impl Sync for RbRactorLocalStorageType {}
// struct rb_ractor_local_key_struct, opaque.
#[repr(C)]
pub struct RbRactorLocalKeyStruct {
_private: [u8; 0],
}
// typedef struct rb_ractor_local_key_struct *rb_ractor_local_key_t;
//
// A key is shared by every Ractor, and each Ractor keeps its own value for
// it. Keys are never freed.
pub type RbRactorLocalKey = *mut RbRactorLocalKeyStruct;
#[cfg_attr(rutie_dllimport, link(name = "rutie_ruby"))]
extern "C" {
// RUBY_EXTERN const struct rb_ractor_local_storage_type rb_ractor_local_storage_type_free;
//
// `RB_RACTOR_LOCAL_STORAGE_TYPE_FREE`: no `mark`, and `ruby_xfree` as `free`.
pub static rb_ractor_local_storage_type_free: RbRactorLocalStorageType;
// VALUE
// rb_ractor_stdin(void)
pub fn rb_ractor_stdin() -> Value;
// VALUE
// rb_ractor_stdout(void)
pub fn rb_ractor_stdout() -> Value;
// VALUE
// rb_ractor_stderr(void)
pub fn rb_ractor_stderr() -> Value;
// void
// rb_ractor_stdin_set(VALUE io)
//
// Sets the current Ractor's `$stdin` without checking `io`.
pub fn rb_ractor_stdin_set(io: Value);
// void
// rb_ractor_stdout_set(VALUE io)
pub fn rb_ractor_stdout_set(io: Value);
// void
// rb_ractor_stderr_set(VALUE io)
pub fn rb_ractor_stderr_set(io: Value);
// rb_ractor_local_key_t
// rb_ractor_local_storage_value_newkey(void)
pub fn rb_ractor_local_storage_value_newkey() -> RbRactorLocalKey;
// VALUE
// rb_ractor_local_storage_value(rb_ractor_local_key_t key)
//
// The current Ractor's value for `key`, or `Qnil` when it has none.
pub fn rb_ractor_local_storage_value(key: RbRactorLocalKey) -> Value;
// bool
// rb_ractor_local_storage_value_lookup(rb_ractor_local_key_t key, VALUE *val)
//
// Stores the current Ractor's value for `key` in `*val` and returns
// `true`, or returns `false` when it has none.
pub fn rb_ractor_local_storage_value_lookup(key: RbRactorLocalKey, val: *mut Value) -> bool;
// void
// rb_ractor_local_storage_value_set(rb_ractor_local_key_t key, VALUE val)
//
// The value is marked as long as the Ractor lives.
pub fn rb_ractor_local_storage_value_set(key: RbRactorLocalKey, val: Value);
// rb_ractor_local_key_t
// rb_ractor_local_storage_ptr_newkey(const struct rb_ractor_local_storage_type *type)
//
// Ruby keeps `type`, which must live forever.
pub fn rb_ractor_local_storage_ptr_newkey(
storage_type: *const RbRactorLocalStorageType,
) -> RbRactorLocalKey;
// void *
// rb_ractor_local_storage_ptr(rb_ractor_local_key_t key)
//
// The current Ractor's pointer for `key`, or null when it has none.
pub fn rb_ractor_local_storage_ptr(key: RbRactorLocalKey) -> *mut c_void;
// void
// rb_ractor_local_storage_ptr_set(rb_ractor_local_key_t key, void *ptr)
//
// The type's `free` runs on the pointer when the Ractor is freed;
// replacing the pointer does not free the old one.
pub fn rb_ractor_local_storage_ptr_set(key: RbRactorLocalKey, ptr: *mut c_void);
// VALUE
// rb_ractor_make_shareable(VALUE obj)
//
// Deep-freezes `obj` and marks it shareable (`Ractor.make_shareable`);
// raises `Ractor::Error` for an object that cannot be shared.
pub fn rb_ractor_make_shareable(object: Value) -> Value;
// VALUE
// rb_ractor_make_shareable_copy(VALUE obj)
//
// `rb_ractor_make_shareable` on a deep copy of `obj`.
pub fn rb_ractor_make_shareable_copy(object: Value) -> Value;
// bool
// rb_ractor_shareable_p_continue(VALUE obj)
//
// The slow path of the inline `rb_ractor_shareable_p` (see
// `binding::ractor::is_shareable`), for heap objects without the
// `FL_SHAREABLE` flag.
pub fn rb_ractor_shareable_p_continue(object: Value) -> bool;
}
#[cfg(test)]
mod tests {
use super::*;
static NO_CALLBACKS: RbRactorLocalStorageType = RbRactorLocalStorageType {
mark: None,
free: None,
};
#[test]
fn test_ractor_local_storage_ptr() {
crate::on_ruby_thread(|| unsafe {
// `RB_RACTOR_LOCAL_STORAGE_TYPE_FREE`: no mark function, a free one.
assert!(rb_ractor_local_storage_type_free.mark.is_none());
assert!(rb_ractor_local_storage_type_free.free.is_some());
static mut DATA: u64 = 42;
let key = rb_ractor_local_storage_ptr_newkey(&NO_CALLBACKS);
let data = std::ptr::addr_of_mut!(DATA) as *mut c_void;
assert!(rb_ractor_local_storage_ptr(key).is_null());
rb_ractor_local_storage_ptr_set(key, data);
assert_eq!(rb_ractor_local_storage_ptr(key), data);
assert_eq!(*(rb_ractor_local_storage_ptr(key) as *const u64), 42);
});
}
}