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
|
//! # Synchronization module
//!
//! Provides synchronization objects for thread-safe memory sharing.
use core::cell::UnsafeCell;
use core::marker::{Send, Sized, Sync};
use core::ops::FnOnce;
/// # Synchronization interfaces
///
/// Provides Synchronization traits.
pub mod interface {
use core::ops::FnOnce;
/// # Mutex Trait
///
/// Basic Locking primitive to allow single-process access to data
pub trait Mutex {
/// # The data
///
/// Each mutex protects some internal data from modification across
/// processes when it is in use. This is important if the process
/// is preempted while the function is using it.
type Data;
/// # Locking mechanism
///
/// Locks the mutex to access the data in a closure.
/// The data can be read and modified in this closure without worry
/// of poisoning the data across processes.
fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R;
}
/// # Initializable
///
/// Initializable type
pub trait Initializable {
/// # Initialize structure
fn init(&mut self);
}
}
/// # Basic Lock Structure
pub struct NullLock<T>
where
T: ?Sized,
{
/// The internal data to safely share
data: UnsafeCell<T>,
}
/// # Allow thread sharing
unsafe impl<T> Send for NullLock<T> where T: ?Sized + Send {}
/// # Allow thread sharing
unsafe impl<T> Sync for NullLock<T> where T: ?Sized + Send {}
impl<T> NullLock<T> {
/// # Create a new instance of the lock
pub const fn new(data: T) -> Self {
Self {
data: UnsafeCell::new(data),
}
}
}
impl<T: interface::Initializable> NullLock<T> {
/// # Initialize NullLock
pub fn init(&self) {
use interface::Mutex;
self.lock(|initializable| {
initializable.init();
});
}
}
impl<T> interface::Mutex for NullLock<T> {
/// # Underlying data of the lock
type Data = T;
/// # Locking mechanism
///
/// Locks the Mutex, and passes a mutable reference
/// to the encapsulated data to a closure.
fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut T) -> R) -> R {
let data = unsafe { &mut *self.data.get() };
f(data)
}
}
use core::sync::atomic::{AtomicBool, Ordering};
/// # Spinlock
pub struct SpinLock<T>
where
T: Sized,
{
data: UnsafeCell<T>,
lock: AtomicBool,
}
unsafe impl<T> Send for SpinLock<T> where T: Sized + Send {}
unsafe impl<T> Sync for SpinLock<T> where T: Sized + Send {}
impl<T> SpinLock<T> {
/// # New lock
pub const fn new(data: T) -> Self {
Self {
data: UnsafeCell::new(data),
lock: AtomicBool::new(false),
}
}
}
impl<T: interface::Initializable> SpinLock<T> {
/// # Init
pub fn init(&self) {
use interface::Mutex;
self.lock(|init| {
init.init();
});
}
}
impl<T> interface::Mutex for SpinLock<T> {
/// # Data type
type Data = T;
/// # Lock
fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut T) -> R) -> R {
while let false = self.lock.swap(true, Ordering::SeqCst) {}
let data = unsafe { &mut *self.data.get() };
let res = f(data);
// Release the lock after finished with the underlying data
self.lock.store(false, Ordering::SeqCst);
res
}
}
|