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