iceoryx2_bb_posix/
semaphore.rs

1// Copyright (c) 2023 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13//! Provides the [`NamedSemaphore`] and the [`UnnamedSemaphore`]. Both can be used in an
14//! inter-process context to signal events between processes.
15
16pub use crate::ipc_capable::{Handle, IpcCapable};
17
18use core::fmt::Debug;
19
20use crate::ipc_capable::internal::{Capability, HandleStorage, IpcConstructible};
21use iceoryx2_bb_concurrency::cell::UnsafeCell;
22use iceoryx2_bb_container::semantic_string::*;
23use iceoryx2_bb_elementary::enum_gen;
24use iceoryx2_bb_system_types::file_name::FileName;
25use iceoryx2_bb_system_types::file_path::*;
26use iceoryx2_bb_system_types::path::*;
27use iceoryx2_log::{debug, fail, fatal_panic, warn};
28use iceoryx2_pal_posix::posix::errno::Errno;
29use iceoryx2_pal_posix::posix::MemZeroedStruct;
30use iceoryx2_pal_posix::*;
31
32use crate::{
33    adaptive_wait::*,
34    clock::{AsTimespec, Time, TimeError},
35    config::MAX_INITIAL_SEMAPHORE_VALUE,
36    system_configuration::*,
37};
38use core::time::Duration;
39
40pub use crate::clock::ClockType;
41pub use crate::creation_mode::CreationMode;
42pub use crate::permission::Permission;
43
44enum_gen! { NamedSemaphoreCreationError
45  entry:
46    InsufficientPermissions,
47    InitialValueTooLarge,
48    PerProcessFileHandleLimitReached,
49    SystemWideFileHandleLimitReached,
50    AlreadyExists,
51    MaxFilePathLengthExceeded,
52    Interrupt,
53    NotSupportForGivenName,
54    DoesNotExist,
55    NoSpaceLeft,
56    UnknownError(i32)
57}
58
59#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
60pub enum UnnamedSemaphoreCreationError {
61    InitialValueTooLarge,
62    ExceedsMaximumNumberOfSemaphores,
63    InsufficientPermissions,
64    UnknownError(i32),
65}
66
67#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
68pub enum SemaphorePostError {
69    Overflow,
70    UnknownError(i32),
71}
72
73#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
74pub enum SemaphoreWaitError {
75    NotSupported,
76    DeadlockConditionDetected,
77    Interrupt,
78    UnknownError(i32),
79}
80
81#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
82pub enum UnnamedSemaphoreOpenIpcHandleError {
83    IsNotInterProcessCapable,
84    Uninitialized,
85}
86
87enum_gen! {
88    SemaphoreTimedWaitError
89  entry:
90    WaitingTimeExceedsSystemLimits
91  mapping:
92    SemaphoreWaitError,
93    AdaptiveWaitError,
94    TimeError
95}
96
97enum_gen! {
98    /// The SemaphoreError enum is a generalization when one doesn't require the fine-grained error
99    /// handling enums. One can forward SemaphoreError as more generic return value when a method
100    /// returns a Semaphore***Error.
101    /// On a higher level it is again convertable to [`crate::Error`].
102    SemaphoreError
103  generalization:
104    FailedToCreate <= NamedSemaphoreCreationError; UnnamedSemaphoreCreationError,
105    FailedToPost <= SemaphorePostError,
106    FailedToWait <= SemaphoreWaitError; SemaphoreTimedWaitError
107}
108
109#[derive(PartialEq, Eq)]
110enum UnlinkMode {
111    IgnoreNonExistingSemaphore,
112    FailWhenSemaphoreDoesNotExist,
113}
114
115#[derive(PartialEq, Eq)]
116enum InitMode {
117    Create,
118    Open,
119    TryOpen,
120}
121
122mod internal {
123    use super::*;
124
125    #[doc(hidden)]
126    pub trait SemaphoreHandle {
127        fn handle(&self) -> *mut posix::sem_t;
128        fn get_clock_type(&self) -> ClockType;
129    }
130}
131
132/// Defines the interface of a [`NamedSemaphore`] and an [`UnnamedSemaphore`].
133pub trait SemaphoreInterface: internal::SemaphoreHandle + Debug {
134    /// Increments the semaphore by one. If the semaphore already holds the maximum supported value
135    /// another post call will lead to [`SemaphorePostError::Overflow`].
136    fn post(&self) -> Result<(), SemaphorePostError> {
137        if unsafe { posix::sem_post(self.handle()) } == 0 {
138            return Ok(());
139        }
140
141        let msg = "Unable to post semaphore";
142        handle_errno!(SemaphorePostError, from self,
143            fatal Errno::EINVAL => ("This should never happen! {} since an invalid handle was provided.", msg),
144            Errno::EOVERFLOW => (Overflow, "{} since the operation would cause an overflow.", msg),
145            v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
146        );
147    }
148
149    /// Decrements the semaphore by one. If the semaphore is zero it waits until a
150    /// [`SemaphoreInterface::post()`] call incremented the semaphore by one. A semaphores internal
151    /// value is always greater or equal to zero.
152    fn blocking_wait(&self) -> Result<(), SemaphoreWaitError> {
153        if unsafe { posix::sem_wait(self.handle()) } == 0 {
154            return Ok(());
155        }
156
157        let msg = "Unable to wait on semaphore";
158        handle_errno!(SemaphoreWaitError, from self,
159            fatal Errno::EINVAL => ("This should never happen! {} since an invalid handle was provided!", msg),
160            Errno::ENOSYS => (NotSupported, "{} since sem_wait is not supported by the system.", msg),
161            Errno::EDEADLK => (DeadlockConditionDetected, "{} since a deadlock condition was detected.", msg),
162            Errno::EINTR => (Interrupt, "{} since an interrupt signal was received.", msg),
163            v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
164        );
165    }
166
167    /// Tries to decrement the semaphore by one if it is greater zero and returns true. If the semaphores
168    /// internal value is zero it returns false and does not decrement the semaphore.
169    fn try_wait(&self) -> Result<bool, SemaphoreWaitError> {
170        if unsafe { posix::sem_trywait(self.handle()) } == 0 {
171            return Ok(true);
172        }
173
174        let msg = "Unable to wait on semaphore";
175        handle_errno!(SemaphoreWaitError, from self,
176            success Errno::EAGAIN => false,
177            fatal Errno::EINVAL => ("This should never happen! {} since an invalid handle was provided!", msg),
178            Errno::ENOSYS => (NotSupported, "{} since sem_wait is not supported by the system.", msg),
179            Errno::EDEADLK => (DeadlockConditionDetected, "{} since a deadlock condition was detected.", msg),
180            Errno::EINTR => (Interrupt, "{} since an interrupt signal was received.", msg),
181            v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
182        );
183    }
184
185    /// Tries to decrement the semaphore until the decrement was successful and returns true
186    /// or the timeout has passed and then returns false.
187    fn timed_wait(&self, timeout: Duration) -> Result<bool, SemaphoreTimedWaitError> {
188        let msg = "Unable to timed wait on semaphore";
189        match self.clock_type() {
190            ClockType::Monotonic => {
191                let mut adaptive_wait = fail!(from self, when AdaptiveWaitBuilder::new()
192                    .clock_type(self.clock_type())
193                    .create(), "{} since the adaptive wait could not be created.", msg);
194
195                match adaptive_wait.timed_wait_while(
196                    || -> Result<bool, SemaphoreWaitError> { Ok(!self.try_wait()?) },
197                    timeout,
198                ) {
199                    Ok(v) => Ok(v),
200                    Err(AdaptiveTimedWaitWhileError::PredicateFailure(v)) => {
201                        fail!(from self, with SemaphoreTimedWaitError::from(v),
202                            "{} since try_wait() failed with ({:?}).", msg, v);
203                    }
204                    Err(AdaptiveTimedWaitWhileError::AdaptiveWaitError(v)) => {
205                        fail!(from self, with SemaphoreTimedWaitError::from(v),
206                             "{} since adaptive wait failed with ({:?}).", msg, v);
207                    }
208                }
209            }
210            ClockType::Realtime => {
211                let wait_time = timeout
212                    + fail!(from self, when Time::now_with_clock(self.clock_type()),
213                    "{} due to a failure while acquiring the current system time.", msg)
214                    .as_duration();
215                if unsafe { posix::sem_timedwait(self.handle(), &wait_time.as_timespec()) } == 0 {
216                    return Ok(true);
217                }
218
219                let msg = "Failed to perform timedwait";
220                handle_errno!(SemaphoreTimedWaitError, from self,
221                    success Errno::ETIMEDOUT => false,
222                    Errno::EINVAL => (WaitingTimeExceedsSystemLimits, "{} since the provided duration {:?} exceeds the maximum supported limit.", msg, timeout),
223                    Errno::EDEADLK => (SemaphoreWaitError(SemaphoreWaitError::DeadlockConditionDetected), "{} since a deadlock condition was detected.", msg),
224                    Errno::EINTR => (SemaphoreWaitError(SemaphoreWaitError::Interrupt), "{} since an interrupt signal occurred.", msg),
225                    v => (SemaphoreWaitError(SemaphoreWaitError::UnknownError(v as i32)), "{} since an unknown error occurred ({}).", msg, v)
226                )
227            }
228        }
229    }
230
231    fn clock_type(&self) -> ClockType {
232        self.get_clock_type()
233    }
234}
235
236/// Builder for the [`NamedSemaphore`].
237///
238/// # Example
239///
240/// ## Create new named semaphore
241///
242/// ```ignore
243/// # extern crate iceoryx2_loggers;
244///
245/// use iceoryx2_bb_posix::semaphore::*;
246/// use iceoryx2_bb_system_types::file_name::FileName;
247/// use iceoryx2_bb_container::semantic_string::*;
248///
249/// let name = FileName::new(b"mySemaphoreName").unwrap();
250/// let semaphore = NamedSemaphoreBuilder::new(&name)
251///     // defines the clock which is used in [`SemaphoreInterface::timed_wait()`]
252///                     .clock_type(ClockType::Monotonic)
253///     // the semaphore is created, if there already exists a semaphore it is deleted
254///                     .creation_mode(CreationMode::PurgeAndCreate)
255///                     .initial_value(5)
256///                     .permission(Permission::OWNER_ALL | Permission::GROUP_ALL)
257///                     .create()
258///                     .expect("failed to create semaphore");
259/// ```
260///
261/// ## Open existing semaphore
262///
263/// ```no_run
264/// # extern crate iceoryx2_loggers;
265///
266/// use iceoryx2_bb_posix::semaphore::*;
267/// use iceoryx2_bb_system_types::file_name::FileName;
268/// use iceoryx2_bb_container::semantic_string::*;
269///
270/// let name = FileName::new(b"mySemaphoreName").unwrap();
271/// let semaphore = NamedSemaphoreBuilder::new(&name)
272///                     .clock_type(ClockType::Monotonic)
273///                     .open_existing()
274///                     .expect("failed to open semaphore");
275/// ```
276#[derive(Debug)]
277pub struct NamedSemaphoreBuilder {
278    name: FileName,
279    initial_value: u32,
280    permission: Permission,
281    clock_type: ClockType,
282    creation_mode: Option<CreationMode>,
283}
284
285impl NamedSemaphoreBuilder {
286    pub fn new(name: &FileName) -> Self {
287        Self {
288            creation_mode: None,
289            name: *name,
290            initial_value: 0,
291            permission: Permission::OWNER_ALL,
292            clock_type: ClockType::default(),
293        }
294    }
295
296    /// Sets the type of clock which will be used in [`SemaphoreInterface::timed_wait()`]. Be
297    /// aware a clock like [`ClockType::Realtime`] is depending on the systems local time. If this
298    /// time changes while waiting it can cause extrem long waits or no wait at all.
299    pub fn clock_type(mut self, value: ClockType) -> Self {
300        self.clock_type = value;
301        self
302    }
303
304    /// Opens an already existing [`NamedSemaphore`].
305    pub fn open_existing(self) -> Result<NamedSemaphore, NamedSemaphoreCreationError> {
306        NamedSemaphore::new(self)
307    }
308
309    /// Defines how the semaphore will be created and returns the [`NamedSemaphoreCreationBuilder`]
310    /// which provides further means of configuration only available when a semaphore is created.
311    pub fn creation_mode(mut self, creation_mode: CreationMode) -> NamedSemaphoreCreationBuilder {
312        self.creation_mode = Some(creation_mode);
313        NamedSemaphoreCreationBuilder { config: self }
314    }
315}
316
317/// Provides additional settings which are only available for newly created semaphores. Is
318/// returned by [`NamedSemaphoreBuilder::creation_mode()`].
319///
320/// For an example see [`NamedSemaphoreBuilder`]
321pub struct NamedSemaphoreCreationBuilder {
322    config: NamedSemaphoreBuilder,
323}
324
325impl NamedSemaphoreCreationBuilder {
326    /// Sets the initial value of the semaphore. Must be less than [`MAX_INITIAL_SEMAPHORE_VALUE`].
327    pub fn initial_value(mut self, value: u32) -> Self {
328        self.config.initial_value = value;
329        self
330    }
331
332    /// Sets the permission of the newly created semaphore.
333    pub fn permission(mut self, value: Permission) -> Self {
334        self.config.permission = value;
335        self
336    }
337
338    /// Creates a [`NamedSemaphore`].
339    pub fn create(self) -> Result<NamedSemaphore, NamedSemaphoreCreationError> {
340        NamedSemaphore::new(self.config)
341    }
342}
343
344/// Represents a POSIX named semaphore - a semaphore with a corresponding file handle which can
345/// be opened by other processes. The filename corresponds to the semaphore name. A named semaphore
346/// is created by the [`NamedSemaphoreBuilder`].
347///
348/// # Example
349///
350/// ## In process 1
351/// ```no_run
352/// # extern crate iceoryx2_loggers;
353///
354/// use iceoryx2_bb_posix::semaphore::*;
355/// use iceoryx2_bb_posix::clock::*;
356/// use core::time::Duration;
357/// use iceoryx2_bb_system_types::file_name::FileName;
358/// use iceoryx2_bb_container::semantic_string::*;
359///
360/// let name = FileName::new(b"mySemaphoreName").unwrap();
361/// let semaphore = NamedSemaphoreBuilder::new(&name)
362///                     .creation_mode(CreationMode::PurgeAndCreate)
363///                     .permission(Permission::OWNER_ALL)
364///                     .create()
365///                     .expect("failed to create semaphore");
366///
367/// loop {
368///     nanosleep(Duration::from_secs(1));
369///     println!("trigger process 2");
370///     semaphore.post().expect("failed to trigger semaphore");
371/// }
372/// ```
373///
374/// ## In process 2
375/// ```no_run
376/// # extern crate iceoryx2_loggers;
377///
378/// use iceoryx2_bb_posix::semaphore::*;
379/// use iceoryx2_bb_system_types::file_name::FileName;
380/// use iceoryx2_bb_container::semantic_string::*;
381///
382/// let name = FileName::new(b"mySemaphoreName").unwrap();
383/// let semaphore = NamedSemaphoreBuilder::new(&name)
384///                     .open_existing()
385///                     .expect("failed to open semaphore");
386///
387/// loop {
388///     semaphore.blocking_wait().expect("failed to wait on semaphore");
389///     println!("process 1 has triggered me");
390/// }
391/// ```
392///
393/// ## Output
394///
395/// When both processes are running in two separate terminals one can observe that process 1 triggers
396/// process 2 every second.
397#[derive(Debug)]
398pub struct NamedSemaphore {
399    name: FileName,
400    handle: *mut posix::sem_t,
401    has_ownership: bool,
402    clock_type: ClockType,
403}
404
405unsafe impl Send for NamedSemaphore {}
406unsafe impl Sync for NamedSemaphore {}
407
408impl Drop for NamedSemaphore {
409    fn drop(&mut self) {
410        if core::ptr::eq(self.handle, posix::SEM_FAILED) {
411            return;
412        }
413
414        if unsafe { posix::sem_close(self.handle) } != 0 {
415            fatal_panic!(from self, "This should never happen! The semaphore handle is invalid and cannot be closed.");
416        }
417
418        if self.has_ownership
419            && self
420                .unlink(UnlinkMode::FailWhenSemaphoreDoesNotExist)
421                .is_err()
422        {
423            fatal_panic!(from self, "Failed to cleanup semaphore. Something else removed a managed semaphore which should never happen!");
424        }
425    }
426}
427
428impl NamedSemaphore {
429    fn new(config: NamedSemaphoreBuilder) -> Result<NamedSemaphore, NamedSemaphoreCreationError> {
430        let mut new_sem = NamedSemaphore {
431            name: config.name,
432            handle: posix::SEM_FAILED,
433            has_ownership: false,
434            clock_type: config.clock_type,
435        };
436
437        match config.creation_mode {
438            None => {
439                new_sem.open(Permission::none(), InitMode::Open, 0)?;
440            }
441            Some(CreationMode::PurgeAndCreate) => {
442                new_sem.has_ownership = true;
443                fail!(from new_sem, when new_sem.unlink(UnlinkMode::IgnoreNonExistingSemaphore), "Failed to remove semaphore before creating a new one.");
444                new_sem.open(config.permission, InitMode::Create, config.initial_value)?;
445            }
446            Some(CreationMode::CreateExclusive) => {
447                new_sem.has_ownership = true;
448                new_sem.open(config.permission, InitMode::Create, config.initial_value)?;
449            }
450            Some(CreationMode::OpenOrCreate) => {
451                match new_sem.open(Permission::none(), InitMode::TryOpen, 0) {
452                    Ok(()) => (),
453                    Err(NamedSemaphoreCreationError::DoesNotExist) => {
454                        new_sem.has_ownership = true;
455                        new_sem.open(config.permission, InitMode::Create, config.initial_value)?;
456                    }
457                    Err(v) => return Err(v),
458                }
459            }
460        };
461
462        Ok(new_sem)
463    }
464
465    fn unlink(&mut self, mode: UnlinkMode) -> Result<(), NamedSemaphoreCreationError> {
466        let file_path =
467            FilePath::from_path_and_file(&Path::new(b"/").unwrap(), &self.name).unwrap();
468        if unsafe { posix::sem_unlink(file_path.as_c_str()) } == 0 {
469            debug!(from self, "semaphore removed.");
470            return Ok(());
471        }
472
473        let msg = "Unable to unlink semaphore";
474        let ignore_non_existing_semaphore = mode == UnlinkMode::IgnoreNonExistingSemaphore;
475        handle_errno!(NamedSemaphoreCreationError, from self,
476            success_when ignore_non_existing_semaphore,
477                Errno::ENOENT => ((), AlreadyExists, "{} since no semaphore with the given name exists.", msg),
478            Errno::EACCES => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
479            Errno::ENAMETOOLONG => (MaxFilePathLengthExceeded, "{} since the name exceeds the maximum supported length.", msg),
480            v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
481        )
482    }
483
484    fn open(
485        &mut self,
486        permission: Permission,
487        mode: InitMode,
488        initial_value: u32,
489    ) -> Result<(), NamedSemaphoreCreationError> {
490        let msg;
491        if initial_value > MAX_INITIAL_SEMAPHORE_VALUE {
492            fail!(from self, with NamedSemaphoreCreationError::InitialValueTooLarge,
493                "Unable to create semaphore since the initial semaphore value {} is greater than the maximum supported value of {}.", initial_value, MAX_INITIAL_SEMAPHORE_VALUE);
494        }
495
496        let file_path =
497            FilePath::from_path_and_file(&Path::new(b"/").unwrap(), &self.name).unwrap();
498        Errno::reset();
499        self.handle = match mode {
500            InitMode::Create => unsafe {
501                msg = "Unable to create semaphore";
502                posix::sem_create(
503                    file_path.as_c_str(),
504                    posix::O_CREAT | posix::O_EXCL,
505                    permission.as_mode(),
506                    initial_value,
507                )
508            },
509            InitMode::Open | InitMode::TryOpen => unsafe {
510                msg = "Unable to open semaphore";
511                posix::sem_open(file_path.as_c_str(), 0)
512            },
513        };
514
515        if !core::ptr::eq(self.handle, posix::SEM_FAILED) {
516            match mode {
517                InitMode::Create => debug!(from self, "semaphore created."),
518                _ => debug!(from self, "semaphore opened."),
519            }
520            return Ok(());
521        }
522
523        let has_try_open_mode = mode == InitMode::TryOpen;
524        handle_errno!(NamedSemaphoreCreationError, from self,
525            success_when has_try_open_mode,
526                Errno::ENOENT => ((), DoesNotExist, "{} since the semaphore does not exist." ,msg),
527            Errno::EACCES => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
528            Errno::EEXIST => (AlreadyExists, "{} since the semaphore already exists.", msg),
529            Errno::EINTR => (Interrupt, "{} since an interrupt signal was received.", msg),
530            Errno::EINVAL => (NotSupportForGivenName, "{} since the operation is not supported for the given name.", msg),
531            Errno::EMFILE => (PerProcessFileHandleLimitReached, "{} since the current process already holds the maximum amount of semaphore or file descriptos.", msg),
532            Errno::ENAMETOOLONG => (MaxFilePathLengthExceeded, "{} since the name exceeds the maximum supported length.", msg),
533            Errno::ENFILE => (SystemWideFileHandleLimitReached, "{} since the system-wide semaphore or file-handle limit is reached.", msg),
534            Errno::ENOSPC => (NoSpaceLeft, "{} due to insufficient space on the target.", msg),
535            v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg,v)
536        );
537    }
538
539    /// Returns the name of the named semaphore
540    pub fn name(&self) -> &FileName {
541        &self.name
542    }
543}
544
545impl internal::SemaphoreHandle for NamedSemaphore {
546    fn handle(&self) -> *mut posix::sem_t {
547        self.handle
548    }
549
550    fn get_clock_type(&self) -> ClockType {
551        self.clock_type
552    }
553}
554
555impl SemaphoreInterface for NamedSemaphore {}
556
557/// Creates an [`UnnamedSemaphore`] which can be either used process locally or can be stored in a
558/// shared memory segment and then used during inter-process communication.
559///
560/// # Example
561///
562/// ```
563/// # extern crate iceoryx2_loggers;
564///
565/// use iceoryx2_bb_posix::semaphore::*;
566///
567/// let semaphore_handle = UnnamedSemaphoreHandle::new();
568/// let semaphore = UnnamedSemaphoreBuilder::new().initial_value(5)
569///                                               .is_interprocess_capable(false)
570///                                               .clock_type(ClockType::Monotonic)
571///                                               .create(&semaphore_handle)
572///                                               .expect("failed to create unnamed semaphore");
573/// ```
574#[derive(Debug)]
575pub struct UnnamedSemaphoreBuilder {
576    clock_type: ClockType,
577    is_interprocess_capable: bool,
578    initial_value: u32,
579}
580
581impl Default for UnnamedSemaphoreBuilder {
582    fn default() -> Self {
583        UnnamedSemaphoreBuilder {
584            clock_type: ClockType::default(),
585            is_interprocess_capable: true,
586            initial_value: 0,
587        }
588    }
589}
590
591impl UnnamedSemaphoreBuilder {
592    pub fn new() -> UnnamedSemaphoreBuilder {
593        Self::default()
594    }
595
596    /// Sets the initial value of the semaphore. Must be less than [`MAX_INITIAL_SEMAPHORE_VALUE`].
597    pub fn initial_value(mut self, value: u32) -> Self {
598        self.initial_value = value;
599        self
600    }
601
602    /// Defines if the [`UnnamedSemaphore`] can be used in an inter-process communication context.
603    pub fn is_interprocess_capable(mut self, value: bool) -> Self {
604        self.is_interprocess_capable = value;
605        self
606    }
607
608    /// Sets the type of clock which will be used in [`SemaphoreInterface::timed_wait()`]. Be
609    /// aware a clock like [`ClockType::Realtime`] is depending on the systems local time. If this
610    /// time changes while waiting it can cause extrem long waits or no wait at all.
611    pub fn clock_type(mut self, value: ClockType) -> Self {
612        self.clock_type = value;
613        self
614    }
615
616    fn initialize_semaphore(
617        &self,
618        sem: *mut posix::sem_t,
619    ) -> Result<Capability, UnnamedSemaphoreCreationError> {
620        let msg = "Unable to create semaphore";
621
622        if self.initial_value > MAX_INITIAL_SEMAPHORE_VALUE {
623            fail!(from self, with UnnamedSemaphoreCreationError::InitialValueTooLarge,
624                "{} since the initial value {} is too large.", msg, self.initial_value);
625        }
626
627        if unsafe {
628            posix::sem_init(
629                sem,
630                if self.is_interprocess_capable { 1 } else { 0 },
631                self.initial_value,
632            )
633        } == -1
634        {
635            handle_errno!(UnnamedSemaphoreCreationError, from self,
636                Errno::EINVAL => (InitialValueTooLarge, "{} since the initial value {} is too large. Please verify posix configuration!", msg, self.initial_value),
637                Errno::ENOSPC => (ExceedsMaximumNumberOfSemaphores, "{} since it exceeds the maximum amount of semaphores {}.", msg, Limit::MaxNumberOfSemaphores.value()),
638                Errno::EPERM => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
639                v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
640            );
641        }
642
643        match self.is_interprocess_capable {
644            true => Ok(Capability::InterProcess),
645            false => Ok(Capability::ProcessLocal),
646        }
647    }
648
649    /// Creates an [`UnnamedSemaphore`].
650    pub fn create(
651        self,
652        handle: &UnnamedSemaphoreHandle,
653    ) -> Result<UnnamedSemaphore<'_>, UnnamedSemaphoreCreationError> {
654        unsafe {
655            handle
656                .handle
657                .initialize(|sem| self.initialize_semaphore(sem))?;
658        }
659
660        unsafe { *handle.clock_type.get() = self.clock_type };
661
662        Ok(UnnamedSemaphore::new(handle))
663    }
664}
665
666#[derive(Debug)]
667pub struct UnnamedSemaphoreHandle {
668    handle: HandleStorage<posix::sem_t>,
669    clock_type: UnsafeCell<ClockType>,
670}
671
672unsafe impl Send for UnnamedSemaphoreHandle {}
673unsafe impl Sync for UnnamedSemaphoreHandle {}
674
675impl Handle for UnnamedSemaphoreHandle {
676    fn new() -> Self {
677        Self {
678            handle: HandleStorage::new(posix::sem_t::new_zeroed()),
679            clock_type: UnsafeCell::new(ClockType::default()),
680        }
681    }
682
683    fn is_inter_process_capable(&self) -> bool {
684        self.handle.is_inter_process_capable()
685    }
686
687    fn is_initialized(&self) -> bool {
688        self.handle.is_initialized()
689    }
690}
691
692impl Drop for UnnamedSemaphoreHandle {
693    fn drop(&mut self) {
694        if self.handle.is_initialized() {
695            unsafe {
696                self.handle.cleanup(|sem| {
697                    if posix::sem_destroy(sem) != 0 {
698                        warn!(from self,
699                            "Unable to destroy unnamed semaphore. Was it already destroyed by another instance in another process?");
700                    }
701                });
702            };
703        }
704    }
705}
706
707/// An unnamed semaphore which can be used process locally or for inter-process triggers.
708///
709/// # Example
710///
711/// ```no_run
712/// # extern crate iceoryx2_loggers;
713///
714/// use iceoryx2_bb_posix::semaphore::*;
715/// use std::thread;
716/// use iceoryx2_bb_posix::clock::*;
717/// use core::time::Duration;
718///
719/// let semaphore_handle = UnnamedSemaphoreHandle::new();
720/// let semaphore = UnnamedSemaphoreBuilder::new().create(&semaphore_handle)
721///     .expect("failed to create semaphore");
722///
723/// thread::scope(|s| {
724///     s.spawn(|| {
725///         loop {
726///             semaphore.blocking_wait().expect("failed to wait on semaphore");
727///             println!("the thread was triggered");
728///         }
729///     });
730///
731///     loop {
732///         nanosleep(Duration::from_secs(1));
733///         println!("trigger thread");
734///         semaphore.post().expect("failed to trigger semaphore");
735///     }
736/// });
737/// ```
738#[derive(Debug)]
739pub struct UnnamedSemaphore<'a> {
740    handle: &'a UnnamedSemaphoreHandle,
741}
742
743unsafe impl Send for UnnamedSemaphore<'_> {}
744unsafe impl Sync for UnnamedSemaphore<'_> {}
745
746impl<'a> IpcConstructible<'a, UnnamedSemaphoreHandle> for UnnamedSemaphore<'a> {
747    fn new(handle: &'a UnnamedSemaphoreHandle) -> Self {
748        Self { handle }
749    }
750}
751
752impl<'a> IpcCapable<'a, UnnamedSemaphoreHandle> for UnnamedSemaphore<'a> {
753    fn is_interprocess_capable(&self) -> bool {
754        self.handle.is_inter_process_capable()
755    }
756}
757
758impl internal::SemaphoreHandle for UnnamedSemaphore<'_> {
759    fn handle(&self) -> *mut posix::sem_t {
760        unsafe { self.handle.handle.get() }
761    }
762
763    fn get_clock_type(&self) -> ClockType {
764        unsafe { *self.handle.clock_type.get() }
765    }
766}
767
768impl SemaphoreInterface for UnnamedSemaphore<'_> {}