1pub 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 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
133pub trait SemaphoreInterface: internal::SemaphoreHandle + Debug {
135 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 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 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 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#[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 pub fn clock_type(mut self, value: ClockType) -> Self {
297 self.clock_type = value;
298 self
299 }
300
301 pub fn open_existing(self) -> Result<NamedSemaphore, NamedSemaphoreCreationError> {
303 NamedSemaphore::new(self)
304 }
305
306 pub fn creation_mode(mut self, creation_mode: CreationMode) -> NamedSemaphoreCreationBuilder {
309 self.creation_mode = Some(creation_mode);
310 NamedSemaphoreCreationBuilder { config: self }
311 }
312}
313
314pub struct NamedSemaphoreCreationBuilder {
319 config: NamedSemaphoreBuilder,
320}
321
322impl NamedSemaphoreCreationBuilder {
323 pub fn initial_value(mut self, value: u32) -> Self {
325 self.config.initial_value = value;
326 self
327 }
328
329 pub fn permission(mut self, value: Permission) -> Self {
331 self.config.permission = value;
332 self
333 }
334
335 pub fn create(self) -> Result<NamedSemaphore, NamedSemaphoreCreationError> {
337 NamedSemaphore::new(self.config)
338 }
339}
340
341#[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 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#[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 pub fn initial_value(mut self, value: u32) -> Self {
589 self.initial_value = value;
590 self
591 }
592
593 pub fn is_interprocess_capable(mut self, value: bool) -> Self {
595 self.is_interprocess_capable = value;
596 self
597 }
598
599 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 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#[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<'_> {}