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
#![deny(
warnings,
clippy::all,
clippy::correctness,
clippy::style,
clippy::complexity,
clippy::perf,
clippy::pedantic,
clippy::nursery,
clippy::cargo
)]
use crossbeam_epoch::{Atomic, Owned};
use std::ops::Deref;
use std::{marker::PhantomData, sync::atomic::Ordering, thread};
pub struct Inner<T> {
flag_ptr: usize,
data_ptr: usize,
_type: PhantomData<T>,
}
const fn drop_inner(flag: usize) -> usize {
flag & 0b01
}
const fn drop_outer(flag: usize) -> usize {
flag & 0b10
}
const fn is_outer_live(flag: usize) -> bool {
flag & 0b01 > 0
}
impl<T> Inner<T> {
#[must_use]
pub fn get(&self) -> Option<&T> {
let guard = crossbeam_epoch::pin();
let flag_ptr = unsafe { &*(self.flag_ptr as *const Atomic<usize>) };
let flag = flag_ptr.load(Ordering::Acquire, &guard);
let old = unsafe { *flag.deref() };
if is_outer_live(old) {
Some(unsafe { &*(self.data_ptr as *const T) })
} else {
None
}
}
}
impl<T> Drop for Inner<T> {
fn drop(&mut self) {
let guard = crossbeam_epoch::pin();
let flag_ptr = unsafe { &*(self.flag_ptr as *const Atomic<usize>) };
loop {
let flag = flag_ptr.load(Ordering::Acquire, &guard);
let old = unsafe { *flag.deref() };
let n = drop_inner(old);
if let Ok(t) = flag_ptr.compare_and_set(flag, Owned::new(n), Ordering::Release, &guard)
{
if n == 0 {
unsafe {
guard.defer_destroy(t);
std::ptr::drop_in_place(self.data_ptr as *mut T);
}
}
break;
}
}
}
}
pub struct Outer<T> {
flag_ptr: usize,
data_ptr: usize,
_type: PhantomData<T>,
}
impl<T> Deref for Outer<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*(self.data_ptr as *const T) }
}
}
impl<T> Drop for Outer<T> {
fn drop(&mut self) {
let guard = crossbeam_epoch::pin();
let flag_ptr = unsafe { &*(self.flag_ptr as *const Atomic<usize>) };
loop {
let flag = flag_ptr.load(Ordering::Acquire, &guard);
let old = unsafe { *flag.deref() };
let n = drop_outer(old);
if let Ok(t) = flag_ptr.compare_and_set(flag, Owned::new(n), Ordering::Release, &guard)
{
if n == 0 {
unsafe {
guard.defer_destroy(t);
std::ptr::drop_in_place(self.data_ptr as *mut T);
}
}
break;
}
}
}
}
pub fn spawn<T, F>(data: T, f: F) -> Outer<T>
where
T: Send + 'static,
F: FnOnce(Inner<T>) + Send + 'static,
{
let flag_ptr = Box::into_raw(Box::new(Atomic::new(0b11))) as usize;
let data_ptr = Box::into_raw(Box::new(data)) as usize;
let inner = Inner {
flag_ptr,
data_ptr,
_type: PhantomData,
};
thread::spawn(move || f(inner));
Outer {
flag_ptr,
data_ptr,
_type: PhantomData,
}
}