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