@@ -9,79 +9,193 @@ 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
+ ///
130
+ /// # Example
131
+ ///
132
+ /// ```rust
133
+ /// use core::sync::atomic::{AtomicU64, Ordering};
134
+ /// use std::fmt::Debug;
135
+ /// use svsm::locking::*;
136
+ ///
137
+ /// #[derive(Debug)]
138
+ /// struct MyData {
139
+ /// value: i32,
140
+ /// }
141
+ ///
142
+ /// // Create a new RWLock with some initial data.
143
+ /// let data = MyData { value: 42 };
144
+ /// let rwlock = RWLock::new(data);
145
+ ///
146
+ /// // Lock the RWLock for reading
147
+ /// let reader = rwlock.lock_read();
148
+ /// assert_eq!(reader.value, 42);
149
+ ///
150
+ /// // Lock the RWLock for writing
151
+ /// let mut writer = rwlock.lock_write();
152
+ /// writer.value = 100;
153
+ ///
154
+ /// // Readers can access the data simultaneously
155
+ /// let reader2 = rwlock.lock_read();
156
+ /// assert_eq!(reader2.value, 100);
157
+ /// ```
77
158
impl < T : Debug > RWLock < T > {
159
+ /// Creates a new `RWLock` instance with the provided initial data.
160
+ ///
161
+ /// # Parameters
162
+ ///
163
+ /// - `data`: The initial data to be protected by the `RWLock`.
164
+ ///
165
+ /// # Returns
166
+ ///
167
+ /// A new `RWLock` instance with the specified initial data.
168
+ ///
169
+ /// # Example
170
+ ///
171
+ /// ```rust
172
+ /// use core::sync::atomic::{AtomicU64, Ordering};
173
+ /// use std::fmt::Debug;
174
+ /// use svsm::locking::*;
175
+ ///
176
+ /// #[derive(Debug)]
177
+ /// struct MyData {
178
+ /// value: i32,
179
+ /// }
180
+ ///
181
+ /// let data = MyData { value: 42 };
182
+ /// let rwlock = RWLock::new(data);
183
+ /// ```
78
184
pub const fn new ( data : T ) -> Self {
79
185
RWLock {
80
186
rwlock : AtomicU64 :: new ( 0 ) ,
81
187
data : UnsafeCell :: new ( data) ,
82
188
}
83
189
}
84
190
191
+ /// This function is used to wait until all writers have finished their
192
+ /// operations and retrieve the current state of the RWLock.
193
+ ///
194
+ /// # Returns
195
+ ///
196
+ /// A 64-bit value representing the current state of the RWLock,
197
+ /// including the count of readers and writers.
198
+ ///
85
199
#[ inline]
86
200
fn wait_for_writers ( & self ) -> u64 {
87
201
loop {
@@ -95,6 +209,14 @@ impl<T: Debug> RWLock<T> {
95
209
}
96
210
}
97
211
212
+ /// This function is used to wait until all readers have finished their
213
+ /// operations and retrieve the current state of the RWLock.
214
+ ///
215
+ /// # Returns
216
+ ///
217
+ /// A 64-bit value representing the current state of the RWLock,
218
+ /// including the count of readers and writers.
219
+ ///
98
220
#[ inline]
99
221
fn wait_for_readers ( & self ) -> u64 {
100
222
loop {
@@ -108,6 +230,12 @@ impl<T: Debug> RWLock<T> {
108
230
}
109
231
}
110
232
233
+ /// This function allows multiple readers to access the data concurrently.
234
+ ///
235
+ /// # Returns
236
+ ///
237
+ /// A `ReadLockGuard` that provides read access to the protected data.
238
+ ///
111
239
pub fn lock_read ( & self ) -> ReadLockGuard < T > {
112
240
loop {
113
241
let val = self . wait_for_writers ( ) ;
@@ -130,6 +258,21 @@ impl<T: Debug> RWLock<T> {
130
258
}
131
259
}
132
260
261
+ /// This function ensures exclusive access for a single writer and waits
262
+ /// for all readers to finish before granting access to the writer.
263
+ ///
264
+ /// # Returns
265
+ ///
266
+ /// A `WriteLockGuard` that provides write access to the protected data.
267
+ ///
268
+ /// # Example
269
+ ///
270
+ /// ```rust
271
+ /// use svsm::locking::*;
272
+ /// let rwlock = RWLock::new(42);
273
+ /// let mut writer = rwlock.lock_write();
274
+ /// writer.value = 100;
275
+ /// ```
133
276
pub fn lock_write ( & self ) -> WriteLockGuard < T > {
134
277
// Waiting for current writer to finish
135
278
loop {
0 commit comments