@@ -9,79 +9,163 @@ use core::fmt::Debug;
9
9
use core:: ops:: { Deref , DerefMut } ;
10
10
use core:: sync:: atomic:: { AtomicU64 , Ordering } ;
11
11
12
+ /// A guard that provides read access to the data protected by [`RWLock`]
12
13
#[ derive( Debug ) ]
13
14
#[ must_use = "if unused the RWLock will immediately unlock" ]
14
15
pub struct ReadLockGuard < ' a , T : Debug > {
16
+ /// Reference to the associated `AtomicU64` in the [`RWLock`]
15
17
rwlock : & ' a AtomicU64 ,
18
+ /// Reference to the protected data
16
19
data : & ' a T ,
17
20
}
18
21
22
+ /// Implements the behavior of the [`ReadLockGuard`] when it is dropped
19
23
impl < ' a , T : Debug > Drop for ReadLockGuard < ' a , T > {
24
+ /// Release the read lock
20
25
fn drop ( & mut self ) {
21
26
self . rwlock . fetch_sub ( 1 , Ordering :: Release ) ;
22
27
}
23
28
}
24
29
30
+ /// Implements the behavior of dereferencing the [`ReadLockGuard`] to
31
+ /// access the protected data.
25
32
impl < ' a , T : Debug > Deref for ReadLockGuard < ' a , T > {
26
33
type Target = T ;
34
+ /// Allow reading the protected data through deref
27
35
fn deref ( & self ) -> & T {
28
36
self . data
29
37
}
30
38
}
31
39
40
+ /// A guard that provides exclusive write access to the data protected by [`RWLock`]
32
41
#[ derive( Debug ) ]
33
42
#[ must_use = "if unused the RWLock will immediately unlock" ]
34
43
pub struct WriteLockGuard < ' a , T : Debug > {
44
+ /// Reference to the associated `AtomicU64` in the [`RWLock`]
35
45
rwlock : & ' a AtomicU64 ,
46
+ /// Reference to the protected data (mutable)
36
47
data : & ' a mut T ,
37
48
}
38
49
50
+ /// Implements the behavior of the [`WriteLockGuard`] when it is dropped
39
51
impl < ' a , T : Debug > Drop for WriteLockGuard < ' a , T > {
40
52
fn drop ( & mut self ) {
41
53
// There are no readers - safe to just set lock to 0
42
54
self . rwlock . store ( 0 , Ordering :: Release ) ;
43
55
}
44
56
}
45
57
58
+ /// Implements the behavior of dereferencing the [`WriteLockGuard`] to
59
+ /// access the protected data.
46
60
impl < ' a , T : Debug > Deref for WriteLockGuard < ' a , T > {
47
61
type Target = T ;
48
62
fn deref ( & self ) -> & T {
49
63
self . data
50
64
}
51
65
}
52
66
67
+ /// Implements the behavior of dereferencing the [`WriteLockGuard`] to
68
+ /// access the protected data in a mutable way.
53
69
impl < ' a , T : Debug > DerefMut for WriteLockGuard < ' a , T > {
54
70
fn deref_mut ( & mut self ) -> & mut T {
55
71
self . data
56
72
}
57
73
}
58
74
75
+ /// A simple Read-Write Lock (RWLock) that allows multiple readers or
76
+ /// one exclusive writer.
59
77
#[ derive( Debug ) ]
60
78
pub struct RWLock < T : Debug > {
79
+ /// An atomic 64-bit integer used for synchronization
61
80
rwlock : AtomicU64 ,
81
+ /// An UnsafeCell for interior mutability
62
82
data : UnsafeCell < T > ,
63
83
}
64
84
85
+ /// Implements the trait `Sync` for the [`RWLock`], allowing safe
86
+ /// concurrent access across threads.
65
87
unsafe impl < T : Debug > Sync for RWLock < T > { }
66
88
89
+ /// Splits a 64-bit value into two parts: readers (low 32 bits) and
90
+ /// writers (high 32 bits).
91
+ ///
92
+ /// # Parameters
93
+ ///
94
+ /// - `val`: A 64-bit unsigned integer value to be split.
95
+ ///
96
+ /// # Returns
97
+ ///
98
+ /// A tuple containing two 32-bit unsigned integer values. The first
99
+ /// element of the tuple is the lower 32 bits of input value, and the
100
+ /// second is the upper 32 bits.
101
+ ///
67
102
#[ inline]
68
103
fn split_val ( val : u64 ) -> ( u64 , u64 ) {
69
104
( val & 0xffff_ffffu64 , val >> 32 )
70
105
}
71
106
107
+ /// Composes a 64-bit value by combining the number of readers (low 32
108
+ /// bits) and writers (high 32 bits). This function is used to create a
109
+ /// 64-bit synchronization value that represents the current state of the
110
+ /// RWLock, including the count of readers and writers.
111
+ ///
112
+ /// # Parameters
113
+ ///
114
+ /// - `readers`: The number of readers (low 32 bits) currently holding read locks.
115
+ /// - `writers`: The number of writers (high 32 bits) currently holding write locks.
116
+ ///
117
+ /// # Returns
118
+ ///
119
+ /// A 64-bit value representing the combined state of readers and writers in the RWLock.
120
+ ///
72
121
#[ inline]
73
122
fn compose_val ( readers : u64 , writers : u64 ) -> u64 {
74
123
( readers & 0xffff_ffffu64 ) | ( writers << 32 )
75
124
}
76
125
126
+ /// A reader-writer lock that allows multiple readers or a single writer
127
+ /// to access the protected data. [`RWLock`] provides exclusive access for
128
+ /// writers and shared access for readers, for efficient synchronization.
129
+ ///
77
130
impl < T : Debug > RWLock < T > {
131
+ /// Creates a new [`RWLock`] instance with the provided initial data.
132
+ ///
133
+ /// # Parameters
134
+ ///
135
+ /// - `data`: The initial data to be protected by the [`RWLock`].
136
+ ///
137
+ /// # Returns
138
+ ///
139
+ /// A new [`RWLock`] instance with the specified initial data.
140
+ ///
141
+ /// # Example
142
+ ///
143
+ /// ```rust
144
+ /// use svsm::locking::RWLock;
145
+ ///
146
+ /// #[derive(Debug)]
147
+ /// struct MyData {
148
+ /// value: i32,
149
+ /// }
150
+ ///
151
+ /// let data = MyData { value: 42 };
152
+ /// let rwlock = RWLock::new(data);
153
+ /// ```
78
154
pub const fn new ( data : T ) -> Self {
79
155
RWLock {
80
156
rwlock : AtomicU64 :: new ( 0 ) ,
81
157
data : UnsafeCell :: new ( data) ,
82
158
}
83
159
}
84
160
161
+ /// This function is used to wait until all writers have finished their
162
+ /// operations and retrieve the current state of the [`RWLock`].
163
+ ///
164
+ /// # Returns
165
+ ///
166
+ /// A 64-bit value representing the current state of the [`RWLock`],
167
+ /// including the count of readers and writers.
168
+ ///
85
169
#[ inline]
86
170
fn wait_for_writers ( & self ) -> u64 {
87
171
loop {
@@ -95,6 +179,14 @@ impl<T: Debug> RWLock<T> {
95
179
}
96
180
}
97
181
182
+ /// This function is used to wait until all readers have finished their
183
+ /// operations and retrieve the current state of the [`RWLock`].
184
+ ///
185
+ /// # Returns
186
+ ///
187
+ /// A 64-bit value representing the current state of the [`RWLock`],
188
+ /// including the count of readers and writers.
189
+ ///
98
190
#[ inline]
99
191
fn wait_for_readers ( & self ) -> u64 {
100
192
loop {
@@ -108,6 +200,12 @@ impl<T: Debug> RWLock<T> {
108
200
}
109
201
}
110
202
203
+ /// This function allows multiple readers to access the data concurrently.
204
+ ///
205
+ /// # Returns
206
+ ///
207
+ /// A [`ReadLockGuard`] that provides read access to the protected data.
208
+ ///
111
209
pub fn lock_read ( & self ) -> ReadLockGuard < T > {
112
210
loop {
113
211
let val = self . wait_for_writers ( ) ;
@@ -130,6 +228,13 @@ impl<T: Debug> RWLock<T> {
130
228
}
131
229
}
132
230
231
+ /// This function ensures exclusive access for a single writer and waits
232
+ /// for all readers to finish before granting access to the writer.
233
+ ///
234
+ /// # Returns
235
+ ///
236
+ /// A [`WriteLockGuard`] that provides write access to the protected data.
237
+ ///
133
238
pub fn lock_write ( & self ) -> WriteLockGuard < T > {
134
239
// Waiting for current writer to finish
135
240
loop {
0 commit comments