1pub use crate::ipc_capable::{Handle, IpcCapable};
51
52use core::marker::PhantomData;
53use core::{
54 fmt::Debug,
55 ops::{Deref, DerefMut},
56};
57
58use alloc::format;
59
60use iceoryx2_bb_concurrency::cell::UnsafeCell;
61use iceoryx2_bb_elementary::{enum_gen, scope_guard::ScopeGuardBuilder};
62use iceoryx2_log::{fail, fatal_panic, warn};
63use iceoryx2_pal_posix::posix::errno::Errno;
64use iceoryx2_pal_posix::posix::MemZeroedStruct;
65use iceoryx2_pal_posix::*;
66
67use crate::ipc_capable::internal::{Capability, HandleStorage, IpcConstructible};
68
69#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
70pub enum ReadWriteMutexCreationError {
71 InsufficientMemory,
72 InsufficientResources,
73 InsufficientPermissions,
74 NoInterProcessSupport,
75 NoMutexKindSupport,
76 UnknownError(i32),
77}
78
79#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
80pub enum ReadWriteMutexReadLockError {
81 MaximumAmountOfReadLocksAcquired,
82 DeadlockConditionDetected,
83 UnknownError(i32),
84}
85
86#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
87pub enum ReadWriteMutexUnlockError {
88 OwnedByDifferentEntity,
89 UnknownError(i32),
90}
91
92#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
93pub enum ReadWriteMutexWriteLockError {
94 DeadlockConditionDetected,
95 UnknownError(i32),
96}
97
98#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
99pub enum ReadWriteMutexOpenIpcHandleError {
100 IsNotInterProcessCapable,
101 Uninitialized,
102}
103
104enum_gen! {
105 ReadWriteMutexError
110 generalization:
111 FailedToLock <= ReadWriteMutexWriteLockError; ReadWriteMutexReadLockError,
112 FailedToCreate <= ReadWriteMutexCreationError
113}
114
115#[derive(Debug)]
117pub struct ReadWriteMutexBuilder {
118 is_interprocess_capable: bool,
119}
120
121impl Default for ReadWriteMutexBuilder {
122 fn default() -> Self {
123 ReadWriteMutexBuilder {
124 is_interprocess_capable: true,
125 }
126 }
127}
128
129impl ReadWriteMutexBuilder {
130 pub fn new() -> Self {
131 Self::default()
132 }
133
134 pub fn is_interprocess_capable(mut self, value: bool) -> Self {
136 self.is_interprocess_capable = value;
137 self
138 }
139
140 fn initialize_rw_mutex(
141 &self,
142 mtx: *mut posix::pthread_rwlock_t,
143 ) -> Result<Capability, ReadWriteMutexCreationError> {
144 let msg = "Failed to create mutex";
145 let origin = format!("{self:?}");
146
147 let mut attributes = ScopeGuardBuilder::new(posix::pthread_rwlockattr_t::new_zeroed()).on_init(|attr| {
148 handle_errno!(ReadWriteMutexCreationError, from self,
149 errno_source unsafe { posix::pthread_rwlockattr_init( attr).into() },
150 success Errno::ESUCCES => (),
151 Errno::ENOMEM => (InsufficientMemory, "{} due to insufficient memory while creating rwlock attributes.", msg),
152 v => (UnknownError(v as i32), "{} since an unknown error occurred while creating rwlock attributes.", msg)
153 );
154 }).on_drop(|attr| {
155 match unsafe {posix::pthread_rwlockattr_destroy(attr) } {
156 0 => (),
157 v => {
158 fatal_panic!(from origin, "This should never happen! Failed to release rwlock attributes ({}).", v);
159 }
160 }
161 }).create()?;
162
163 match unsafe { posix::pthread_rwlockattr_setpshared(attributes.get_mut(), 0) } {
164 0 => (),
165 v => {
166 fail!(from origin, with ReadWriteMutexCreationError::NoInterProcessSupport,
167 "{} due to an unknown error while setting interprocess capabilities ({}).", msg,v );
168 }
169 }
170
171 match unsafe { posix::pthread_rwlock_init(mtx, attributes.get()).into() } {
172 Errno::ESUCCES => (),
173 Errno::EAGAIN => {
174 fail!(from origin, with ReadWriteMutexCreationError::InsufficientResources, "{} due to insufficient resources.", msg);
175 }
176 Errno::ENOMEM => {
177 fail!(from origin, with ReadWriteMutexCreationError::InsufficientResources, "{} due to insufficient memory.", msg);
178 }
179 Errno::EPERM => {
180 fail!(from origin, with ReadWriteMutexCreationError::InsufficientPermissions, "{} due to insufficient permissions.", msg);
181 }
182 v => {
183 fail!(from origin, with ReadWriteMutexCreationError::UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v);
184 }
185 };
186
187 match self.is_interprocess_capable {
188 true => Ok(Capability::InterProcess),
189 false => Ok(Capability::ProcessLocal),
190 }
191 }
192
193 pub fn create<T: Debug>(
195 self,
196 t: T,
197 handle: &ReadWriteMutexHandle<T>,
198 ) -> Result<ReadWriteMutex<'_, '_, T>, ReadWriteMutexCreationError> {
199 unsafe {
200 handle
201 .handle
202 .initialize(|mtx| self.initialize_rw_mutex(mtx))?
203 };
204
205 unsafe { *handle.value.get() = Some(t) };
206
207 Ok(ReadWriteMutex::new(handle))
208 }
209}
210
211#[derive(Debug)]
215pub struct MutexReadGuard<'handle, T: Debug> {
216 handle: &'handle ReadWriteMutexHandle<T>,
217}
218
219unsafe impl<T: Send + Debug> Send for MutexReadGuard<'_, T> {}
220unsafe impl<T: Send + Sync + Debug> Sync for MutexReadGuard<'_, T> {}
221
222impl<T: Debug> Deref for MutexReadGuard<'_, T> {
223 type Target = T;
224
225 fn deref(&self) -> &Self::Target {
226 unsafe { (*self.handle.value.get()).as_ref().unwrap() }
227 }
228}
229
230impl<T: Debug> Drop for MutexReadGuard<'_, T> {
231 fn drop(&mut self) {
232 if ReadWriteMutex::release(self.handle).is_err() {
233 fatal_panic!(from self, "This should never happen! Failed to release read lock.");
234 }
235 }
236}
237
238#[derive(Debug)]
242pub struct MutexWriteGuard<'handle, T: Debug> {
243 handle: &'handle ReadWriteMutexHandle<T>,
244}
245
246unsafe impl<T: Send + Debug> Send for MutexWriteGuard<'_, T> {}
247unsafe impl<T: Send + Sync + Debug> Sync for MutexWriteGuard<'_, T> {}
248
249impl<T: Debug> Deref for MutexWriteGuard<'_, T> {
250 type Target = T;
251
252 fn deref(&self) -> &Self::Target {
253 unsafe { (*self.handle.value.get()).as_ref().unwrap() }
254 }
255}
256
257impl<T: Debug> DerefMut for MutexWriteGuard<'_, T> {
258 fn deref_mut(&mut self) -> &mut Self::Target {
259 unsafe { (*self.handle.value.get()).as_mut().unwrap() }
260 }
261}
262
263impl<T: Debug> Drop for MutexWriteGuard<'_, T> {
264 fn drop(&mut self) {
265 if ReadWriteMutex::release(self.handle).is_err() {
266 fatal_panic!(from self, "This should never happen! Failed to release write lock.");
267 }
268 }
269}
270
271#[derive(Debug)]
276pub struct ReadWriteMutexHandle<T: Sized + Debug> {
277 handle: HandleStorage<posix::pthread_rwlock_t>,
278 value: UnsafeCell<Option<T>>,
279}
280
281unsafe impl<T: Sized + Debug> Send for ReadWriteMutexHandle<T> {}
282unsafe impl<T: Sized + Debug> Sync for ReadWriteMutexHandle<T> {}
283
284impl<T: Sized + Debug> Handle for ReadWriteMutexHandle<T> {
285 fn new() -> Self {
286 Self {
287 handle: HandleStorage::new(posix::pthread_rwlock_t::new_zeroed()),
288 value: UnsafeCell::new(None),
289 }
290 }
291
292 fn is_initialized(&self) -> bool {
293 self.handle.is_initialized()
294 }
295
296 fn is_inter_process_capable(&self) -> bool {
297 self.handle.is_inter_process_capable()
298 }
299}
300
301impl<T: Sized + Debug> Drop for ReadWriteMutexHandle<T> {
302 fn drop(&mut self) {
303 if self.handle.is_initialized() {
304 unsafe {
305 self.handle.cleanup(|mtx|{
306 if posix::pthread_rwlock_destroy(mtx) != 0 {
307 warn!(from self,
308 "Unable to destroy read write mutex. Was it already destroyed by another instance in another process?");
309 }
310 });
311 }
312 }
313 }
314}
315
316#[derive(Debug)]
320pub struct ReadWriteMutex<'this, 'handle: 'this, T: Sized + Debug> {
321 handle: &'handle ReadWriteMutexHandle<T>,
322 _lifetime: PhantomData<&'this ()>,
323}
324
325unsafe impl<T: Send + Debug> Send for ReadWriteMutex<'_, '_, T> {}
326unsafe impl<T: Sync + Debug> Sync for ReadWriteMutex<'_, '_, T> {}
327
328impl<'handle, T: Sized + Debug> IpcConstructible<'handle, ReadWriteMutexHandle<T>>
329 for ReadWriteMutex<'_, 'handle, T>
330{
331 fn new(handle: &'handle ReadWriteMutexHandle<T>) -> Self {
332 Self {
333 handle,
334 _lifetime: PhantomData,
335 }
336 }
337}
338
339impl<'handle, T: Sized + Debug> IpcCapable<'handle, ReadWriteMutexHandle<T>>
340 for ReadWriteMutex<'_, 'handle, T>
341{
342 fn is_interprocess_capable(&self) -> bool {
343 self.handle.is_inter_process_capable()
344 }
345}
346
347impl<'this, 'handle: 'this, T: Sized + Debug> ReadWriteMutex<'this, 'handle, T> {
348 pub fn from_handle(
356 handle: &'handle ReadWriteMutexHandle<T>,
357 ) -> ReadWriteMutex<'this, 'handle, T> {
358 Self::new(handle)
359 }
360
361 fn new(handle: &'handle ReadWriteMutexHandle<T>) -> Self {
362 Self {
363 handle,
364 _lifetime: PhantomData,
365 }
366 }
367
368 pub fn read_blocking_lock(
369 &'this self,
370 ) -> Result<MutexReadGuard<'handle, T>, ReadWriteMutexReadLockError> {
371 let msg = "Failed to acquire read-lock";
372 handle_errno!(ReadWriteMutexReadLockError, from self,
373 errno_source unsafe { posix::pthread_rwlock_rdlock(self.handle.handle.get()).into() },
374 success Errno::ESUCCES => MutexReadGuard { handle: self.handle },
375 Errno::EAGAIN => (MaximumAmountOfReadLocksAcquired, "{} since the maximum amount of read-locks is already acquired.", msg),
376 Errno::EDEADLK => (DeadlockConditionDetected, "{} since a deadlock condition was detected.", msg),
377 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
378 );
379 }
380
381 pub fn read_try_lock(
384 &'this self,
385 ) -> Result<Option<MutexReadGuard<'handle, T>>, ReadWriteMutexReadLockError> {
386 let msg = "Failed to try to acquire read-lock";
387 handle_errno!(ReadWriteMutexReadLockError, from self,
388 errno_source unsafe { posix::pthread_rwlock_tryrdlock(self.handle.handle.get()).into() },
389 success Errno::ESUCCES => Some(MutexReadGuard { handle: self.handle });
390 success Errno::EBUSY => None;
391 success Errno::EDEADLK => None,
392 Errno::EAGAIN => (MaximumAmountOfReadLocksAcquired, "{} since the maximum amount of read-locks is already acquired.", msg),
393 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
394 );
395 }
396
397 pub fn write_blocking_lock(
400 &'this self,
401 ) -> Result<MutexWriteGuard<'handle, T>, ReadWriteMutexWriteLockError> {
402 let msg = "Failed to acquire write-lock";
403 handle_errno!(ReadWriteMutexWriteLockError, from self,
404 errno_source unsafe { posix::pthread_rwlock_wrlock(self.handle.handle.get()).into() },
405 success Errno::ESUCCES => MutexWriteGuard { handle: self.handle },
406 Errno::EDEADLK => (DeadlockConditionDetected, "{} since a deadlock condition was detected.", msg),
407 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
408 );
409 }
410
411 pub fn write_try_lock(
414 &'this self,
415 ) -> Result<Option<MutexWriteGuard<'handle, T>>, ReadWriteMutexWriteLockError> {
416 let msg = "Failed to try to acquire write-lock";
417 handle_errno!(ReadWriteMutexWriteLockError, from self,
418 errno_source unsafe { posix::pthread_rwlock_trywrlock(self.handle.handle.get()).into() },
419 success Errno::ESUCCES => Some(MutexWriteGuard { handle: self.handle });
420 success Errno::EBUSY => None;
421 success Errno::EDEADLK => None,
422 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
423 );
424 }
425
426 fn release(handle: &ReadWriteMutexHandle<T>) -> Result<(), ReadWriteMutexUnlockError> {
427 let msg = "Unable to release lock";
428 match unsafe { posix::pthread_rwlock_unlock(handle.handle.get()).into() } {
429 Errno::ESUCCES => Ok(()),
430 Errno::EPERM => {
431 fail!(from handle, with ReadWriteMutexUnlockError::OwnedByDifferentEntity,
432 "{} since it is not owned by the current thread.", msg);
433 }
434 v => {
435 fail!(from handle, with ReadWriteMutexUnlockError::UnknownError(v as i32),
436 "{} since an unknown error occurred ({}).", msg, v);
437 }
438 }
439 }
440}