diff --git a/.cirrus.yml b/.cirrus.yml index adc49c3f1..662357b05 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -269,15 +269,4 @@ macos_aarch64_stable_debug_task: - rustup component add clippy rustfmt set_toolchain_script: rustup default stable <<: *IOX2_CARGO_FMT_AND_CLIPPY - <<: *IOX2_COMMON_BUILD_DEBUG - test_script: - - cargo test -p iceoryx2-pal-concurrency-sync - -p iceoryx2-pal-posix - -p iceoryx2-bb-container - -p iceoryx2-bb-elementary - -p iceoryx2-bb-lock-free - -p iceoryx2-bb-log - -p iceoryx2-bb-memory - -p iceoryx2-bb-system-types - -p iceoryx2-bb-testing - --lib --bins --tests --no-fail-fast + <<: *IOX2_COMMON_BUILD_AND_TEST_DEBUG diff --git a/README.md b/README.md index 0497a3a64..3c6ba0a13 100644 --- a/README.md +++ b/README.md @@ -260,7 +260,7 @@ The support levels can be adjusted when required. | Linux (x86_64) | done | tier 2 | tier 1 | | Linux (aarch64) | done | tier 2 | tier 1 | | Linux (32-bit) | in-progress | tier 3 | tier 1 | -| Mac OS | in-progress | tier 3 | tier 2 | +| Mac OS | done | tier 2 | tier 2 | | QNX | planned | - | tier 1 | | WatchOS | planned | - | tier 2 | | Windows | done | tier 2 | tier 2 | diff --git a/ROADMAP.md b/ROADMAP.md index cbc16d9e9..bec0acf75 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -59,6 +59,7 @@ * [ ] Zero-copy GPU communication with Cuda, NvSci, Vulkan * [ ] Zero-copy across hypervisor partitions * [ ] Zero-copy via QEMU ivshmem: +* [ ] dmabuf support, see: https://blaztinn.gitlab.io/post/dmabuf-texture-sharing/ * [ ] Support dynamic sized types in a memory efficient manner * Buddy allocator for sender data-segment * Introduce runtime fixed-size types @@ -128,3 +129,7 @@ * simple use case: pub/sub + event to notify subscriber to notify sample send * would reduce error handling: connect to service with wrong messaging pattern * [ ] Implement Resizable SharedMemoryConcept that is able to extend the shared memory by adding additional posix shared memory objects + +## Integration Into Other Projects + +* [ ] Maybe Hyprland diff --git a/doc/release-notes/iceoryx2-unreleased.md b/doc/release-notes/iceoryx2-unreleased.md index c80cdf1ce..e8a510de1 100644 --- a/doc/release-notes/iceoryx2-unreleased.md +++ b/doc/release-notes/iceoryx2-unreleased.md @@ -1,28 +1,28 @@ # iceoryx2 v?.?.? -## [vx.x.x](https://github.com/larry-robotics/iceoryx2/tree/vx.x.x) (xxxx-xx-xx) +## [vx.x.x](https://github.com/eclipse-iceoryx/iceoryx2/tree/vx.x.x) (xxxx-xx-xx) -[Full Changelog](https://github.com/larry-robotics/iceoryx2/compare/vx.x.x...vx.x.x) +[Full Changelog](https://github.com/eclipse-iceoryx/iceoryx2/compare/vx.x.x...vx.x.x) ### Features - * Example [#1](https://github.com/larry-robotics/iceoryx2/issues/1) + * MacOS Platform support [#51](https://github.com/eclipse-iceoryx/iceoryx2/issues/51) ### Bugfixes - * Example [#1](https://github.com/larry-robotics/iceoryx2/issues/1) + * Example [#1](https://github.com/eclipse-iceoryx/iceoryx2/issues/1) ### Refactoring - * Example [#1](https://github.com/larry-robotics/iceoryx2/issues/1) + * Example [#1](https://github.com/eclipse-iceoryx/iceoryx2/issues/1) ### Workflow - * Example [#1](https://github.com/larry-robotics/iceoryx2/issues/1) + * Example [#1](https://github.com/eclipse-iceoryx/iceoryx2/issues/1) ### New API features - * Example [#1](https://github.com/larry-robotics/iceoryx2/issues/1) + * Example [#1](https://github.com/eclipse-iceoryx/iceoryx2/issues/1) ### API Breaking Changes diff --git a/iceoryx2-bb/posix/src/condition_variable.rs b/iceoryx2-bb/posix/src/condition_variable.rs index f84f35fc3..47420edd8 100644 --- a/iceoryx2-bb/posix/src/condition_variable.rs +++ b/iceoryx2-bb/posix/src/condition_variable.rs @@ -153,7 +153,7 @@ impl<'mutex, 'handle, T: Debug> From> /// use iceoryx2_bb_posix::mutex::*; /// /// -/// // create a condition variable which allows multiple predicates in wait_while nad +/// // create a condition variable which allows multiple predicates in blocking_wait_while nad /// // timed_wait_while /// let mtx_handle = MutexHandle::::new(); /// let condvar = ConditionVariableBuilder::new() @@ -237,7 +237,7 @@ impl ConditionVariableBuilder { /// modified and used for triggering. /// /// The condition variable can use - /// multiple conditions in [`MultiConditionVariable::wait_while()`] and + /// multiple conditions in [`MultiConditionVariable::blocking_wait_while()`] and /// [`MultiConditionVariable::timed_wait_while()`] but is only able to trigger all waiters. pub fn create_multi_condition_variable( self, @@ -252,7 +252,7 @@ impl ConditionVariableBuilder { /// /// The condition variable has one fixed /// condition which has to be provided on construction. The methods - /// [`ConditionVariable::wait_while()`] and + /// [`ConditionVariable::blocking_wait_while()`] and /// [`ConditionVariable::timed_wait_while()`] will wait on that preset condition until /// it is satisfied. /// The restriction to a preset fixed condition comes with the feature to signal single waiters @@ -489,7 +489,7 @@ pub trait BasicConditionVariableInterface: } /// Condition variable which allows to use multiple conditions in -/// [`MultiConditionVariable::wait_while()`] and +/// [`MultiConditionVariable::blocking_wait_while()`] and /// [`MultiConditionVariable::timed_wait_while()`] concurrently but with the draw /// back that only all waiters can be triggered and not one. /// The reason is when one waits on multiple @@ -505,7 +505,7 @@ pub trait BasicConditionVariableInterface: /// is written. /// The condition variable provides the following features: /// * wait on the condition variable: [wait](BasicConditionVariableInterface::wait()), [timed_wait](BasicConditionVariableInterface::timed_wait()) -/// * wait until a defined condition occurs: [wait_while](MultiConditionVariable::wait_while()), [timed_wait_while](MultiConditionVariable::timed_wait_while()) +/// * wait until a defined condition occurs: [blocking_wait_while](MultiConditionVariable::blocking_wait_while()), [timed_wait_while](MultiConditionVariable::timed_wait_while()) /// * modify condition variable and then notify waiters: /// [notify_all](MultiConditionVariable::notify_all()), [modify_notify_all](MultiConditionVariable::modify_notify_all()) /// * trigger waiters without changing condition variable: [trigger_all](BasicConditionVariableInterface::trigger_all()) @@ -530,7 +530,7 @@ pub trait BasicConditionVariableInterface: /// thread::scope(|s| { /// let t1 = s.spawn(|| { /// // wait until value is 5000 -/// let guard = cv.wait_while(|t| *t == 5000).expect("failed to wait"); +/// let guard = cv.blocking_wait_while(|t| *t == 5000).expect("failed to wait"); /// println!("cv value changed to 5000"); /// }); /// @@ -589,12 +589,11 @@ impl<'mtx_handle, T: Debug> MultiConditionVariable<'mtx_handle, T> { /// [`MultiConditionVariable::modify_notify_all()`] or /// [`BasicConditionVariableInterface::trigger_all()`] /// and the provided predicate returns true. - pub fn wait_while bool>( + pub fn blocking_wait_while bool>( &self, mut predicate: P, ) -> Result, ConditionVariableWaitError<'_, '_, T>> { - let mut guard = - fail!(from self, when self.mutex.lock(), "Failed to lock mutex in wait_while."); + let mut guard = fail!(from self, when self.mutex.lock(), "Failed to lock mutex in blocking_wait_while."); while !(predicate)(&mut *guard) { self.condvar.pthread_wait(&self.mutex)?; @@ -742,7 +741,7 @@ impl Drop for ConditionVariableGuard<'_, '_, '_, T> { } /// Condition variable which requires a fixed predicate on creation which is then used in -/// [`ConditionVariable::wait_while()`] and +/// [`ConditionVariable::blocking_wait_while()`] and /// [`ConditionVariable::timed_wait_while()`] concurrently with the benefit of triggering /// single waiters. /// The reason is when one waits on multiple @@ -758,7 +757,7 @@ impl Drop for ConditionVariableGuard<'_, '_, '_, T> { /// is written. /// The condition variable provides the following features: /// * wait on the condition variable: [wait](BasicConditionVariableInterface::wait()), [timed_wait](BasicConditionVariableInterface::timed_wait()) -/// * wait until a defined condition occurs: [wait_while](ConditionVariable::wait_while()), [timed_wait_while](ConditionVariable::timed_wait_while()) +/// * wait until a defined condition occurs: [blocking_wait_while](ConditionVariable::blocking_wait_while()), [timed_wait_while](ConditionVariable::timed_wait_while()) /// * modify condition variable and then notify waiters: /// [notify_all](ConditionVariable::notify_all()), [modify_notify_all](ConditionVariable::modify_notify_all()), /// [notify_one](ConditionVariable::notify_one()), [modify_notify_one](ConditionVariable::modify_notify_one()) @@ -786,7 +785,7 @@ impl Drop for ConditionVariableGuard<'_, '_, '_, T> { /// thread::scope(|s| { /// let t1 = s.spawn(|| { /// // wait until value is 5000 -/// let guard = cv.wait_while().expect("failed to wait"); +/// let guard = cv.blocking_wait_while().expect("failed to wait"); /// println!("cv value is greater or equal 5000"); /// }); /// @@ -856,13 +855,14 @@ impl<'mtx_handle, T: Debug> ConditionVariable<'mtx_handle, T> { /// [`BasicConditionVariableInterface::trigger_all()`] or /// [`ConditionVariable::trigger_one()`] /// and the provided predicate returns true. - pub fn wait_while( + pub fn blocking_wait_while( &self, ) -> Result< MutexGuard<'_, '_, ConditionVariableData>, ConditionVariableWaitError<'_, '_, ConditionVariableData>, > { - let guard = fail!(from self, when self.mutex.lock(), "failed to lock mutex in wait_while"); + let guard = + fail!(from self, when self.mutex.lock(), "failed to lock mutex in blocking_wait_while"); while !self.call_underlying_predicate(&guard) { self.condvar.pthread_wait(&self.mutex)?; diff --git a/iceoryx2-bb/posix/src/thread.rs b/iceoryx2-bb/posix/src/thread.rs index 3d42d645c..309dd96d2 100644 --- a/iceoryx2-bb/posix/src/thread.rs +++ b/iceoryx2-bb/posix/src/thread.rs @@ -48,7 +48,7 @@ //! //! ## Create a highly customized thread with guarded stack //! -//! ``` +//! ```ignore //! use iceoryx2_bb_posix::thread::*; //! use iceoryx2_bb_posix::scheduler::*; //! use iceoryx2_bb_posix::system_configuration::*; diff --git a/iceoryx2-bb/posix/tests/condition_variable_tests.rs b/iceoryx2-bb/posix/tests/condition_variable_tests.rs index b48099683..fd9d78647 100644 --- a/iceoryx2-bb/posix/tests/condition_variable_tests.rs +++ b/iceoryx2-bb/posix/tests/condition_variable_tests.rs @@ -12,13 +12,14 @@ use iceoryx2_bb_posix::condition_variable::*; use iceoryx2_bb_testing::assert_that; +use iceoryx2_bb_testing::watchdog::Watchdog; use std::sync::atomic::{AtomicI32, Ordering}; use std::sync::Arc; use std::thread; use std::time::Duration; use std::time::Instant; -static TIMEOUT: Duration = Duration::from_millis(10); +static TIMEOUT: Duration = Duration::from_millis(100); #[test] fn multi_condition_variable_construction_works() { @@ -48,7 +49,7 @@ fn multi_condition_variable_wait_while_is_signalled_by_notify_all() { thread::scope(|s| { let t1 = s.spawn(|| { - let guard = sut.wait_while(|t| *t == 4456).unwrap(); + let guard = sut.blocking_wait_while(|t| *t == 4456).unwrap(); assert_that!(*guard, eq 4456); }); @@ -77,7 +78,7 @@ fn multi_condition_variable_wait_while_is_signalled_by_modify_notify_all() { thread::scope(|s| { let t1 = s.spawn(|| { - let guard = sut.wait_while(|t| *t == 4456).unwrap(); + let guard = sut.blocking_wait_while(|t| *t == 4456).unwrap(); assert_that!(*guard, eq 4456); }); @@ -253,14 +254,14 @@ fn condition_variable_notify_all_signals_all_waiters() { let sut_thread1 = Arc::clone(&sut); let counter_thread1 = Arc::clone(&counter); let t1 = s.spawn(move || { - sut_thread1.wait_while().unwrap(); + sut_thread1.blocking_wait_while().unwrap(); counter_thread1.fetch_add(1, Ordering::Relaxed); }); let sut_thread2 = Arc::clone(&sut); let counter_thread2 = Arc::clone(&counter); let t2 = s.spawn(move || { - sut_thread2.wait_while().unwrap(); + sut_thread2.blocking_wait_while().unwrap(); counter_thread2.fetch_add(1, Ordering::Relaxed); }); @@ -299,14 +300,14 @@ fn condition_variable_notify_one_signals_one_waiter() { let sut_thread1 = Arc::clone(&sut); let counter_thread1 = Arc::clone(&counter); let t1 = s.spawn(move || { - sut_thread1.wait_while().unwrap(); + sut_thread1.blocking_wait_while().unwrap(); counter_thread1.fetch_add(1, Ordering::Relaxed); }); let sut_thread2 = Arc::clone(&sut); let counter_thread2 = Arc::clone(&counter); let t2 = s.spawn(move || { - sut_thread2.wait_while().unwrap(); + sut_thread2.blocking_wait_while().unwrap(); counter_thread2.fetch_add(1, Ordering::Relaxed); }); @@ -369,6 +370,7 @@ fn condition_variable_modify_notify_all_signals_all_waiters() { #[test] fn condition_variable_modify_notify_one_signals_one_waiter() { + let _watchdog = Watchdog::new(Duration::from_secs(10)); let handle = MutexHandle::>::new(); thread::scope(|s| { let counter = Arc::new(AtomicI32::new(0)); @@ -381,14 +383,14 @@ fn condition_variable_modify_notify_one_signals_one_waiter() { let sut_thread1 = Arc::clone(&sut); let counter_thread1 = Arc::clone(&counter); let t1 = s.spawn(move || { - sut_thread1.timed_wait_while(TIMEOUT * 10).unwrap(); + sut_thread1.blocking_wait_while().unwrap(); counter_thread1.fetch_add(1, Ordering::Relaxed); }); let sut_thread2 = Arc::clone(&sut); let counter_thread2 = Arc::clone(&counter); let t2 = s.spawn(move || { - sut_thread2.timed_wait_while(TIMEOUT * 10).unwrap(); + sut_thread2.blocking_wait_while().unwrap(); counter_thread2.fetch_add(1, Ordering::Relaxed); }); @@ -396,6 +398,8 @@ fn condition_variable_modify_notify_one_signals_one_waiter() { let counter_old_1 = counter.load(Ordering::Relaxed); sut.modify_notify_one(|value| *value = 2213).unwrap(); + while counter.load(Ordering::Relaxed) == 0 {} + thread::sleep(TIMEOUT); let counter_old_2 = counter.load(Ordering::Relaxed); sut.modify_notify_one(|value| *value = 2213).unwrap(); @@ -462,5 +466,5 @@ fn condition_variable_wait_while_does_not_wait_when_predicate_is_fulfilled() { ); sut.lock().unwrap().value = 9999999; - assert_that!(sut.wait_while(), is_ok); + assert_that!(sut.blocking_wait_while(), is_ok); } diff --git a/iceoryx2-bb/posix/tests/mutex_tests.rs b/iceoryx2-bb/posix/tests/mutex_tests.rs index b72a5ae32..9b15f3b56 100644 --- a/iceoryx2-bb/posix/tests/mutex_tests.rs +++ b/iceoryx2-bb/posix/tests/mutex_tests.rs @@ -16,12 +16,13 @@ use iceoryx2_bb_posix::system_configuration::Feature; use iceoryx2_bb_posix::unmovable_ipc_handle::AcquireIpcHandleError; use iceoryx2_bb_testing::assert_that; use iceoryx2_bb_testing::test_requires; +use iceoryx2_bb_testing::watchdog::Watchdog; use std::sync::Arc; use std::sync::Barrier; use std::thread; use std::time::Duration; -const TIMEOUT: Duration = Duration::from_millis(50); +const TIMEOUT: Duration = Duration::from_millis(100); #[test] fn mutex_lock_works() { @@ -389,6 +390,7 @@ fn mutex_with_deadlock_detection_blocks() { #[test] fn mutex_can_be_recovered_when_thread_died() { + let _watchdog = Watchdog::new(Duration::from_secs(10)); let handle = MutexHandle::::new(); let sut = MutexBuilder::new() .thread_termination_behavior(MutexThreadTerminationBehavior::ReleaseWhenLocked) @@ -429,6 +431,7 @@ fn mutex_can_be_recovered_when_thread_died() { #[test] fn mutex_in_unrecoverable_state_if_state_of_leaked_mutex_is_not_repaired() { + let _watchdog = Watchdog::new(Duration::from_secs(10)); let handle = MutexHandle::::new(); let sut = MutexBuilder::new() .thread_termination_behavior(MutexThreadTerminationBehavior::ReleaseWhenLocked) diff --git a/iceoryx2-bb/posix/tests/shared_memory_tests.rs b/iceoryx2-bb/posix/tests/shared_memory_tests.rs index 96a6bca98..b4327290f 100644 --- a/iceoryx2-bb/posix/tests/shared_memory_tests.rs +++ b/iceoryx2-bb/posix/tests/shared_memory_tests.rs @@ -18,7 +18,7 @@ use iceoryx2_bb_testing::{assert_that, test_requires}; use iceoryx2_pal_posix::posix::POSIX_SUPPORT_PERSISTENT_SHARED_MEMORY; fn generate_shm_name() -> FileName { - let mut file_name = FileName::new(b"shm_tests_").unwrap(); + let mut file_name = FileName::new(b"shared_memory_tests_").unwrap(); file_name .push_bytes(UniqueSystemId::new().unwrap().value().to_b64().as_bytes()) .unwrap(); @@ -92,7 +92,7 @@ fn shared_memory_create_and_modify_open_works() { #[test] fn shared_memory_opening_with_non_fitting_size_fails() { let shm_name = generate_shm_name(); - let _sut_create = SharedMemoryBuilder::new(&shm_name) + let sut_create = SharedMemoryBuilder::new(&shm_name) .creation_mode(CreationMode::PurgeAndCreate) .size(1024) .permission(Permission::OWNER_ALL) @@ -102,14 +102,14 @@ fn shared_memory_opening_with_non_fitting_size_fails() { let sut_open1 = SharedMemoryBuilder::new(&shm_name) .creation_mode(CreationMode::OpenOrCreate) - .size(8192) + .size(sut_create.size() + 1) .permission(Permission::OWNER_ALL) .zero_memory(true) .create(); let sut_open2 = SharedMemoryBuilder::new(&shm_name) .creation_mode(CreationMode::OpenOrCreate) - .size(16384) + .size(sut_create.size() * 2) .permission(Permission::OWNER_ALL) .zero_memory(true) .create(); diff --git a/iceoryx2-bb/threadsafe/tests/trigger_queue_tests.rs b/iceoryx2-bb/threadsafe/tests/trigger_queue_tests.rs index 7513b3488..6ef9f9aa1 100644 --- a/iceoryx2-bb/threadsafe/tests/trigger_queue_tests.rs +++ b/iceoryx2-bb/threadsafe/tests/trigger_queue_tests.rs @@ -17,9 +17,10 @@ use std::time::Duration; use iceoryx2_bb_posix::clock::{nanosleep, Time}; use iceoryx2_bb_posix::mutex::MutexHandle; use iceoryx2_bb_testing::assert_that; +use iceoryx2_bb_testing::watchdog::Watchdog; use iceoryx2_bb_threadsafe::trigger_queue::*; -const TIMEOUT: Duration = Duration::from_millis(25); +const TIMEOUT: Duration = Duration::from_millis(100); const SUT_CAPACITY: usize = 128; type Sut<'a> = TriggerQueue<'a, usize, SUT_CAPACITY>; @@ -153,6 +154,7 @@ fn trigger_queue_blocking_push_blocks_until_there_is_space_again() { let mtx_handle = MutexHandle::new(); let free_handle = UnnamedSemaphoreHandle::new(); let used_handle = UnnamedSemaphoreHandle::new(); + let _watchdog = Watchdog::new(Duration::from_secs(10)); let sut = Sut::new(&mtx_handle, &free_handle, &used_handle); @@ -170,10 +172,11 @@ fn trigger_queue_blocking_push_blocks_until_there_is_space_again() { nanosleep(TIMEOUT).unwrap(); let counter_old = counter.load(Ordering::Relaxed); sut.blocking_pop(); - nanosleep(TIMEOUT).unwrap(); assert_that!(counter_old, eq 0); - assert_that!(counter.load(Ordering::Relaxed), eq 1); + + // if the thread is not unblocked the counter stays zero until the watchdog intervenes + while counter.load(Ordering::Relaxed) == 0 {} }); } @@ -182,6 +185,7 @@ fn trigger_queue_blocking_pop_blocks_until_there_is_something_pushed() { let mtx_handle = MutexHandle::new(); let free_handle = UnnamedSemaphoreHandle::new(); let used_handle = UnnamedSemaphoreHandle::new(); + let _watchdog = Watchdog::new(Duration::from_secs(10)); let sut = Sut::new(&mtx_handle, &free_handle, &used_handle); @@ -196,10 +200,11 @@ fn trigger_queue_blocking_pop_blocks_until_there_is_something_pushed() { nanosleep(TIMEOUT).unwrap(); let counter_old = counter.load(Ordering::Relaxed); sut.blocking_push(0); - nanosleep(TIMEOUT).unwrap(); assert_that!(counter_old, eq 0); - assert_that!(counter.load(Ordering::Relaxed), eq 1); + + // if the thread is not unblocked the counter stays zero until the watchdog intervenes + while counter.load(Ordering::Relaxed) == 0 {} }); } diff --git a/iceoryx2-cal/src/event/process_local.rs b/iceoryx2-cal/src/event/process_local.rs index 06955425f..d9f839191 100644 --- a/iceoryx2-cal/src/event/process_local.rs +++ b/iceoryx2-cal/src/event/process_local.rs @@ -193,7 +193,7 @@ impl Listener for Duplex { fn blocking_wait(&self) -> Result, ListenerWaitError> { let msg = "Failed to blocking_wait"; - match self.management.as_ref().borrow_cvar().wait_while() { + match self.management.as_ref().borrow_cvar().blocking_wait_while() { Err(v) => { fail!(from self, with ListenerWaitError::InternalFailure, "{} due to an internal failure in the underlying condition variable ({:?}).", msg, v); diff --git a/iceoryx2-pal/concurrency-sync/tests/condition_variable_tests.rs b/iceoryx2-pal/concurrency-sync/tests/condition_variable_tests.rs index 40694a165..0b7f48f1c 100644 --- a/iceoryx2-pal/concurrency-sync/tests/condition_variable_tests.rs +++ b/iceoryx2-pal/concurrency-sync/tests/condition_variable_tests.rs @@ -49,13 +49,13 @@ impl ThreadInWait { loop { let mut wait_for_thread = false; for v in &self.thread_in_wait { - if v.load(Ordering::Relaxed) == false { + if !v.load(Ordering::Relaxed) { wait_for_thread = true; break; } } - if wait_for_thread == false { + if !wait_for_thread { break; } } diff --git a/iceoryx2-pal/posix/src/macos/mman.rs b/iceoryx2-pal/posix/src/macos/mman.rs index 44573a83b..49361a96d 100644 --- a/iceoryx2-pal/posix/src/macos/mman.rs +++ b/iceoryx2-pal/posix/src/macos/mman.rs @@ -13,6 +13,8 @@ #![allow(non_camel_case_types)] #![allow(clippy::missing_safety_doc)] +use std::io::Write; + use iceoryx2_pal_configuration::PATH_SEPARATOR; use crate::posix::*; @@ -22,6 +24,8 @@ use super::{ settings::{MAX_PATH_LENGTH, SHM_STATE_DIRECTORY, SHM_STATE_SUFFIX}, }; +const SHM_MAX_NAME_LEN: usize = 33; + pub unsafe fn mlock(addr: *const void, len: size_t) -> int { crate::internal::mlock(addr, len) } @@ -74,23 +78,102 @@ unsafe fn shm_file_path(name: *const char, suffix: &[u8]) -> [u8; MAX_PATH_LENGT state_file_path } +unsafe fn get_real_shm_name(name: *const char) -> Option<[u8; SHM_MAX_NAME_LEN]> { + let shm_file_path = shm_file_path(name, SHM_STATE_SUFFIX); + let shm_state_fd = open_with_mode(shm_file_path.as_ptr().cast(), O_RDONLY, 0); + if shm_state_fd == -1 { + return None; + } + + let mut buffer = [0u8; SHM_MAX_NAME_LEN]; + + if read( + shm_state_fd, + buffer.as_mut_ptr().cast(), + SHM_MAX_NAME_LEN - 1, + ) <= 0 + { + close(shm_state_fd); + return None; + } + + close(shm_state_fd); + Some(buffer) +} + +unsafe fn write_real_shm_name(name: *const char, buffer: &[u8]) -> bool { + let shm_file_path = shm_file_path(name, SHM_STATE_SUFFIX); + let shm_state_fd = open_with_mode( + shm_file_path.as_ptr().cast(), + O_EXCL | O_CREAT | O_RDWR, + S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, + ); + + if shm_state_fd == -1 { + return false; + } + + if write(shm_state_fd, buffer.as_ptr().cast(), buffer.len()) != buffer.len() as _ { + remove(shm_file_path.as_ptr().cast()); + close(shm_state_fd); + return false; + } + + close(shm_state_fd); + true +} + +unsafe fn generate_real_shm_name() -> [u8; SHM_MAX_NAME_LEN] { + let mut now = timespec::new(); + clock_gettime(CLOCK_REALTIME, &mut now); + let pid = getpid(); + let shm_name = pid.to_string() + "_" + &now.tv_sec.to_string() + "_" + &now.tv_nsec.to_string(); + + let mut buffer = [0u8; SHM_MAX_NAME_LEN]; + buffer.as_mut_slice().write_all(shm_name.as_bytes()).expect( + "always works since 3 32-bit numbers and 2 underscores do not use more than 33 characters", + ); + buffer +} + pub unsafe fn shm_open(name: *const char, oflag: int, mode: mode_t) -> int { - let ret_val = crate::internal::shm_open(name, oflag, mode as uint); - if ret_val != -1 { - let shm_file_path = shm_file_path(name, SHM_STATE_SUFFIX); + let real_name = get_real_shm_name(name); + if oflag & O_EXCL != 0 && real_name.is_some() { + Errno::set(Errno::EEXIST); + return -1; + } - if open_with_mode(shm_file_path.as_ptr().cast(), O_CREAT | O_RDONLY, mode) == -1 { - close(ret_val); - return -1; + let real_name = match real_name { + Some(name) => name, + None => { + if oflag & O_CREAT == 0 { + Errno::set(Errno::ENOENT); + return -1; + } + let real_name = generate_real_shm_name(); + if !write_real_shm_name(name, &real_name) { + return -1; + } + real_name } - } + }; - ret_val + crate::internal::shm_open(real_name.as_ptr().cast(), oflag, mode as uint) } pub unsafe fn shm_unlink(name: *const char) -> int { - remove(shm_file_path(name, SHM_STATE_SUFFIX).as_ptr().cast()); - crate::internal::shm_unlink(name) + let real_name = get_real_shm_name(name); + + if let Some(real_name) = real_name { + let ret_val = crate::internal::shm_unlink(real_name.as_ptr().cast()); + if ret_val == 0 || (ret_val == -1 && Errno::get() == Errno::ENOENT) { + remove(shm_file_path(name, SHM_STATE_SUFFIX).as_ptr().cast()); + } + return ret_val; + } + + Errno::set(Errno::ENOENT); + -1 } pub unsafe fn mmap( diff --git a/iceoryx2/tests/service_publish_subscribe_tests.rs b/iceoryx2/tests/service_publish_subscribe_tests.rs index 0392644fd..f235e7cbd 100644 --- a/iceoryx2/tests/service_publish_subscribe_tests.rs +++ b/iceoryx2/tests/service_publish_subscribe_tests.rs @@ -864,7 +864,7 @@ mod service_publish_subscribe { const BUFFER_SIZE: usize = 1; const HISTORY_SIZE: usize = 0; const MAX_BORROW: usize = 1; - const MAX_SUBSCRIBERS: usize = 100; + const MAX_SUBSCRIBERS: usize = 50; const MAX_LOAN: usize = 1; publisher_never_goes_out_of_memory_impl::( @@ -929,11 +929,11 @@ mod service_publish_subscribe { #[test] fn publisher_never_goes_out_of_memory_with_huge_values() { - const BUFFER_SIZE: usize = 129; - const HISTORY_SIZE: usize = 131; - const MAX_BORROW: usize = 112; - const MAX_SUBSCRIBERS: usize = 123; - const MAX_LOAN: usize = 135; + const BUFFER_SIZE: usize = 29; + const HISTORY_SIZE: usize = 31; + const MAX_BORROW: usize = 12; + const MAX_SUBSCRIBERS: usize = 25; + const MAX_LOAN: usize = 35; publisher_never_goes_out_of_memory_impl::( BUFFER_SIZE,