1pub use crate::ipc_capable::{Handle, IpcCapable};
57
58use crate::ipc_capable::internal::{Capability, HandleStorage, IpcConstructible};
59use crate::{clock::AsTimespec, handle_errno};
60use iceoryx2_bb_elementary::{enum_gen, scope_guard::ScopeGuardBuilder};
61use iceoryx2_bb_log::{fail, fatal_panic, warn};
62use iceoryx2_pal_posix::posix::errno::Errno;
63use iceoryx2_pal_posix::posix::Struct;
64use iceoryx2_pal_posix::*;
65use std::{
66 cell::UnsafeCell,
67 fmt::Debug,
68 ops::{Deref, DerefMut},
69 time::Duration,
70};
71
72use crate::{
73 adaptive_wait::*,
74 clock::{ClockType, Time, TimeError},
75};
76
77#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
78pub enum ReadWriteMutexCreationError {
79 InsufficientMemory,
80 InsufficientResources,
81 InsufficientPermissions,
82 NoInterProcessSupport,
83 NoMutexKindSupport,
84 UnknownError(i32),
85}
86
87#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
88pub enum ReadWriteMutexReadLockError {
89 MaximumAmountOfReadLocksAcquired,
90 DeadlockConditionDetected,
91 UnknownError(i32),
92}
93
94#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
95pub enum ReadWriteMutexUnlockError {
96 OwnedByDifferentEntity,
97 UnknownError(i32),
98}
99
100#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
101pub enum ReadWriteMutexWriteLockError {
102 DeadlockConditionDetected,
103 UnknownError(i32),
104}
105
106#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
107pub enum ReadWriteMutexOpenIpcHandleError {
108 IsNotInterProcessCapable,
109 Uninitialized,
110}
111
112enum_gen! {
113 ReadWriteMutexReadTimedLockError
114 entry:
115 TimeoutExceedsMaximumSupportedDuration
116 mapping:
117 ReadWriteMutexReadLockError,
118 AdaptiveWaitError,
119 TimeError
120}
121
122enum_gen! {
123 ReadWriteMutexWriteTimedLockError
124 entry:
125 TimeoutExceedsMaximumSupportedDuration
126 mapping:
127 ReadWriteMutexWriteLockError,
128 AdaptiveWaitError,
129 TimeError
130}
131
132enum_gen! {
133 ReadWriteMutexError
138 generalization:
139 FailedToLock <= ReadWriteMutexWriteTimedLockError; ReadWriteMutexReadTimedLockError; ReadWriteMutexWriteLockError; ReadWriteMutexReadLockError,
140 FailedToCreate <= ReadWriteMutexCreationError
141}
142
143#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
145#[repr(i32)]
146pub enum ReadWriteMutexPriority {
147 PreferReader = posix::PTHREAD_PREFER_READER_NP,
148 PreferWriter = posix::PTHREAD_PREFER_WRITER_NP,
149 PreferWriterNonRecursive = posix::PTHREAD_PREFER_WRITER_NONRECURSIVE_NP,
150}
151
152#[derive(Debug)]
154pub struct ReadWriteMutexBuilder {
155 clock_type: ClockType,
156 mutex_priority: ReadWriteMutexPriority,
157 is_interprocess_capable: bool,
158}
159
160impl Default for ReadWriteMutexBuilder {
161 fn default() -> Self {
162 ReadWriteMutexBuilder {
163 clock_type: ClockType::default(),
164 mutex_priority: ReadWriteMutexPriority::PreferReader,
165 is_interprocess_capable: true,
166 }
167 }
168}
169
170impl ReadWriteMutexBuilder {
171 pub fn new() -> Self {
172 Self::default()
173 }
174
175 pub fn clock_type(mut self, value: ClockType) -> Self {
178 self.clock_type = value;
179 self
180 }
181
182 pub fn is_interprocess_capable(mut self, value: bool) -> Self {
184 self.is_interprocess_capable = value;
185 self
186 }
187
188 pub fn mutex_priority(mut self, value: ReadWriteMutexPriority) -> Self {
190 self.mutex_priority = value;
191 self
192 }
193
194 fn initialize_rw_mutex(
195 &self,
196 mtx: *mut posix::pthread_rwlock_t,
197 ) -> Result<Capability, ReadWriteMutexCreationError> {
198 let msg = "Failed to create mutex";
199 let origin = format!("{:?}", self);
200
201 let mut attributes = ScopeGuardBuilder::new(posix::pthread_rwlockattr_t::new()).on_init(|attr| {
202 handle_errno!(ReadWriteMutexCreationError, from self,
203 errno_source unsafe { posix::pthread_rwlockattr_init( attr).into() },
204 success Errno::ESUCCES => (),
205 Errno::ENOMEM => (InsufficientMemory, "{} due to insufficient memory while creating rwlock attributes.", msg),
206 v => (UnknownError(v as i32), "{} since an unknown error occurred while creating rwlock attributes.", msg)
207 );
208 }).on_drop(|attr| {
209 match unsafe {posix::pthread_rwlockattr_destroy(attr) } {
210 0 => (),
211 v => {
212 fatal_panic!(from origin, "This should never happen! Failed to release rwlock attributes ({}).", v);
213 }
214 }
215 }).create()?;
216
217 match unsafe { posix::pthread_rwlockattr_setpshared(attributes.get_mut(), 0) } {
218 0 => (),
219 v => {
220 fail!(from origin, with ReadWriteMutexCreationError::NoInterProcessSupport,
221 "{} due to an unknown error while setting interprocess capabilities ({}).", msg,v );
222 }
223 }
224
225 match unsafe {
226 posix::pthread_rwlockattr_setkind_np(attributes.get_mut(), self.mutex_priority as i32)
227 } {
228 0 => (),
229 v => {
230 fail!(from origin, with ReadWriteMutexCreationError::NoMutexKindSupport,
231 "{} due to an unknown error while setting the mutex kind ({}).", msg, v);
232 }
233 }
234
235 match unsafe { posix::pthread_rwlock_init(mtx, attributes.get()).into() } {
236 Errno::ESUCCES => (),
237 Errno::EAGAIN => {
238 fail!(from origin, with ReadWriteMutexCreationError::InsufficientResources, "{} due to insufficient resources.", msg);
239 }
240 Errno::ENOMEM => {
241 fail!(from origin, with ReadWriteMutexCreationError::InsufficientResources, "{} due to insufficient memory.", msg);
242 }
243 Errno::EPERM => {
244 fail!(from origin, with ReadWriteMutexCreationError::InsufficientPermissions, "{} due to insufficient permissions.", msg);
245 }
246 v => {
247 fail!(from origin, with ReadWriteMutexCreationError::UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v);
248 }
249 };
250
251 match self.is_interprocess_capable {
252 true => Ok(Capability::InterProcess),
253 false => Ok(Capability::ProcessLocal),
254 }
255 }
256
257 pub fn create<T: Debug>(
259 self,
260 t: T,
261 handle: &ReadWriteMutexHandle<T>,
262 ) -> Result<ReadWriteMutex<'_, T>, ReadWriteMutexCreationError> {
263 unsafe {
264 handle
265 .handle
266 .initialize(|mtx| self.initialize_rw_mutex(mtx))?
267 };
268
269 unsafe { *handle.clock_type.get() = self.clock_type };
270 unsafe { *handle.value.get() = Some(t) };
271
272 Ok(ReadWriteMutex::new(handle))
273 }
274}
275
276#[derive(Debug)]
281pub struct MutexReadGuard<'a, 'b, T: Debug> {
282 mutex: &'a ReadWriteMutex<'b, T>,
283}
284
285unsafe impl<T: Send + Debug> Send for MutexReadGuard<'_, '_, T> {}
286unsafe impl<T: Send + Sync + Debug> Sync for MutexReadGuard<'_, '_, T> {}
287
288impl<T: Debug> Deref for MutexReadGuard<'_, '_, T> {
289 type Target = T;
290
291 fn deref(&self) -> &Self::Target {
292 unsafe { (*self.mutex.handle.value.get()).as_ref().unwrap() }
293 }
294}
295
296impl<T: Debug> Drop for MutexReadGuard<'_, '_, T> {
297 fn drop(&mut self) {
298 if self.mutex.release().is_err() {
299 fatal_panic!(from self.mutex, "This should never happen! Failed to release read lock.");
300 }
301 }
302}
303
304#[derive(Debug)]
309pub struct MutexWriteGuard<'a, 'b, T: Debug> {
310 mutex: &'a ReadWriteMutex<'b, T>,
311}
312
313unsafe impl<T: Send + Debug> Send for MutexWriteGuard<'_, '_, T> {}
314unsafe impl<T: Send + Sync + Debug> Sync for MutexWriteGuard<'_, '_, T> {}
315
316impl<T: Debug> Deref for MutexWriteGuard<'_, '_, T> {
317 type Target = T;
318
319 fn deref(&self) -> &Self::Target {
320 unsafe { (*self.mutex.handle.value.get()).as_ref().unwrap() }
321 }
322}
323
324impl<T: Debug> DerefMut for MutexWriteGuard<'_, '_, T> {
325 fn deref_mut(&mut self) -> &mut Self::Target {
326 unsafe { (*self.mutex.handle.value.get()).as_mut().unwrap() }
327 }
328}
329
330impl<T: Debug> Drop for MutexWriteGuard<'_, '_, T> {
331 fn drop(&mut self) {
332 if self.mutex.release().is_err() {
333 fatal_panic!(from self.mutex, "This should never happen! Failed to release write lock.");
334 }
335 }
336}
337
338#[derive(Debug)]
343pub struct ReadWriteMutexHandle<T: Sized + Debug> {
344 handle: HandleStorage<posix::pthread_rwlock_t>,
345 clock_type: UnsafeCell<ClockType>,
346 value: UnsafeCell<Option<T>>,
347}
348
349unsafe impl<T: Sized + Debug> Send for ReadWriteMutexHandle<T> {}
350unsafe impl<T: Sized + Debug> Sync for ReadWriteMutexHandle<T> {}
351
352impl<T: Sized + Debug> Handle for ReadWriteMutexHandle<T> {
353 fn new() -> Self {
354 Self {
355 handle: HandleStorage::new(posix::pthread_rwlock_t::new()),
356 clock_type: UnsafeCell::new(ClockType::default()),
357 value: UnsafeCell::new(None),
358 }
359 }
360
361 fn is_initialized(&self) -> bool {
362 self.handle.is_initialized()
363 }
364
365 fn is_inter_process_capable(&self) -> bool {
366 self.handle.is_inter_process_capable()
367 }
368}
369
370impl<T: Sized + Debug> Drop for ReadWriteMutexHandle<T> {
371 fn drop(&mut self) {
372 if self.handle.is_initialized() {
373 unsafe {
374 self.handle.cleanup(|mtx|{
375 if posix::pthread_rwlock_destroy(mtx) != 0 {
376 warn!(from self,
377 "Unable to destroy read write mutex. Was it already destroyed by another instance in another process?");
378 }
379 });
380 }
381 }
382 }
383}
384
385#[derive(Debug)]
389pub struct ReadWriteMutex<'a, T: Sized + Debug> {
390 handle: &'a ReadWriteMutexHandle<T>,
391}
392
393unsafe impl<T: Send + Debug> Send for ReadWriteMutex<'_, T> {}
394unsafe impl<T: Sync + Debug> Sync for ReadWriteMutex<'_, T> {}
395
396impl<'a, T: Sized + Debug> IpcConstructible<'a, ReadWriteMutexHandle<T>> for ReadWriteMutex<'a, T> {
397 fn new(handle: &'a ReadWriteMutexHandle<T>) -> Self {
398 Self { handle }
399 }
400}
401
402impl<'a, T: Sized + Debug> IpcCapable<'a, ReadWriteMutexHandle<T>> for ReadWriteMutex<'a, T> {
403 fn is_interprocess_capable(&self) -> bool {
404 self.handle.is_inter_process_capable()
405 }
406}
407
408impl<'a, T: Sized + Debug> ReadWriteMutex<'a, T> {
409 fn new(handle: &'a ReadWriteMutexHandle<T>) -> Self {
410 Self { handle }
411 }
412
413 pub fn clock_type(&self) -> ClockType {
415 unsafe { *self.handle.clock_type.get() }
416 }
417
418 pub fn read_lock(&self) -> Result<MutexReadGuard<'_, '_, T>, ReadWriteMutexReadLockError> {
421 let msg = "Failed to acquire read-lock";
422 handle_errno!(ReadWriteMutexReadLockError, from self,
423 errno_source unsafe { posix::pthread_rwlock_rdlock(self.handle.handle.get()).into() },
424 success Errno::ESUCCES => MutexReadGuard { mutex: self },
425 Errno::EAGAIN => (MaximumAmountOfReadLocksAcquired, "{} since the maximum amount of read-locks is already acquired.", msg),
426 Errno::EDEADLK => (DeadlockConditionDetected, "{} since a deadlock condition was detected.", msg),
427 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
428 );
429 }
430
431 pub fn read_try_lock(
434 &self,
435 ) -> Result<Option<MutexReadGuard<'_, '_, T>>, ReadWriteMutexReadLockError> {
436 let msg = "Failed to try to acquire read-lock";
437 handle_errno!(ReadWriteMutexReadLockError, from self,
438 errno_source unsafe { posix::pthread_rwlock_tryrdlock(self.handle.handle.get()).into() },
439 success Errno::ESUCCES => Some(MutexReadGuard { mutex: self });
440 success Errno::EBUSY => None;
441 success Errno::EDEADLK => None,
442 Errno::EAGAIN => (MaximumAmountOfReadLocksAcquired, "{} since the maximum amount of read-locks is already acquired.", msg),
443 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
444 );
445 }
446
447 pub fn read_timed_lock(
450 &self,
451 timeout: Duration,
452 ) -> Result<Option<MutexReadGuard<'_, '_, T>>, ReadWriteMutexReadTimedLockError> {
453 let msg = "Failted to timed wait for read lock";
454
455 match self.clock_type() {
456 ClockType::Realtime => {
457 let now = fail!(from self, when Time::now_with_clock(ClockType::Realtime),
458 "{} due to a failure while acquiring current system time.", msg);
459 let timeout_adjusted = now.as_duration() + timeout;
460 handle_errno!(ReadWriteMutexReadTimedLockError, from self,
461 errno_source unsafe { posix::pthread_rwlock_timedrdlock(self.handle.handle.get(), &timeout_adjusted.as_timespec()) }.into(),
462 success Errno::ESUCCES => Some(MutexReadGuard { mutex: self });
463 success Errno::ETIMEDOUT => None;
464 success Errno::EDEADLK => None,
465 Errno::EAGAIN => (ReadWriteMutexReadLockError(ReadWriteMutexReadLockError::MaximumAmountOfReadLocksAcquired), "{} since the maximum number of read locks were already acquired.", msg),
466 Errno::EINVAL => (TimeoutExceedsMaximumSupportedDuration, "{} since the timeout of {:?} exceeds the maximum supported duration.", msg, timeout),
467 v => (ReadWriteMutexReadLockError(ReadWriteMutexReadLockError::UnknownError(v as i32)), "{} since unknown error occurred while acquiring the lock ({})", msg, v)
468 )
469 }
470 ClockType::Monotonic => {
471 let time = fail!(from self, when Time::now_with_clock(self.clock_type()),
472 "{} due to a failure while acquiring current system time in.", msg);
473 let mut adaptive_wait = fail!(from self, when AdaptiveWaitBuilder::new()
474 .clock_type(self.clock_type())
475 .create(), "{} since the adaptive wait could not be created.", msg);
476
477 loop {
478 match self.read_try_lock() {
479 Ok(Some(v)) => return Ok(Some(v)),
480 Ok(None) => match fail!(from self, when time.elapsed(),
481 "{} due to a failure while acquiring elapsed system time.", msg)
482 < timeout
483 {
484 true => {
485 fail!(from self, when adaptive_wait.wait(), "{} since AdaptiveWait failed.", msg);
486 }
487 false => return Ok(None),
488 },
489 Err(v) => {
490 fail!(from self, with ReadWriteMutexReadTimedLockError::ReadWriteMutexReadLockError(v),
491 "{} since read_try_lock failed.", msg);
492 }
493 }
494 }
495 }
496 }
497 }
498
499 pub fn write_lock(&self) -> Result<MutexWriteGuard<'_, '_, T>, ReadWriteMutexWriteLockError> {
502 let msg = "Failed to acquire write-lock";
503 handle_errno!(ReadWriteMutexWriteLockError, from self,
504 errno_source unsafe { posix::pthread_rwlock_wrlock(self.handle.handle.get()).into() },
505 success Errno::ESUCCES => MutexWriteGuard { mutex: self },
506 Errno::EDEADLK => (DeadlockConditionDetected, "{} since a deadlock condition was detected.", msg),
507 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
508 );
509 }
510
511 pub fn write_try_lock(
514 &self,
515 ) -> Result<Option<MutexWriteGuard<'_, '_, T>>, ReadWriteMutexWriteLockError> {
516 let msg = "Failed to try to acquire write-lock";
517 handle_errno!(ReadWriteMutexWriteLockError, from self,
518 errno_source unsafe { posix::pthread_rwlock_trywrlock(self.handle.handle.get()).into() },
519 success Errno::ESUCCES => Some(MutexWriteGuard { mutex: self });
520 success Errno::EBUSY => None;
521 success Errno::EDEADLK => None,
522 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
523 );
524 }
525
526 pub fn write_timed_lock(
529 &self,
530 timeout: Duration,
531 ) -> Result<Option<MutexWriteGuard<'_, '_, T>>, ReadWriteMutexWriteTimedLockError> {
532 let msg = "Failed to timed wait for write lock";
533
534 match self.clock_type() {
535 ClockType::Realtime => {
536 let now = fail!(from self, when Time::now_with_clock(ClockType::Realtime),
537 "{} due to a failure while acquiring current system time.", msg);
538 let timeout_adjusted = now.as_duration() + timeout;
539 handle_errno!(ReadWriteMutexWriteTimedLockError, from self,
540 errno_source unsafe { posix::pthread_rwlock_timedwrlock(self.handle.handle.get(), &timeout_adjusted.as_timespec()) }.into(),
541 success Errno::ESUCCES => Some(MutexWriteGuard { mutex: self });
542 success Errno::ETIMEDOUT => None;
543 success Errno::EDEADLK => None,
544 Errno::EINVAL => (TimeoutExceedsMaximumSupportedDuration, "{} since the timeout of {:?} exceeds the maximum supported duration.", msg, timeout),
545 v => (ReadWriteMutexWriteLockError(ReadWriteMutexWriteLockError::UnknownError(v as i32)), "{} since unknown error occurred while acquiring the lock ({})", msg, v)
546 )
547 }
548 ClockType::Monotonic => {
549 let time = fail!(from self, when Time::now_with_clock(self.clock_type()),
550 "{} due to a failure while acquiring current system time.", msg);
551 let mut adaptive_wait = fail!(from self, when AdaptiveWaitBuilder::new()
552 .clock_type(self.clock_type())
553 .create(), "{} since the adaptive wait could not be created.", msg);
554
555 loop {
556 match self.write_try_lock() {
557 Ok(Some(v)) => return Ok(Some(v)),
558 Ok(None) => match fail!(from self, when time.elapsed(),
559 "{} due to a failure while acquiring elapsed system time.", msg)
560 < timeout
561 {
562 true => {
563 fail!(from self, when adaptive_wait.wait(), "{} since AdaptiveWait failed.", msg);
564 }
565 false => return Ok(None),
566 },
567 Err(v) => {
568 fail!(from self, with ReadWriteMutexWriteTimedLockError::ReadWriteMutexWriteLockError(v),
569 "{} since write_try_lock failed.", msg);
570 }
571 }
572 }
573 }
574 }
575 }
576
577 fn release(&self) -> Result<(), ReadWriteMutexUnlockError> {
578 let msg = "Unable to release lock";
579 match unsafe { posix::pthread_rwlock_unlock(self.handle.handle.get()).into() } {
580 Errno::ESUCCES => Ok(()),
581 Errno::EPERM => {
582 fail!(from self, with ReadWriteMutexUnlockError::OwnedByDifferentEntity,
583 "{} since it is not owned by the current thread.", msg);
584 }
585 v => {
586 fail!(from self, with ReadWriteMutexUnlockError::UnknownError(v as i32),
587 "{} since an unknown error occurred ({}).", msg, v);
588 }
589 }
590 }
591}