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