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
use std::sync::atomic::{AtomicU32, Ordering};
/// Once is an object that will perform exactly one action.
///
/// A Once must not be copied after first use.
pub struct Once {
done: AtomicU32,
}
impl Once {
pub fn new() -> Self {
Self {
done: Default::default(),
}
}
/// Do calls the function f if and only if Do is being called for the
/// first time for this instance of Once. In other words, given
/// var once Once
/// if once.Do(f) is called multiple times, only the first call will invoke f,
/// even if f has a different value in each invocation. A new instance of
/// Once is required for each function to execute.
///
/// Do is intended for initialization that must be run exactly once. Since f
/// is niladic, it may be necessary to use a function literal to capture the
/// arguments to a function to be invoked by Do:
/// config.once.do(|| { config.init(filename) })
///
/// Because no call to Do returns until the one call to f returns, if f causes
/// Do to be called, it will deadlock.
///
/// If f panics, Do considers it to have returned; future calls of Do return
/// without calling f.
pub fn r#do<F>(&self, f: F)
where
F: FnMut(),
{
if self.done.load(Ordering::SeqCst) == 0 {
self.do_slow(f);
}
}
fn do_slow<F>(&self, mut f: F)
where
F: FnMut(),
{
if self.done.load(Ordering::SeqCst) == 0 {
self.done.store(1, Ordering::SeqCst);
f();
}
}
}
#[cfg(test)]
mod test {
use crate::std::sync::channel::Sender;
use crate::std::sync::Once;
use crate::{chan, defer};
use std::cell::UnsafeCell;
use std::panic::catch_unwind;
use std::sync::Arc;
pub struct One {
pub inner: UnsafeCell<i32>,
}
unsafe impl Send for One {}
unsafe impl Sync for One {}
impl One {
pub fn increment(&self) {
*(unsafe { &mut *self.inner.get() }) += 1;
}
pub fn value(&self) -> i32 {
unsafe { *self.inner.get() }
}
}
unsafe fn run(once: Arc<Once>, o: Arc<One>, s: Arc<Sender<bool>>) {
once.r#do(|| {
o.increment();
});
if o.value() != 1 {
panic!(format!("once failed inside run: {} is not 1", o.value()));
}
s.send(true);
}
#[test]
fn test_once() {
let one = Arc::new(One {
inner: UnsafeCell::new(0),
});
let once = Arc::new(Once::new());
let (s, r) = chan!();
let sender = Arc::new(s);
let n = 10;
for i in 0..n {
let oc = once.clone();
let s = sender.clone();
let o = one.clone();
co!(move || {
unsafe {
run(oc, o, s);
}
});
}
for i in 0..n {
r.recv();
}
if one.value() != 1 {
panic!(format!("once failed outside run: {} is not 1", one.value()));
}
}
#[test]
fn test_once_panic() {
let once = Once::new();
catch_unwind(|| {
once.r#do(|| {
panic!("failed");
});
});
once.r#do(|| {
panic!("Once.Do called twice");
});
}
}