1pub 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 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
132pub trait SemaphoreInterface: internal::SemaphoreHandle + Debug {
134 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 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 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 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#[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 pub fn clock_type(mut self, value: ClockType) -> Self {
300 self.clock_type = value;
301 self
302 }
303
304 pub fn open_existing(self) -> Result<NamedSemaphore, NamedSemaphoreCreationError> {
306 NamedSemaphore::new(self)
307 }
308
309 pub fn creation_mode(mut self, creation_mode: CreationMode) -> NamedSemaphoreCreationBuilder {
312 self.creation_mode = Some(creation_mode);
313 NamedSemaphoreCreationBuilder { config: self }
314 }
315}
316
317pub struct NamedSemaphoreCreationBuilder {
322 config: NamedSemaphoreBuilder,
323}
324
325impl NamedSemaphoreCreationBuilder {
326 pub fn initial_value(mut self, value: u32) -> Self {
328 self.config.initial_value = value;
329 self
330 }
331
332 pub fn permission(mut self, value: Permission) -> Self {
334 self.config.permission = value;
335 self
336 }
337
338 pub fn create(self) -> Result<NamedSemaphore, NamedSemaphoreCreationError> {
340 NamedSemaphore::new(self.config)
341 }
342}
343
344#[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 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#[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 pub fn initial_value(mut self, value: u32) -> Self {
598 self.initial_value = value;
599 self
600 }
601
602 pub fn is_interprocess_capable(mut self, value: bool) -> Self {
604 self.is_interprocess_capable = value;
605 self
606 }
607
608 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 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#[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<'_> {}