ratomic 0.1.0 → 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 +16 -0
- data/Cargo.lock +381 -0
- data/Cargo.toml +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +176 -0
- data/ext/ratomic/Cargo.toml +22 -0
- data/ext/ratomic/build.rs +3 -0
- data/ext/ratomic/extconf.rb +2 -12
- data/ext/ratomic/src/counter.rs +26 -0
- data/ext/ratomic/src/fixed_size_object_pool.rs +52 -0
- data/ext/ratomic/src/hashmap.rs +70 -0
- data/ext/ratomic/src/lib.rs +401 -0
- data/ext/ratomic/src/mpmc_queue.rs +164 -0
- data/ext/ratomic/src/sem.rs +72 -0
- data/lib/ratomic/counter.rb +51 -0
- data/lib/ratomic/map.rb +56 -0
- data/lib/ratomic/pool.rb +154 -0
- data/lib/ratomic/queue.rb +17 -0
- data/lib/ratomic/undefined.rb +15 -0
- data/lib/ratomic/version.rb +1 -1
- data/lib/ratomic.rb +8 -60
- data/ratomic.gemspec +19 -13
- metadata +41 -23
- data/ext/ratomic/counter.h +0 -45
- data/ext/ratomic/fixed-size-object-pool.h +0 -76
- data/ext/ratomic/hashmap.h +0 -74
- data/ext/ratomic/mpmc-queue.h +0 -68
- data/ext/ratomic/ratomic.c +0 -16
- data/lib/ratomic/ratomic.bundle +0 -0
- data/rs/Cargo.lock +0 -196
- data/rs/Cargo.toml +0 -26
- data/rs/cbindgen.toml +0 -12
- data/rs/rust-atomics.h +0 -89
- data/rs/src/bin/mpmc_queue.rs +0 -89
- data/rs/src/counter.rs +0 -57
- data/rs/src/fixed_size_object_pool.rs +0 -120
- data/rs/src/hashmap.rs +0 -129
- data/rs/src/lib.rs +0 -23
- data/rs/src/mpmc_queue.rs +0 -231
- data/rs/src/sem.rs +0 -75
- /data/{rs → ext/ratomic}/src/gc_guard.rs +0 -0
data/rs/src/counter.rs
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
use std::sync::atomic::{AtomicU64, Ordering};
|
|
2
|
-
|
|
3
|
-
#[derive(Debug)]
|
|
4
|
-
pub struct AtomicCounter {
|
|
5
|
-
value: AtomicU64,
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
impl AtomicCounter {
|
|
9
|
-
pub fn new(n: u64) -> Self {
|
|
10
|
-
Self {
|
|
11
|
-
value: AtomicU64::new(n),
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pub fn inc(&self, amt: u64) {
|
|
16
|
-
self.value.fetch_add(amt, Ordering::Relaxed);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub fn dec(&self, amt: u64) {
|
|
20
|
-
self.value.fetch_sub(amt, Ordering::Relaxed);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
pub fn read(&self) -> u64 {
|
|
24
|
-
self.value.load(Ordering::Relaxed)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
#[unsafe(no_mangle)]
|
|
29
|
-
pub unsafe extern "C" fn atomic_counter_init(counter: *mut AtomicCounter, n: u64) {
|
|
30
|
-
unsafe { counter.write(AtomicCounter::new(n)) }
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
#[unsafe(no_mangle)]
|
|
34
|
-
pub unsafe extern "C" fn atomic_counter_increment(counter: *const AtomicCounter, amt: u64) {
|
|
35
|
-
let counter = unsafe { counter.as_ref().unwrap() };
|
|
36
|
-
counter.inc(amt);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
#[unsafe(no_mangle)]
|
|
40
|
-
pub unsafe extern "C" fn atomic_counter_decrement(counter: *const AtomicCounter, amt: u64) {
|
|
41
|
-
let counter = unsafe { counter.as_ref().unwrap() };
|
|
42
|
-
counter.dec(amt);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
#[unsafe(no_mangle)]
|
|
46
|
-
pub unsafe extern "C" fn atomic_counter_read(counter: *const AtomicCounter) -> u64 {
|
|
47
|
-
let counter = unsafe { counter.as_ref().unwrap() };
|
|
48
|
-
counter.read()
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
pub const ATOMIC_COUNTER_SIZE: usize = 8;
|
|
52
|
-
|
|
53
|
-
#[test]
|
|
54
|
-
fn test_atomic_counter() {
|
|
55
|
-
assert_eq!(ATOMIC_COUNTER_SIZE, std::mem::size_of::<AtomicCounter>());
|
|
56
|
-
assert!(crate::is_sync_and_send::<AtomicCounter>());
|
|
57
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
use crossbeam_channel::{Receiver, Sender};
|
|
2
|
-
use std::{ffi::c_ulong, time::Duration};
|
|
3
|
-
|
|
4
|
-
pub struct FixedSizeObjectPool {
|
|
5
|
-
pool: Vec<c_ulong>,
|
|
6
|
-
tx: Sender<usize>,
|
|
7
|
-
rx: Receiver<usize>,
|
|
8
|
-
timeout: Duration,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
#[repr(C)]
|
|
12
|
-
pub struct PooledItem {
|
|
13
|
-
pub idx: usize,
|
|
14
|
-
pub rbobj: c_ulong,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
impl FixedSizeObjectPool {
|
|
18
|
-
fn new() -> Self {
|
|
19
|
-
let (tx, rx) = crossbeam_channel::unbounded();
|
|
20
|
-
|
|
21
|
-
Self {
|
|
22
|
-
pool: vec![],
|
|
23
|
-
tx,
|
|
24
|
-
rx,
|
|
25
|
-
timeout: Duration::MAX,
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
fn init(
|
|
30
|
-
&mut self,
|
|
31
|
-
size: usize,
|
|
32
|
-
timeout_in_ms: u64,
|
|
33
|
-
rb_make_obj: extern "C" fn(c_ulong) -> c_ulong,
|
|
34
|
-
) {
|
|
35
|
-
self.timeout = Duration::from_millis(timeout_in_ms);
|
|
36
|
-
|
|
37
|
-
self.pool = Vec::with_capacity(size);
|
|
38
|
-
for idx in 0..size {
|
|
39
|
-
self.pool.push((rb_make_obj)(0));
|
|
40
|
-
self.tx.send(idx).unwrap();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
fn mark(&self, f: extern "C" fn(c_ulong)) {
|
|
45
|
-
for item in self.pool.iter() {
|
|
46
|
-
f(*item);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
fn checkout(&mut self) -> Option<PooledItem> {
|
|
51
|
-
let idx = self.rx.recv_timeout(self.timeout).ok()?;
|
|
52
|
-
Some(PooledItem {
|
|
53
|
-
idx,
|
|
54
|
-
rbobj: self.pool[idx],
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
fn checkin(&mut self, idx: usize) {
|
|
59
|
-
self.tx.send(idx).unwrap();
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
#[unsafe(no_mangle)]
|
|
64
|
-
pub unsafe extern "C" fn fixed_size_object_pool_alloc(pool: *mut FixedSizeObjectPool) {
|
|
65
|
-
unsafe { pool.write(FixedSizeObjectPool::new()) }
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
#[unsafe(no_mangle)]
|
|
69
|
-
pub unsafe extern "C" fn fixed_size_object_pool_init(
|
|
70
|
-
pool: *mut FixedSizeObjectPool,
|
|
71
|
-
max_size: usize,
|
|
72
|
-
timeout_in_ms: u64,
|
|
73
|
-
rb_make_obj: extern "C" fn(c_ulong) -> c_ulong,
|
|
74
|
-
) {
|
|
75
|
-
let pool = unsafe { pool.as_mut().unwrap() };
|
|
76
|
-
pool.init(max_size, timeout_in_ms, rb_make_obj);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
#[unsafe(no_mangle)]
|
|
80
|
-
pub unsafe extern "C" fn fixed_size_object_pool_drop(pool: *mut FixedSizeObjectPool) {
|
|
81
|
-
unsafe { std::ptr::drop_in_place(pool) };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
#[unsafe(no_mangle)]
|
|
85
|
-
pub unsafe extern "C" fn fixed_size_object_pool_mark(
|
|
86
|
-
pool: *const FixedSizeObjectPool,
|
|
87
|
-
f: extern "C" fn(c_ulong),
|
|
88
|
-
) {
|
|
89
|
-
let pool = unsafe { pool.as_ref().unwrap() };
|
|
90
|
-
pool.mark(f);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
#[unsafe(no_mangle)]
|
|
94
|
-
pub unsafe extern "C" fn fixed_size_object_pool_checkout(
|
|
95
|
-
pool: *mut FixedSizeObjectPool,
|
|
96
|
-
) -> PooledItem {
|
|
97
|
-
let pool = unsafe { pool.as_mut().unwrap() };
|
|
98
|
-
pool.checkout().unwrap_or(PooledItem { idx: 0, rbobj: 0 })
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
#[unsafe(no_mangle)]
|
|
102
|
-
pub unsafe extern "C" fn fixed_size_object_pool_checkin(
|
|
103
|
-
pool: *mut FixedSizeObjectPool,
|
|
104
|
-
idx: usize,
|
|
105
|
-
) {
|
|
106
|
-
let pool = unsafe { pool.as_mut().unwrap() };
|
|
107
|
-
pool.checkin(idx);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
pub const FIXED_SIZE_OBJECT_POOL_SIZE: usize = 72;
|
|
111
|
-
|
|
112
|
-
#[test]
|
|
113
|
-
fn test_concurrent_hash_map() {
|
|
114
|
-
assert_eq!(
|
|
115
|
-
FIXED_SIZE_OBJECT_POOL_SIZE,
|
|
116
|
-
std::mem::size_of::<FixedSizeObjectPool>(),
|
|
117
|
-
"size mismatch"
|
|
118
|
-
);
|
|
119
|
-
assert!(crate::is_sync_and_send::<FixedSizeObjectPool>());
|
|
120
|
-
}
|
data/rs/src/hashmap.rs
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
use std::ffi::{c_int, c_ulong};
|
|
2
|
-
|
|
3
|
-
#[derive(Debug)]
|
|
4
|
-
struct RubyHashEql(c_ulong);
|
|
5
|
-
|
|
6
|
-
impl PartialEq for RubyHashEql {
|
|
7
|
-
fn eq(&self, other: &Self) -> bool {
|
|
8
|
-
unsafe { rb_eql(self.0, other.0) != 0 }
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
impl Eq for RubyHashEql {}
|
|
12
|
-
|
|
13
|
-
impl std::hash::Hash for RubyHashEql {
|
|
14
|
-
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
15
|
-
let ruby_hash = unsafe { rb_hash(self.0) };
|
|
16
|
-
ruby_hash.hash(state);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
pub struct ConcurrentHashMap {
|
|
21
|
-
map: dashmap::DashMap<RubyHashEql, c_ulong>,
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
unsafe extern "C" {
|
|
25
|
-
fn rb_hash(obj: c_ulong) -> c_ulong;
|
|
26
|
-
fn rb_eql(lhs: c_ulong, rhs: c_ulong) -> c_int;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
impl ConcurrentHashMap {
|
|
30
|
-
fn new() -> Self {
|
|
31
|
-
Self {
|
|
32
|
-
map: dashmap::DashMap::new(),
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
fn get(&self, key: c_ulong) -> Option<c_ulong> {
|
|
37
|
-
let key = RubyHashEql(key);
|
|
38
|
-
self.map.get(&key).map(|v| *v)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
fn set(&self, key: c_ulong, value: c_ulong) {
|
|
42
|
-
let key = RubyHashEql(key);
|
|
43
|
-
self.map.insert(key, value);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
fn clear(&self) {
|
|
47
|
-
self.map.clear()
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
fn fetch_and_modify(&self, key: c_ulong, f: extern "C" fn(c_ulong) -> c_ulong) {
|
|
51
|
-
let key = RubyHashEql(key);
|
|
52
|
-
self.map.alter(&key, |_, v| f(v));
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
fn mark(&self, f: extern "C" fn(c_ulong)) {
|
|
56
|
-
for pair in self.map.iter() {
|
|
57
|
-
f(pair.key().0);
|
|
58
|
-
f(*pair.value());
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
#[unsafe(no_mangle)]
|
|
64
|
-
pub unsafe extern "C" fn concurrent_hash_map_init(hashmap: *mut ConcurrentHashMap) {
|
|
65
|
-
unsafe { hashmap.write(ConcurrentHashMap::new()) }
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
#[unsafe(no_mangle)]
|
|
69
|
-
pub unsafe extern "C" fn concurrent_hash_map_drop(hashmap: *mut ConcurrentHashMap) {
|
|
70
|
-
unsafe { std::ptr::drop_in_place(hashmap) };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
#[unsafe(no_mangle)]
|
|
74
|
-
pub unsafe extern "C" fn concurrent_hash_map_clear(hashmap: *const ConcurrentHashMap) {
|
|
75
|
-
let hashmap = unsafe { hashmap.as_ref().unwrap() };
|
|
76
|
-
hashmap.clear();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
#[unsafe(no_mangle)]
|
|
80
|
-
pub unsafe extern "C" fn concurrent_hash_map_get(
|
|
81
|
-
hashmap: *const ConcurrentHashMap,
|
|
82
|
-
key: c_ulong,
|
|
83
|
-
fallback: c_ulong,
|
|
84
|
-
) -> c_ulong {
|
|
85
|
-
let hashmap = unsafe { hashmap.as_ref().unwrap() };
|
|
86
|
-
hashmap.get(key).unwrap_or(fallback)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
#[unsafe(no_mangle)]
|
|
90
|
-
pub unsafe extern "C" fn concurrent_hash_map_set(
|
|
91
|
-
hashmap: *const ConcurrentHashMap,
|
|
92
|
-
key: c_ulong,
|
|
93
|
-
value: c_ulong,
|
|
94
|
-
) {
|
|
95
|
-
let hashmap = unsafe { hashmap.as_ref().unwrap() };
|
|
96
|
-
hashmap.set(key, value);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
#[unsafe(no_mangle)]
|
|
100
|
-
pub unsafe extern "C" fn concurrent_hash_map_mark(
|
|
101
|
-
hashmap: *const ConcurrentHashMap,
|
|
102
|
-
f: extern "C" fn(c_ulong),
|
|
103
|
-
) {
|
|
104
|
-
let hashmap = unsafe { hashmap.as_ref().unwrap() };
|
|
105
|
-
hashmap.mark(f);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
#[unsafe(no_mangle)]
|
|
109
|
-
pub unsafe extern "C" fn concurrent_hash_map_fetch_and_modify(
|
|
110
|
-
hashmap: *const ConcurrentHashMap,
|
|
111
|
-
key: c_ulong,
|
|
112
|
-
f: extern "C" fn(c_ulong) -> c_ulong,
|
|
113
|
-
) {
|
|
114
|
-
let hashmap = unsafe { hashmap.as_ref().unwrap() };
|
|
115
|
-
hashmap.fetch_and_modify(key, f);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
pub const CONCURRENT_HASH_MAP_SIZE: usize = 40;
|
|
119
|
-
|
|
120
|
-
#[test]
|
|
121
|
-
fn test_concurrent_hash_map() {
|
|
122
|
-
assert_eq!(
|
|
123
|
-
CONCURRENT_HASH_MAP_SIZE,
|
|
124
|
-
std::mem::size_of::<ConcurrentHashMap>(),
|
|
125
|
-
"size mismatch"
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
assert!(crate::is_sync_and_send::<ConcurrentHashMap>());
|
|
129
|
-
}
|
data/rs/src/lib.rs
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
#![expect(clippy::missing_safety_doc)]
|
|
2
|
-
|
|
3
|
-
mod counter;
|
|
4
|
-
pub use counter::*;
|
|
5
|
-
|
|
6
|
-
mod hashmap;
|
|
7
|
-
pub use hashmap::*;
|
|
8
|
-
|
|
9
|
-
mod fixed_size_object_pool;
|
|
10
|
-
pub use fixed_size_object_pool::*;
|
|
11
|
-
|
|
12
|
-
mod mpmc_queue;
|
|
13
|
-
pub use mpmc_queue::*;
|
|
14
|
-
|
|
15
|
-
mod gc_guard;
|
|
16
|
-
pub(crate) use gc_guard::GcGuard;
|
|
17
|
-
|
|
18
|
-
mod sem;
|
|
19
|
-
|
|
20
|
-
#[cfg(test)]
|
|
21
|
-
pub(crate) fn is_sync_and_send<T: Sync + Send>() -> bool {
|
|
22
|
-
true
|
|
23
|
-
}
|
data/rs/src/mpmc_queue.rs
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
use crate::{GcGuard, sem::Semaphore};
|
|
2
|
-
use std::{
|
|
3
|
-
cell::Cell,
|
|
4
|
-
ffi::c_ulong,
|
|
5
|
-
sync::atomic::{AtomicUsize, Ordering},
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
struct QueueElement {
|
|
9
|
-
sequence: AtomicUsize,
|
|
10
|
-
data: Cell<c_ulong>,
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
unsafe impl Send for QueueElement {}
|
|
14
|
-
unsafe impl Sync for QueueElement {}
|
|
15
|
-
|
|
16
|
-
pub struct MpmcQueue {
|
|
17
|
-
buffer: Vec<QueueElement>,
|
|
18
|
-
buffer_mask: usize,
|
|
19
|
-
enqueue_pos: AtomicUsize,
|
|
20
|
-
dequeue_pos: AtomicUsize,
|
|
21
|
-
|
|
22
|
-
gc_guard: GcGuard,
|
|
23
|
-
read_sem: Semaphore,
|
|
24
|
-
write_sem: Semaphore,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
impl MpmcQueue {
|
|
28
|
-
fn alloc() -> Self {
|
|
29
|
-
Self {
|
|
30
|
-
buffer: vec![],
|
|
31
|
-
buffer_mask: 0,
|
|
32
|
-
enqueue_pos: AtomicUsize::new(0),
|
|
33
|
-
dequeue_pos: AtomicUsize::new(0),
|
|
34
|
-
|
|
35
|
-
gc_guard: GcGuard::alloc(),
|
|
36
|
-
read_sem: Semaphore::alloc(),
|
|
37
|
-
write_sem: Semaphore::alloc(),
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
fn init(&mut self, buffer_size: usize, default: c_ulong) {
|
|
42
|
-
assert!(buffer_size >= 2);
|
|
43
|
-
assert_eq!(buffer_size & (buffer_size - 1), 0);
|
|
44
|
-
|
|
45
|
-
let mut buffer = Vec::with_capacity(buffer_size);
|
|
46
|
-
for i in 0..buffer_size {
|
|
47
|
-
buffer.push(QueueElement {
|
|
48
|
-
sequence: AtomicUsize::new(i),
|
|
49
|
-
data: Cell::new(default),
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
self.buffer_mask = buffer_size - 1;
|
|
54
|
-
self.buffer = buffer;
|
|
55
|
-
self.enqueue_pos.store(0, Ordering::Relaxed);
|
|
56
|
-
self.dequeue_pos.store(0, Ordering::Relaxed);
|
|
57
|
-
|
|
58
|
-
self.gc_guard.init();
|
|
59
|
-
self.read_sem.init(0);
|
|
60
|
-
self.write_sem.init(buffer_size as u32);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
pub fn new(buffer_size: usize, default: c_ulong) -> Self {
|
|
64
|
-
let mut q = Self::alloc();
|
|
65
|
-
q.init(buffer_size, default);
|
|
66
|
-
q
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
fn try_push(&self, data: c_ulong) -> bool {
|
|
70
|
-
let mut cell;
|
|
71
|
-
let mut pos = self.enqueue_pos.load(Ordering::Relaxed);
|
|
72
|
-
loop {
|
|
73
|
-
cell = &self.buffer[pos & self.buffer_mask];
|
|
74
|
-
let seq = cell.sequence.load(Ordering::Acquire);
|
|
75
|
-
let diff = seq as isize - pos as isize;
|
|
76
|
-
if diff == 0 {
|
|
77
|
-
if self
|
|
78
|
-
.enqueue_pos
|
|
79
|
-
.compare_exchange_weak(pos, pos + 1, Ordering::Relaxed, Ordering::Relaxed)
|
|
80
|
-
.is_ok()
|
|
81
|
-
{
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
} else if diff < 0 {
|
|
85
|
-
return false;
|
|
86
|
-
} else {
|
|
87
|
-
pos = self.enqueue_pos.load(Ordering::Relaxed);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
cell.data.set(data);
|
|
91
|
-
cell.sequence.store(pos + 1, Ordering::Release);
|
|
92
|
-
self.read_sem.post();
|
|
93
|
-
true
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
fn try_pop(&self) -> Option<c_ulong> {
|
|
97
|
-
let mut cell;
|
|
98
|
-
let mut pos = self.dequeue_pos.load(Ordering::Relaxed);
|
|
99
|
-
loop {
|
|
100
|
-
cell = &self.buffer[pos & self.buffer_mask];
|
|
101
|
-
let seq = cell.sequence.load(Ordering::Acquire);
|
|
102
|
-
let diff = seq as isize - (pos + 1) as isize;
|
|
103
|
-
if diff == 0 {
|
|
104
|
-
if self
|
|
105
|
-
.dequeue_pos
|
|
106
|
-
.compare_exchange_weak(pos, pos + 1, Ordering::Relaxed, Ordering::Relaxed)
|
|
107
|
-
.is_ok()
|
|
108
|
-
{
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
111
|
-
} else if diff < 0 {
|
|
112
|
-
return None;
|
|
113
|
-
} else {
|
|
114
|
-
pos = self.dequeue_pos.load(Ordering::Relaxed);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
let data = cell.data.get();
|
|
119
|
-
cell.sequence
|
|
120
|
-
.store(pos + self.buffer_mask + 1, Ordering::Release);
|
|
121
|
-
self.write_sem.post();
|
|
122
|
-
|
|
123
|
-
#[cfg(feature = "simulation")]
|
|
124
|
-
std::thread::sleep(std::time::Duration::from_millis(100));
|
|
125
|
-
|
|
126
|
-
Some(data)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
pub fn push(&self, data: c_ulong) {
|
|
130
|
-
loop {
|
|
131
|
-
if self.try_push(data) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
self.write_sem.wait();
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
pub fn pop(&self) -> c_ulong {
|
|
139
|
-
loop {
|
|
140
|
-
if let Some(data) = self.gc_guard.acquire_as_consumer(|| self.try_pop()) {
|
|
141
|
-
return data;
|
|
142
|
-
}
|
|
143
|
-
self.read_sem.wait();
|
|
144
|
-
// self.read_sem
|
|
145
|
-
// .wait_for(std::time::Duration::from_millis(100));
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
pub fn acquire_as_gc<F, T>(&self, f: F) -> T
|
|
150
|
-
where
|
|
151
|
-
F: FnOnce() -> T,
|
|
152
|
-
{
|
|
153
|
-
self.gc_guard.acquire_as_gc(f)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
fn foreach<F>(&self, f: F)
|
|
157
|
-
where
|
|
158
|
-
F: Fn(c_ulong),
|
|
159
|
-
{
|
|
160
|
-
for item in self.buffer.iter() {
|
|
161
|
-
let value = item.data.get();
|
|
162
|
-
f(value);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
fn mark(&self, mark: extern "C" fn(c_ulong)) {
|
|
167
|
-
self.acquire_as_gc(|| {
|
|
168
|
-
self.foreach(|item| {
|
|
169
|
-
mark(item);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
#[unsafe(no_mangle)]
|
|
176
|
-
pub unsafe extern "C" fn mpmc_queue_alloc(q: *mut MpmcQueue) {
|
|
177
|
-
unsafe { q.write(MpmcQueue::alloc()) }
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
#[unsafe(no_mangle)]
|
|
181
|
-
pub unsafe extern "C" fn mpmc_queue_init(q: *mut MpmcQueue, capacity: usize, default: c_ulong) {
|
|
182
|
-
let q = unsafe { q.as_mut().unwrap() };
|
|
183
|
-
q.init(capacity, default);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
#[unsafe(no_mangle)]
|
|
187
|
-
pub unsafe extern "C" fn mpmc_queue_drop(q: *mut MpmcQueue) {
|
|
188
|
-
unsafe { std::ptr::drop_in_place(q) };
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
#[unsafe(no_mangle)]
|
|
192
|
-
pub unsafe extern "C" fn mpmc_queue_mark(q: *const MpmcQueue, f: extern "C" fn(c_ulong)) {
|
|
193
|
-
let q = unsafe { q.as_ref().unwrap() };
|
|
194
|
-
q.mark(f);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
#[repr(C)]
|
|
198
|
-
pub struct MpmcQueuePushPayload {
|
|
199
|
-
queue: *mut MpmcQueue,
|
|
200
|
-
item: c_ulong,
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
#[unsafe(no_mangle)]
|
|
204
|
-
pub unsafe extern "C" fn mpmc_queue_push(
|
|
205
|
-
push_paylod: *mut std::ffi::c_void,
|
|
206
|
-
) -> *mut std::ffi::c_void {
|
|
207
|
-
let push_payload = unsafe { push_paylod.cast::<MpmcQueuePushPayload>().as_ref().unwrap() };
|
|
208
|
-
let q = unsafe { push_payload.queue.as_ref().unwrap() };
|
|
209
|
-
q.push(push_payload.item);
|
|
210
|
-
return std::ptr::null_mut();
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
#[unsafe(no_mangle)]
|
|
214
|
-
pub unsafe extern "C" fn mpmc_queue_pop(q: *mut std::ffi::c_void) -> *mut std::ffi::c_void {
|
|
215
|
-
let q = unsafe { q.cast::<MpmcQueue>().as_ref().unwrap() };
|
|
216
|
-
let item = q.pop();
|
|
217
|
-
unsafe { std::mem::transmute(item) }
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
pub const MPMC_QUEUE_OBJECT_SIZE: usize = 80;
|
|
221
|
-
|
|
222
|
-
#[test]
|
|
223
|
-
fn test_mpmc_queue_size() {
|
|
224
|
-
assert_eq!(
|
|
225
|
-
MPMC_QUEUE_OBJECT_SIZE,
|
|
226
|
-
std::mem::size_of::<MpmcQueue>(),
|
|
227
|
-
"size mismatch"
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
assert!(crate::is_sync_and_send::<MpmcQueue>());
|
|
231
|
-
}
|
data/rs/src/sem.rs
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
use std::time::Duration;
|
|
2
|
-
|
|
3
|
-
use libc::{
|
|
4
|
-
CLOCK_REALTIME, clock_gettime, sem_destroy, sem_init, sem_post, sem_t, sem_wait,
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
pub(crate) struct Semaphore {
|
|
8
|
-
inner: *mut sem_t,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
impl Semaphore {
|
|
12
|
-
pub(crate) fn alloc() -> Self {
|
|
13
|
-
unsafe { std::mem::zeroed() }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
pub(crate) fn init(&mut self, initial: u32) {
|
|
17
|
-
let ptr = Box::into_raw(Box::new(unsafe { std::mem::zeroed() }));
|
|
18
|
-
|
|
19
|
-
let res = unsafe { sem_init(ptr, 0, initial) };
|
|
20
|
-
if res != 0 {
|
|
21
|
-
panic!(
|
|
22
|
-
"failed to create semaphore: {:?}",
|
|
23
|
-
std::io::Error::last_os_error()
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
self.inner = ptr;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
pub(crate) fn post(&self) {
|
|
31
|
-
let res = unsafe { sem_post(self.inner) };
|
|
32
|
-
if res != 0 {
|
|
33
|
-
panic!(
|
|
34
|
-
"failed to post to semaphore: {:?}",
|
|
35
|
-
std::io::Error::last_os_error()
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
pub(crate) fn wait(&self) {
|
|
41
|
-
let res = unsafe { sem_wait(self.inner) };
|
|
42
|
-
if res != 0 {
|
|
43
|
-
panic!(
|
|
44
|
-
"failed to wait for semaphore: {:?}",
|
|
45
|
-
std::io::Error::last_os_error()
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// pub(crate) fn wait_for(&self, duration: Duration) -> bool {
|
|
51
|
-
// let mut abstime = unsafe { std::mem::zeroed() };
|
|
52
|
-
// let res = unsafe { clock_gettime(CLOCK_REALTIME, &mut abstime) };
|
|
53
|
-
// if res != 0 {
|
|
54
|
-
// panic!(
|
|
55
|
-
// "failed to call clock_gettime: {:?}",
|
|
56
|
-
// std::io::Error::last_os_error()
|
|
57
|
-
// );
|
|
58
|
-
// }
|
|
59
|
-
// abstime.tv_nsec += duration.as_nanos() as i64;
|
|
60
|
-
// let res = unsafe { sem_timedwait(self.inner, &abstime) };
|
|
61
|
-
// res != -1
|
|
62
|
-
// }
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
impl Drop for Semaphore {
|
|
66
|
-
fn drop(&mut self) {
|
|
67
|
-
unsafe {
|
|
68
|
-
sem_destroy(self.inner);
|
|
69
|
-
drop(Box::from_raw(self.inner));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
unsafe impl Send for Semaphore {}
|
|
75
|
-
unsafe impl Sync for Semaphore {}
|
|
File without changes
|