diff --git a/.cirrus.yml b/.cirrus.yml index fd2b7d838..a5154d4c5 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -271,15 +271,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/CONTRIBUTING.md b/CONTRIBUTING.md index e69de29bb..c56d93e98 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -0,0 +1,45 @@ +# Contributing to Eclipse iceoryx2 + + 1. Every new contributor must sign the + [Eclipse Contributor Agreement (ECA)](https://www.eclipse.org/legal/ECA.php) + first. + 2. Before you start to work, please create an issue first. + 3. Create a branch with the prefix `iox2-$ISSUE_NUMBER$`. + 4. Every file requires this copyright header. + + ``` + // Copyright (c) 2023 Contributors to the Eclipse Foundation + // + // See the NOTICE file(s) distributed with this work for additional + // information regarding copyright ownership. + // + // This program and the accompanying materials are made available under the + // terms of the Apache Software License 2.0 which is available at + // https://www.apache.org/licenses/LICENSE-2.0, or the MIT license + // which is available at https://opensource.org/licenses/MIT. + // + // SPDX-License-Identifier: Apache-2.0 OR MIT + ``` + + 5. Every commit must have the prefix `[#$ISSUE_NUMBER$]`. + 6. When the work is done, please add your changes to the release notes in + `doc/release-notes/iceoryx2-unreleased.md`. + 7. Create a pull request. + 8. (optional) If you are a new contributor we would love to show our gratitude + for your support so please add yourself at the end of `README.md`. + The entry template looks like this: + + ```html + + + $FIRST_NAME$ »$COOL_NICK_NAME$« $LAST_NAME$
+ $FIRST_NAME$ »$COOL_NICK_NAME$« $LAST_NAME$
+ ``` + + **Notes:** + * The `$FIRST_NAME »$COOL_NICK_NAME$« $LAST_NAME$` is a suggestion but it can + be whatever you feel comfortable with. + * You can obtain the ID of your profile picture by clicking on your profile + icon on the top right, selecting `Your profile` and then right-clicking on + your profile picture and selecting `Copy image address`. The last number in + the URL is the ID of your profile picture. 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..12b4e5fd5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -7,6 +7,19 @@ * [ ] `#![no_std]` on `stable` on all tier 1 platforms * [ ] completely dynamic setup with dynamic shared memory +## Shared Memory Container & Types + +* [ ] Make `iceoryx2_bb_container` public with announcement +* [ ] Create and document dynamic size container concept for shared memory and apply it + to all existing containers: `ByteString`, `Vec`, `Queue` + * Open Question: How can these containers be cloned, copied? +* [ ] Introduce additional containers: `HashMap`, `Tree`, `Set`, `List` +* [ ] Introduce elementary types, look into: `simple-si-units` crate + * Add types like: memory size, percentage, strict percentage (0..100), data throughput, resolution + (further types found in informatics) +* [ ] Add `derive` proc macro to ensure that only shm compatible types can be + transferred via zero-copy + ## Language Bindings * [ ] C @@ -59,6 +72,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 @@ -77,7 +91,7 @@ * [ ] Android * [x] Linux * [x] Windows -* [ ] Mac Os +* [x] Mac Os * [ ] iOS * [ ] WatchOS * [x] FreeBSD @@ -128,3 +142,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 c21667e6c..2632b3cb0 100644 --- a/doc/release-notes/iceoryx2-unreleased.md +++ b/doc/release-notes/iceoryx2-unreleased.md @@ -1,20 +1,22 @@ # 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) + * Services with the same name for different messaging patterns are supported [#16](https://github.com/eclipse-iceoryx/iceoryx2/issues/16) ### Bugfixes - * Example [#1](https://github.com/larry-robotics/iceoryx2/issues/1) + * Fix undefined behavior in `FixedSizeByteString::new_unchecked` [#61](https://github.com/eclipse-iceoryx/iceoryx2/issues/61) + * Fix suffix of static config [#66](https://github.com/eclipse-iceoryx/iceoryx2/issues/66) ### Refactoring - * Example [#1](https://github.com/larry-robotics/iceoryx2/issues/1) + * Example [#1](https://github.com/eclipse-iceoryx/iceoryx2/issues/1) ### Workflow @@ -22,7 +24,9 @@ ### New API features - * Example [#1](https://github.com/larry-robotics/iceoryx2/issues/1) + * Add `FixedSizeByteString::from_bytes_truncated` [#56](https://github.com/eclipse-iceoryx/iceoryx2/issues/56) + * Add `Deref`, `DerefMut`, `Clone`, `Eq`, `PartialEq` and `extend_from_slice` to (FixedSize)Vec [#58](https://github.com/eclipse-iceoryx/iceoryx2/issues/58) + * `MessagingPattern` implements `Display` [#64](https://github.com/eclipse-iceoryx/iceoryx2/issues/64) ### API Breaking Changes diff --git a/iceoryx2-bb/container/src/byte_string.rs b/iceoryx2-bb/container/src/byte_string.rs index 2f1fb638c..db9e8b937 100644 --- a/iceoryx2-bb/container/src/byte_string.rs +++ b/iceoryx2-bb/container/src/byte_string.rs @@ -207,23 +207,12 @@ impl FixedSizeByteString { /// /// * `bytes` len must be smaller or equal than [`FixedSizeByteString::capacity()`] /// - pub const unsafe fn new_unchecked(bytes: &[u8]) -> Self { + pub unsafe fn new_unchecked(bytes: &[u8]) -> Self { if CAPACITY < bytes.len() { panic!("Insufficient capacity to store bytes."); } - let mut new_self = Self::new(); - new_self.len = bytes.len(); - std::ptr::copy( - bytes.as_ptr(), - new_self.data.as_ptr() as *mut u8, - bytes.len(), - ); - - let zero = 0u8; - std::ptr::copy(&zero, new_self.data.as_ptr().add(bytes.len()) as *mut u8, 1); - - new_self + Self::from_bytes_truncated(bytes) } /// Creates a new [`FixedSizeByteString`] from a byte slice @@ -237,6 +226,22 @@ impl FixedSizeByteString { Ok(new_self) } + /// Creates a new [`FixedSizeByteString`] from a byte slice. If the byte slice does not fit + /// into the [`FixedSizeByteString`] it will be truncated. + pub fn from_bytes_truncated(bytes: &[u8]) -> Self { + let mut new_self = Self::new(); + new_self.len = std::cmp::min(bytes.len(), CAPACITY); + for (i, byte) in bytes.iter().enumerate().take(new_self.len) { + new_self.data[i].write(*byte); + } + + if new_self.len < CAPACITY { + new_self.data[new_self.len].write(0); + } + + new_self + } + /// Creates a new byte string from a given null-terminated string /// /// # Safety diff --git a/iceoryx2-bb/container/src/semantic_string.rs b/iceoryx2-bb/container/src/semantic_string.rs index ea3abf34f..a1400fdcd 100644 --- a/iceoryx2-bb/container/src/semantic_string.rs +++ b/iceoryx2-bb/container/src/semantic_string.rs @@ -295,7 +295,7 @@ macro_rules! semantic_string { } impl $string_name { - pub const unsafe fn new_unchecked(bytes: &[u8]) -> Self { + pub unsafe fn new_unchecked(bytes: &[u8]) -> Self { Self { value: iceoryx2_bb_container::byte_string::FixedSizeByteString::new_unchecked(bytes), } diff --git a/iceoryx2-bb/container/src/vec.rs b/iceoryx2-bb/container/src/vec.rs index 132f21518..5b2bfa21c 100644 --- a/iceoryx2-bb/container/src/vec.rs +++ b/iceoryx2-bb/container/src/vec.rs @@ -64,6 +64,8 @@ use std::{ alloc::Layout, mem::MaybeUninit, + ops::Deref, + ops::DerefMut, sync::atomic::{AtomicBool, Ordering}, }; @@ -136,6 +138,42 @@ impl RelocatableContainer for Vec { } } +impl Deref for Vec { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + self.verify_init(&format!("Vec<{}>::push()", std::any::type_name::())); + unsafe { core::slice::from_raw_parts((*self.data_ptr.as_ptr()).as_ptr(), self.len) } + } +} + +impl DerefMut for Vec { + fn deref_mut(&mut self) -> &mut Self::Target { + self.verify_init(&format!("Vec<{}>::push()", std::any::type_name::())); + unsafe { + core::slice::from_raw_parts_mut((*self.data_ptr.as_mut_ptr()).as_mut_ptr(), self.len) + } + } +} + +impl PartialEq for Vec { + fn eq(&self, other: &Self) -> bool { + if other.len() != self.len() { + return false; + } + + for i in 0..self.len() { + if other[i] != self[i] { + return false; + } + } + + true + } +} + +impl Eq for Vec {} + impl Vec { fn verify_init(&self, source: &str) { if !self @@ -212,6 +250,27 @@ impl Vec { self.len += 1; } + /// Append all elements from other via [`Clone`]. + /// + /// # Safety + /// + /// * Only use this method when [`Vec::init()`] was called before + /// + pub unsafe fn extend_from_slice(&mut self, other: &[T]) -> bool + where + T: Clone, + { + if self.capacity < self.len + other.len() { + return false; + } + + for element in other { + self.push_unchecked(element.clone()); + } + + true + } + /// Removes the last element of the vector and returns it to the user. If the vector is empty /// it returns [`None`]. /// @@ -249,62 +308,6 @@ impl Vec { value.assume_init() } - - /// Returns a reference to the element at the specified index. If the index is out of bounds it - /// returns [`None`]. - /// - /// # Safety - /// - /// * Only use this method when [`Vec::init()`] was called before - /// - pub unsafe fn get(&self, index: usize) -> Option<&T> { - if self.len <= index { - None - } else { - self.verify_init(&format!("Vec<{}>::get()", std::any::type_name::())); - Some(self.get_unchecked(index)) - } - } - - /// Returns a reference to the element at the specified index. The user has to ensure that the - /// index is present in the vector otherwise it leads to undefined behavior. - /// - /// # Safety - /// - /// * Only use this method when [`Vec::init()`] was called before - /// * The index must be not out of bounds - /// - pub unsafe fn get_unchecked(&self, index: usize) -> &T { - &*(*self.data_ptr.as_ptr().add(index)).as_ptr() - } - - /// Returns a mutable reference to the element at the specified index. If the index is out of - /// bounds it returns [`None`]. - /// - /// # Safety - /// - /// * Only use this method when [`Vec::init()`] was called before - /// - pub unsafe fn get_mut(&mut self, index: usize) -> Option<&mut T> { - if self.len <= index { - None - } else { - self.verify_init(&format!("Vec<{}>::get_mut()", std::any::type_name::())); - Some(self.get_unchecked_mut(index)) - } - } - - /// Returns a mutable reference to the element at the specified index. The user has to ensure - /// that the index is present in the vector otherwise it leads to undefined behavior. - /// - /// # Safety - /// - /// * Only use this method when [`Vec::init()`] was called before - /// * The index must be not out of bounds - /// - pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T { - &mut *(*self.data_ptr.as_mut_ptr().add(index)).as_mut_ptr() - } } /// Relocatable vector with compile time fixed size capacity. In contrast to its counterpart the @@ -330,6 +333,36 @@ impl Default for FixedSizeVec { } } +impl Deref for FixedSizeVec { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + self.state.deref() + } +} + +impl DerefMut for FixedSizeVec { + fn deref_mut(&mut self) -> &mut Self::Target { + self.state.deref_mut() + } +} + +impl PartialEq for FixedSizeVec { + fn eq(&self, other: &Self) -> bool { + self.state.eq(&other.state) + } +} + +impl Eq for FixedSizeVec {} + +impl Clone for FixedSizeVec { + fn clone(&self) -> Self { + let mut new_self = Self::new(); + new_self.extend_from_slice(self.deref()); + new_self + } +} + unsafe impl Send for FixedSizeVec {} unsafe impl Sync for FixedSizeVec {} @@ -373,6 +406,14 @@ impl FixedSizeVec { unsafe { self.state.fill(value) } } + /// Append all elements from other via [`Clone`]. + pub fn extend_from_slice(&mut self, other: &[T]) -> bool + where + T: Clone, + { + unsafe { self.state.extend_from_slice(other) } + } + /// Removes the last element of the vector and returns it to the user. If the vector is empty /// it returns [`None`]. pub fn pop(&mut self) -> Option { @@ -383,38 +424,4 @@ impl FixedSizeVec { pub fn clear(&mut self) { unsafe { self.state.clear() } } - - /// Returns a reference to the element at the specified index. If the index is out of bounds it - /// returns [`None`]. - pub fn get(&self, index: usize) -> Option<&T> { - unsafe { self.state.get(index) } - } - - /// Returns a reference to the element at the specified index. The user has to ensure that the - /// index is present in the vector otherwise it leads to undefined behavior. - /// - /// # Safety - /// - /// * The index must be not out of bounds - /// - pub unsafe fn get_unchecked(&self, index: usize) -> &T { - unsafe { self.state.get_unchecked(index) } - } - - /// Returns a mutable reference to the element at the specified index. If the index is out of - /// bounds it returns [`None`]. - pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { - unsafe { self.state.get_mut(index) } - } - - /// Returns a mutable reference to the element at the specified index. The user has to ensure - /// that the index is present in the vector otherwise it leads to undefined behavior. - /// - /// # Safety - /// - /// * The index must be not out of bounds - /// - pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T { - unsafe { self.state.get_unchecked_mut(index) } - } } diff --git a/iceoryx2-bb/container/tests/byte_string_tests.rs b/iceoryx2-bb/container/tests/byte_string_tests.rs index 0e58d6efd..1c1e9b633 100644 --- a/iceoryx2-bb/container/tests/byte_string_tests.rs +++ b/iceoryx2-bb/container/tests/byte_string_tests.rs @@ -47,19 +47,40 @@ fn fixed_size_byte_string_from_bytes_works() { assert_that!(sut.pop(), eq Some(b'd')); } +#[test] +fn fixed_size_byte_string_from_bytes_truncated_works() { + let sut = Sut::from_bytes(b"bonjour world"); + assert_that!(sut, is_ok); + let mut sut = sut.unwrap(); + + assert_that!(sut, is_not_empty); + assert_that!(sut.is_full(), eq false); + assert_that!(sut, len 13); + assert_that!(sut, eq b"bonjour world"); + assert_that!(sut, ne b"bonjour world! woo"); + assert_that!(sut.as_bytes(), eq b"bonjour world"); + assert_that!(sut.as_mut_bytes(), eq b"bonjour world"); + assert_that!(sut.as_bytes_with_nul(), eq b"bonjour world\0"); + assert_that!(sut.pop(), eq Some(b'd')); +} + #[test] fn fixed_size_byte_string_from_byte_slice_works() { - let mut sut = Sut::from(b"hello world!"); + let sut = FixedSizeByteString::<5>::from_bytes_truncated(b"hell"); assert_that!(sut, is_not_empty); assert_that!(sut.is_full(), eq false); - assert_that!(sut, len 12); - assert_that!(sut, eq b"hello world!"); - assert_that!(sut, ne b"hello world! woo"); - assert_that!(sut.as_bytes(), eq b"hello world!"); - assert_that!(sut.as_mut_bytes(), eq b"hello world!"); - assert_that!(sut.as_bytes_with_nul(), eq b"hello world!\0"); - assert_that!(sut.pop(), eq Some(b'!')); + assert_that!(sut, len 4); + assert_that!(sut, eq b"hell"); + assert_that!(sut.as_bytes_with_nul(), eq b"hell\0"); + + let sut = FixedSizeByteString::<5>::from_bytes_truncated(b"hello world"); + + assert_that!(sut, is_not_empty); + assert_that!(sut.is_full(), eq true); + assert_that!(sut, len 5); + assert_that!(sut, eq b"hello"); + assert_that!(sut.as_bytes_with_nul(), eq b"hello\0"); } #[test] diff --git a/iceoryx2-bb/container/tests/vec_tests.rs b/iceoryx2-bb/container/tests/vec_tests.rs index d2c3d2d4a..72b09a159 100644 --- a/iceoryx2-bb/container/tests/vec_tests.rs +++ b/iceoryx2-bb/container/tests/vec_tests.rs @@ -84,8 +84,8 @@ fn vec_push_pop_works_with_uninitialized_memory() { assert_that!(sut.is_full(), eq true); for i in 0..sut.capacity() { - assert_that!(unsafe { *sut.get(i).unwrap() }, eq i * 2 + 3); - assert_that!(unsafe { *sut.get_mut(i).unwrap() }, eq i * 2 + 3); + assert_that!(*sut.get(i).unwrap(), eq i * 2 + 3); + assert_that!(*sut.get_mut(i).unwrap(), eq i * 2 + 3); assert_that!(unsafe { *sut.get_unchecked(i) }, eq i * 2 + 3); assert_that!(unsafe { *sut.get_unchecked_mut(i) }, eq i * 2 + 3); } @@ -151,3 +151,49 @@ fn fixed_size_vec_valid_after_move() { assert_that!(result, eq Some((sut2.capacity() - i - 1) * 2 + 3)); } } + +#[test] +fn fixed_size_vec_eq_works() { + let create_vec = |n| { + let mut sut = Sut::new(); + for i in 0..n { + sut.push(4 * i + 3); + } + sut + }; + + let vec1 = create_vec(SUT_CAPACITY - 2); + let vec2 = create_vec(SUT_CAPACITY - 1); + let vec3 = create_vec(SUT_CAPACITY); + + assert_that!(Sut::new() == Sut::new(), eq true); + + assert_that!(vec1 == vec1, eq true); + assert_that!(vec1 == vec2, eq false); + assert_that!(vec1 == vec3, eq false); + assert_that!(vec1 == Sut::new(), eq false); + + assert_that!(vec2 == vec1, eq false); + assert_that!(vec2 == vec2, eq true); + assert_that!(vec2 == vec3, eq false); + assert_that!(vec2 == Sut::new(), eq false); + + assert_that!(vec3 == vec1, eq false); + assert_that!(vec3 == vec2, eq false); + assert_that!(vec3 == vec3, eq true); + assert_that!(vec3 == Sut::new(), eq false); +} + +#[test] +fn fixed_size_vec_clone_works() { + let mut sut = Sut::new(); + let sut1 = sut.clone(); + for i in 0..SUT_CAPACITY { + sut.push(8 * i + 6); + } + + let sut2 = sut.clone(); + + assert_that!(Sut::new() == sut1, eq true); + assert_that!(sut == sut2, eq true); +} 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/config.rs b/iceoryx2-bb/posix/src/config.rs index fd929b49d..2bcdd432f 100644 --- a/iceoryx2-bb/posix/src/config.rs +++ b/iceoryx2-bb/posix/src/config.rs @@ -38,12 +38,17 @@ pub const ADAPTIVE_WAIT_INITIAL_WAITING_TIME: Duration = Duration::from_micros(1 pub const ADAPTIVE_WAIT_FINAL_WAITING_TIME: Duration = Duration::from_millis(10); // directories -pub const TEMP_DIRECTORY: Path = - unsafe { Path::new_unchecked(iceoryx2_pal_configuration::TEMP_DIRECTORY) }; -pub const TEST_DIRECTORY: Path = - unsafe { Path::new_unchecked(iceoryx2_pal_configuration::TEST_DIRECTORY) }; -pub const SHARED_MEMORY_DIRECTORY: Path = - unsafe { Path::new_unchecked(iceoryx2_pal_configuration::SHARED_MEMORY_DIRECTORY) }; +pub fn temp_directory() -> Path { + unsafe { Path::new_unchecked(iceoryx2_pal_configuration::TEMP_DIRECTORY) } +} + +pub fn test_directory() -> Path { + unsafe { Path::new_unchecked(iceoryx2_pal_configuration::TEST_DIRECTORY) } +} + +pub fn shared_memory_directory() -> Path { + unsafe { Path::new_unchecked(iceoryx2_pal_configuration::SHARED_MEMORY_DIRECTORY) } +} // TODO unable to verify? pub const ACL_LIST_CAPACITY: u32 = 25; diff --git a/iceoryx2-bb/posix/src/mutex.rs b/iceoryx2-bb/posix/src/mutex.rs index a1f2725cf..13315c0f5 100644 --- a/iceoryx2-bb/posix/src/mutex.rs +++ b/iceoryx2-bb/posix/src/mutex.rs @@ -266,7 +266,12 @@ pub enum MutexThreadTerminationBehavior { /// mutex owning /// thread/process dies the mutex is put into an inconsistent state which can be recovered with /// [`Mutex::make_consistent()`]. The inconsistent state is detected by the next instance which - /// calls [`Mutex::lock()`], [`Mutex::try_lock()`] or [`Mutex::timed_lock()`]. + /// calls [`Mutex::try_lock()`] or [`Mutex::timed_lock()`]. + /// + /// **Important:** If the owner dies after another thread has already locked the [`Mutex`] it + /// may become impossible to recover the [`Mutex`]. Therefore, this feature should be used + /// only in combination with either [`Mutex::try_lock`] or [`Mutex::timed_lock()`] and + /// never with [`Mutex::lock()`]. /// /// This is also known as robust mutex. ReleaseWhenLocked = posix::PTHREAD_MUTEX_ROBUST, 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/directory_tests.rs b/iceoryx2-bb/posix/tests/directory_tests.rs index 47fc957ac..1b59b8ce3 100644 --- a/iceoryx2-bb/posix/tests/directory_tests.rs +++ b/iceoryx2-bb/posix/tests/directory_tests.rs @@ -87,7 +87,7 @@ impl TestFixture { } fn generate_directory_name(&mut self) -> Path { - let mut directory = TEST_DIRECTORY; + let mut directory = test_directory(); directory.push(PATH_SEPARATOR).unwrap(); directory.push_bytes(b"dir_tests_").unwrap(); directory @@ -107,7 +107,7 @@ impl TestFixture { #[test] fn directory_temp_directory_does_exist() { - assert_that!(Directory::does_exist(&TEST_DIRECTORY).unwrap(), eq true); + assert_that!(Directory::does_exist(&test_directory()).unwrap(), eq true); } #[test] diff --git a/iceoryx2-bb/posix/tests/file_descriptor_set_tests.rs b/iceoryx2-bb/posix/tests/file_descriptor_set_tests.rs index 7b09fcaec..3b2bd42e8 100644 --- a/iceoryx2-bb/posix/tests/file_descriptor_set_tests.rs +++ b/iceoryx2-bb/posix/tests/file_descriptor_set_tests.rs @@ -38,7 +38,7 @@ fn generate_socket_name() -> FilePath { ) .unwrap(); - FilePath::from_path_and_file(&TEST_DIRECTORY, &file).unwrap() + FilePath::from_path_and_file(&test_directory(), &file).unwrap() } #[test] diff --git a/iceoryx2-bb/posix/tests/file_descriptor_tests.rs b/iceoryx2-bb/posix/tests/file_descriptor_tests.rs index d326a6201..a9f2bd4c1 100644 --- a/iceoryx2-bb/posix/tests/file_descriptor_tests.rs +++ b/iceoryx2-bb/posix/tests/file_descriptor_tests.rs @@ -53,7 +53,7 @@ trait GenericTestBuilder { impl GenericTestBuilder for File { fn sut() -> Self { - let name = FilePath::from_path_and_file(&TEST_DIRECTORY, &generate_name()).unwrap(); + let name = FilePath::from_path_and_file(&test_directory(), &generate_name()).unwrap(); let file_content = [170u8; 2048]; diff --git a/iceoryx2-bb/posix/tests/file_lock_tests.rs b/iceoryx2-bb/posix/tests/file_lock_tests.rs index cac8bbe28..ebf28cbc0 100644 --- a/iceoryx2-bb/posix/tests/file_lock_tests.rs +++ b/iceoryx2-bb/posix/tests/file_lock_tests.rs @@ -11,7 +11,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use iceoryx2_bb_container::semantic_string::SemanticString; -use iceoryx2_bb_posix::config::*; +use iceoryx2_bb_posix::config; use iceoryx2_bb_posix::file::*; use iceoryx2_bb_posix::file_lock::*; use iceoryx2_bb_posix::process::*; @@ -38,7 +38,7 @@ fn generate_file_name() -> FilePath { ) .unwrap(); - FilePath::from_path_and_file(&TEST_DIRECTORY, &file).unwrap() + FilePath::from_path_and_file(&config::test_directory(), &file).unwrap() } const TIMEOUT: Duration = Duration::from_millis(10); diff --git a/iceoryx2-bb/posix/tests/file_tests.rs b/iceoryx2-bb/posix/tests/file_tests.rs index f3e095a3f..1f5b48f54 100644 --- a/iceoryx2-bb/posix/tests/file_tests.rs +++ b/iceoryx2-bb/posix/tests/file_tests.rs @@ -33,7 +33,7 @@ fn generate_file_name() -> FilePath { ) .unwrap(); - FilePath::from_path_and_file(&TEST_DIRECTORY, &file).unwrap() + FilePath::from_path_and_file(&test_directory(), &file).unwrap() } struct TestFixture { diff --git a/iceoryx2-bb/posix/tests/metadata_tests.rs b/iceoryx2-bb/posix/tests/metadata_tests.rs index d9d92f66e..c34c55643 100644 --- a/iceoryx2-bb/posix/tests/metadata_tests.rs +++ b/iceoryx2-bb/posix/tests/metadata_tests.rs @@ -28,7 +28,7 @@ use iceoryx2_pal_posix::posix::POSIX_SUPPORT_USERS_AND_GROUPS; #[test] fn metadata_reads_basic_stats_correctly() { let file_name = - FilePath::from_path_and_file(&TEST_DIRECTORY, &FileName::new(b"meta_test").unwrap()) + FilePath::from_path_and_file(&test_directory(), &FileName::new(b"meta_test").unwrap()) .unwrap(); let mut file = FileBuilder::new(&file_name) @@ -50,7 +50,7 @@ fn metadata_reads_owner_and_permission_stats_correctly() { test_requires!(POSIX_SUPPORT_USERS_AND_GROUPS && POSIX_SUPPORT_PERMISSIONS); let file_name = - FilePath::from_path_and_file(&TEST_DIRECTORY, &FileName::new(b"meta_test_123").unwrap()) + FilePath::from_path_and_file(&test_directory(), &FileName::new(b"meta_test_123").unwrap()) .unwrap(); let mut file = FileBuilder::new(&file_name) diff --git a/iceoryx2-bb/posix/tests/mutex_tests.rs b/iceoryx2-bb/posix/tests/mutex_tests.rs index b72a5ae32..cfec622c8 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) @@ -403,14 +405,16 @@ fn mutex_can_be_recovered_when_thread_died() { }); }); - let guard = sut.lock(); - assert_that!(guard, is_err); - match guard.as_ref().err().as_ref().unwrap() { - MutexLockError::LockAcquiredButOwnerDied(_) => (), - _ => assert_that!(true, eq false), + loop { + let guard = sut.try_lock(); + + if guard.is_ok() { + assert_that!(guard.as_ref().unwrap(), is_none); + } else if let Err(MutexLockError::LockAcquiredButOwnerDied(_)) = guard { + sut.make_consistent(); + break; + } } - sut.make_consistent(); - drop(guard); let guard = sut.try_lock(); assert_that!(guard, is_ok); @@ -429,6 +433,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/posix/tests/socket_ancillary_tests.rs b/iceoryx2-bb/posix/tests/socket_ancillary_tests.rs index b0eff3f4a..a82f2969f 100644 --- a/iceoryx2-bb/posix/tests/socket_ancillary_tests.rs +++ b/iceoryx2-bb/posix/tests/socket_ancillary_tests.rs @@ -12,7 +12,7 @@ use iceoryx2_bb_container::semantic_string::SemanticString; use iceoryx2_bb_elementary::unique_id::*; -use iceoryx2_bb_posix::config::*; +use iceoryx2_bb_posix::config; use iceoryx2_bb_posix::file::*; use iceoryx2_bb_posix::file_descriptor::*; use iceoryx2_bb_posix::process::ProcessId; @@ -29,7 +29,7 @@ fn generate_file_name() -> FilePath { file.push_bytes(UniqueId::new().value().to_string().as_bytes()) .unwrap(); - FilePath::from_path_and_file(&TEST_DIRECTORY, &file).unwrap() + FilePath::from_path_and_file(&config::test_directory(), &file).unwrap() } struct TestFixture { diff --git a/iceoryx2-bb/posix/tests/udp_socket_tests.rs b/iceoryx2-bb/posix/tests/udp_socket_tests.rs index 3e1fc9b94..2aacccfdc 100644 --- a/iceoryx2-bb/posix/tests/udp_socket_tests.rs +++ b/iceoryx2-bb/posix/tests/udp_socket_tests.rs @@ -107,12 +107,12 @@ fn udp_socket_when_socket_goes_out_of_scope_address_is_free_again() { fn udp_socket_server_has_correct_address() { let sut_server = UdpServerBuilder::new() .address(ipv4_address::LOCALHOST) - .port(Port::new(65111)) + .port(Port::new(55223)) .listen() .unwrap(); assert_that!(sut_server.address(), eq ipv4_address::LOCALHOST); - assert_that!(sut_server.port(), eq Port::new(65111)); + assert_that!(sut_server.port(), eq Port::new(55223)); } #[test] diff --git a/iceoryx2-bb/posix/tests/unix_datagram_socket_tests.rs b/iceoryx2-bb/posix/tests/unix_datagram_socket_tests.rs index e26abeeda..d4cb05ece 100644 --- a/iceoryx2-bb/posix/tests/unix_datagram_socket_tests.rs +++ b/iceoryx2-bb/posix/tests/unix_datagram_socket_tests.rs @@ -43,7 +43,7 @@ fn generate_socket_name() -> FilePath { ) .unwrap(); - FilePath::from_path_and_file(&TEST_DIRECTORY, &file).unwrap() + FilePath::from_path_and_file(&test_directory(), &file).unwrap() } fn generate_file_name() -> FilePath { @@ -57,7 +57,7 @@ fn generate_file_name() -> FilePath { ) .unwrap(); - FilePath::from_path_and_file(&TEST_DIRECTORY, &file).unwrap() + FilePath::from_path_and_file(&test_directory(), &file).unwrap() } struct TestFixture { 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/communication_channel/message_queue.rs b/iceoryx2-cal/src/communication_channel/message_queue.rs index 5b5c730de..f9abd4293 100644 --- a/iceoryx2-cal/src/communication_channel/message_queue.rs +++ b/iceoryx2-cal/src/communication_channel/message_queue.rs @@ -147,9 +147,9 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { Self { - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, - path_hint: DEFAULT_PATH_HINT, + suffix: Channel::<()>::default_suffix(), + prefix: Channel::<()>::default_prefix(), + path_hint: Channel::<()>::default_path_hint(), } } } @@ -190,7 +190,7 @@ struct SharedConfiguration { } #[derive(Debug)] -pub struct Creator { +pub struct Creator { channel_name: FileName, enable_safe_overflow: bool, buffer_size: usize, @@ -291,7 +291,7 @@ impl CommunicationChannelCreator> for Creator } #[derive(Debug)] -pub struct Connector { +pub struct Connector { channel_name: FileName, config: Configuration, _phantom_data: PhantomData, diff --git a/iceoryx2-cal/src/communication_channel/mod.rs b/iceoryx2-cal/src/communication_channel/mod.rs index 31add38da..7517a98dc 100644 --- a/iceoryx2-cal/src/communication_channel/mod.rs +++ b/iceoryx2-cal/src/communication_channel/mod.rs @@ -72,7 +72,6 @@ pub mod unix_datagram; use std::fmt::Debug; -use iceoryx2_bb_posix::config::TEMP_DIRECTORY; use iceoryx2_bb_system_types::file_name::FileName; use iceoryx2_bb_system_types::path::Path; @@ -81,15 +80,6 @@ use crate::named_concept::{NamedConcept, NamedConceptBuilder, NamedConceptMgmt}; /// The buffer size which the receiver has at least by default pub const DEFAULT_RECEIVER_BUFFER_SIZE: usize = 8; -/// The default suffix of every communication channel -pub const DEFAULT_SUFFIX: FileName = unsafe { FileName::new_unchecked(b".com") }; - -/// The default prefix of every communication channel -pub const DEFAULT_PREFIX: FileName = unsafe { FileName::new_unchecked(b"iox2_") }; - -/// The default path hint for every communication channel -pub const DEFAULT_PATH_HINT: Path = TEMP_DIRECTORY; - /// Describes failures when sending data #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] pub enum CommunicationChannelSendError { @@ -207,4 +197,9 @@ pub trait CommunicationChannel: Sized + Debug + NamedConceptMgmt { fn has_configurable_buffer_size() -> bool { false } + + /// The default suffix of every communication channel + fn default_suffix() -> FileName { + unsafe { FileName::new_unchecked(b".com") } + } } diff --git a/iceoryx2-cal/src/communication_channel/posix_shared_memory.rs b/iceoryx2-cal/src/communication_channel/posix_shared_memory.rs index 4ba42505a..d4e27984a 100644 --- a/iceoryx2-cal/src/communication_channel/posix_shared_memory.rs +++ b/iceoryx2-cal/src/communication_channel/posix_shared_memory.rs @@ -79,9 +79,9 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { Self { - suffix: DEFAULT_SUFFIX, - path_hint: DEFAULT_PATH_HINT, - prefix: DEFAULT_PREFIX, + suffix: Channel::default_suffix(), + path_hint: Channel::default_path_hint(), + prefix: Channel::default_prefix(), } } } diff --git a/iceoryx2-cal/src/communication_channel/process_local.rs b/iceoryx2-cal/src/communication_channel/process_local.rs index 6ad4f2918..5719c128e 100644 --- a/iceoryx2-cal/src/communication_channel/process_local.rs +++ b/iceoryx2-cal/src/communication_channel/process_local.rs @@ -69,9 +69,9 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { Self { - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, - path_hint: DEFAULT_PATH_HINT, + suffix: Channel::default_suffix(), + prefix: Channel::default_prefix(), + path_hint: Channel::default_path_hint(), } } } diff --git a/iceoryx2-cal/src/communication_channel/unix_datagram.rs b/iceoryx2-cal/src/communication_channel/unix_datagram.rs index ae391e85a..e62cdeb10 100644 --- a/iceoryx2-cal/src/communication_channel/unix_datagram.rs +++ b/iceoryx2-cal/src/communication_channel/unix_datagram.rs @@ -37,9 +37,9 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { Self { - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, - path_hint: DEFAULT_PATH_HINT, + suffix: Channel::<()>::default_suffix(), + prefix: Channel::<()>::default_prefix(), + path_hint: Channel::<()>::default_path_hint(), } } } @@ -165,7 +165,7 @@ impl CommunicationChannel for Channel { } #[derive(Debug)] -pub struct Creator { +pub struct Creator { channel_name: FileName, enable_safe_overflow: bool, buffer_size: usize, @@ -240,7 +240,7 @@ impl CommunicationChannelCreator> for Creator } #[derive(Debug)] -pub struct Connector { +pub struct Connector { channel_name: FileName, config: Configuration, _phantom_data: PhantomData, diff --git a/iceoryx2-cal/src/dynamic_storage/mod.rs b/iceoryx2-cal/src/dynamic_storage/mod.rs index 1fc28fd4c..3f26ab7da 100644 --- a/iceoryx2-cal/src/dynamic_storage/mod.rs +++ b/iceoryx2-cal/src/dynamic_storage/mod.rs @@ -57,24 +57,13 @@ use std::fmt::Debug; use iceoryx2_bb_memory::bump_allocator::BumpAllocator; -use iceoryx2_bb_posix::config::TEMP_DIRECTORY; use iceoryx2_bb_system_types::file_name::FileName; -use iceoryx2_bb_system_types::path::Path; use crate::static_storage::file::{NamedConcept, NamedConceptBuilder, NamedConceptMgmt}; pub mod posix_shared_memory; pub mod process_local; -/// The default suffix of every dynamic storage -pub const DEFAULT_SUFFIX: FileName = unsafe { FileName::new_unchecked(b".dyn") }; - -/// The default prefix of every dynamic storage -pub const DEFAULT_PREFIX: FileName = unsafe { FileName::new_unchecked(b"iox2_") }; - -/// The default path hint for every dynamic storage -pub const DEFAULT_PATH_HINT: Path = TEMP_DIRECTORY; - /// Describes failures when creating a new [`DynamicStorage`] #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] pub enum DynamicStorageCreateError { @@ -155,4 +144,9 @@ pub trait DynamicStorage: Sized + Debug + NamedConceptMgmt + Nam /// can be accessed by multiple processes concurrently therefore it must be constant or /// thread-safe. fn get(&self) -> &T; + + /// The default suffix of every dynamic storage + fn default_suffix() -> FileName { + unsafe { FileName::new_unchecked(b".dyn") } + } } diff --git a/iceoryx2-cal/src/dynamic_storage/posix_shared_memory.rs b/iceoryx2-cal/src/dynamic_storage/posix_shared_memory.rs index 05a07518b..0a28ec328 100644 --- a/iceoryx2-cal/src/dynamic_storage/posix_shared_memory.rs +++ b/iceoryx2-cal/src/dynamic_storage/posix_shared_memory.rs @@ -59,7 +59,7 @@ const IS_INITIALIZED_STATE_VALUE: u64 = 0xbeefaffedeadbeef; /// The builder of [`Storage`]. #[derive(Debug)] -pub struct Builder { +pub struct Builder { storage_name: FileName, supplementary_size: usize, has_ownership: bool, @@ -67,7 +67,7 @@ pub struct Builder { _phantom_data: PhantomData, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone)] pub struct Configuration { suffix: FileName, prefix: FileName, @@ -83,9 +83,9 @@ struct Data { impl Default for Configuration { fn default() -> Self { Self { - path: DEFAULT_PATH_HINT, - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, + path: Storage::<()>::default_path_hint(), + suffix: Storage::<()>::default_suffix(), + prefix: Storage::<()>::default_prefix(), } } } diff --git a/iceoryx2-cal/src/dynamic_storage/process_local.rs b/iceoryx2-cal/src/dynamic_storage/process_local.rs index cfd665628..857cad362 100644 --- a/iceoryx2-cal/src/dynamic_storage/process_local.rs +++ b/iceoryx2-cal/src/dynamic_storage/process_local.rs @@ -67,7 +67,7 @@ struct StorageDetails { layout: Layout, } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(PartialEq, Eq, Copy, Clone, Debug)] pub struct Configuration { suffix: FileName, prefix: FileName, @@ -77,9 +77,9 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { Self { - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, - path_hint: DEFAULT_PATH_HINT, + suffix: Storage::<()>::default_suffix(), + prefix: Storage::<()>::default_prefix(), + path_hint: Storage::<()>::default_path_hint(), } } } @@ -273,7 +273,7 @@ impl Drop for Storage { } #[derive(Debug)] -pub struct Builder { +pub struct Builder { name: FileName, supplementary_size: usize, has_ownership: bool, diff --git a/iceoryx2-cal/src/event/mod.rs b/iceoryx2-cal/src/event/mod.rs index 121f3ee1f..72374a3f8 100644 --- a/iceoryx2-cal/src/event/mod.rs +++ b/iceoryx2-cal/src/event/mod.rs @@ -16,7 +16,6 @@ pub mod unix_datagram_socket; use std::{fmt::Debug, time::Duration}; pub use crate::named_concept::{NamedConcept, NamedConceptBuilder, NamedConceptMgmt}; -use iceoryx2_bb_posix::config::TEMP_DIRECTORY; pub use iceoryx2_bb_system_types::file_name::FileName; pub use iceoryx2_bb_system_types::path::Path; @@ -78,15 +77,6 @@ impl std::fmt::Display for ListenerCreateError { impl std::error::Error for ListenerCreateError {} -/// The default suffix of every event -pub const DEFAULT_SUFFIX: FileName = unsafe { FileName::new_unchecked(b".event") }; - -/// The default prefix of every event -pub const DEFAULT_PREFIX: FileName = unsafe { FileName::new_unchecked(b"iox2_") }; - -/// The default path hint for every event -pub const DEFAULT_PATH_HINT: Path = TEMP_DIRECTORY; - pub trait TriggerId: Debug + Copy {} impl TriggerId for u64 {} @@ -117,4 +107,9 @@ pub trait Event: Sized + NamedConceptMgmt + Debug { type NotifierBuilder: NotifierBuilder; type Listener: Listener; type ListenerBuilder: ListenerBuilder; + + /// The default suffix of every event + fn default_suffix() -> FileName { + unsafe { FileName::new_unchecked(b".event") } + } } diff --git a/iceoryx2-cal/src/event/process_local.rs b/iceoryx2-cal/src/event/process_local.rs index 06955425f..2300b29de 100644 --- a/iceoryx2-cal/src/event/process_local.rs +++ b/iceoryx2-cal/src/event/process_local.rs @@ -64,23 +64,25 @@ static PROCESS_LOCAL_STORAGE: Lazy>> = Laz }); #[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct Configuration { +pub struct Configuration { suffix: FileName, prefix: FileName, path: Path, + _phantom: PhantomData, } -impl Default for Configuration { +impl Default for Configuration { fn default() -> Self { Self { - path: DEFAULT_PATH_HINT, - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, + path: EventImpl::::default_path_hint(), + suffix: EventImpl::::default_suffix(), + prefix: EventImpl::::default_prefix(), + _phantom: PhantomData, } } } -impl NamedConceptConfiguration for Configuration { +impl NamedConceptConfiguration for Configuration { fn prefix(mut self, value: FileName) -> Self { self.prefix = value; self @@ -114,7 +116,7 @@ pub struct Duplex { name: FileName, management: Arc>, has_ownership: bool, - config: Configuration, + config: Configuration, } impl NamedConcept for Duplex { @@ -150,7 +152,7 @@ impl Notifier for Duplex { impl Drop for Duplex { fn drop(&mut self) { if self.has_ownership { - fatal_panic!(from self, when unsafe { Event::::remove_cfg(&self.name, &self.config) }, + fatal_panic!(from self, when unsafe { EventImpl::::remove_cfg(&self.name, &self.config) }, "This should never happen! Unable to remove resources."); } } @@ -193,7 +195,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); @@ -206,11 +208,13 @@ impl Listener for Duplex { #[derive(Debug)] pub struct Builder { name: FileName, - config: Configuration, + config: Configuration, _data: PhantomData, } -impl NamedConceptBuilder> for Builder { +impl NamedConceptBuilder> + for Builder +{ fn new(name: &FileName) -> Self { Self { name: *name, @@ -219,13 +223,15 @@ impl NamedConceptBuilder> for Buil } } - fn config(mut self, config: &Configuration) -> Self { + fn config(mut self, config: &Configuration) -> Self { self.config = *config; self } } -impl NotifierBuilder> for Builder { +impl NotifierBuilder> + for Builder +{ fn open(self) -> Result, NotifierCreateError> { let msg = "Failed to open event"; @@ -255,7 +261,9 @@ impl NotifierBuilder } } -impl ListenerBuilder> for Builder { +impl ListenerBuilder> + for Builder +{ fn create(self) -> Result, ListenerCreateError> { let msg = "Failed to create event"; @@ -322,19 +330,19 @@ impl ListenerBuilder } #[derive(Debug)] -pub struct Event { +pub struct EventImpl { _data: PhantomData, } -impl crate::event::Event for Event { +impl crate::event::Event for EventImpl { type Notifier = Duplex; type Listener = Duplex; type NotifierBuilder = Builder; type ListenerBuilder = Builder; } -impl NamedConceptMgmt for Event { - type Configuration = Configuration; +impl NamedConceptMgmt for EventImpl { + type Configuration = Configuration; fn does_exist_cfg( name: &FileName, diff --git a/iceoryx2-cal/src/event/unix_datagram_socket.rs b/iceoryx2-cal/src/event/unix_datagram_socket.rs index d44a24b4d..699d37ece 100644 --- a/iceoryx2-cal/src/event/unix_datagram_socket.rs +++ b/iceoryx2-cal/src/event/unix_datagram_socket.rs @@ -22,23 +22,25 @@ use iceoryx2_bb_posix::{ pub use iceoryx2_bb_system_types::file_name::FileName; #[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct Configuration { +pub struct Configuration { suffix: FileName, prefix: FileName, path: Path, + _phantom: PhantomData, } -impl Default for Configuration { +impl Default for Configuration { fn default() -> Self { Self { - path: DEFAULT_PATH_HINT, - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, + path: EventImpl::::default_path_hint(), + suffix: EventImpl::::default_suffix(), + prefix: EventImpl::::default_prefix(), + _phantom: PhantomData, } } } -impl NamedConceptConfiguration for Configuration { +impl NamedConceptConfiguration for Configuration { fn prefix(mut self, value: FileName) -> Self { self.prefix = value; self @@ -67,19 +69,21 @@ impl NamedConceptConfiguration for Configuration { } } -impl From for crate::communication_channel::unix_datagram::Configuration { - fn from(value: Configuration) -> Self { +impl From> + for crate::communication_channel::unix_datagram::Configuration +{ + fn from(value: Configuration) -> Self { Self::default().suffix(value.suffix).path_hint(value.path) } } #[derive(Debug)] -pub struct Event { +pub struct EventImpl { _data: PhantomData, } -impl NamedConceptMgmt for Event { - type Configuration = Configuration; +impl NamedConceptMgmt for EventImpl { + type Configuration = Configuration; fn does_exist_cfg( name: &FileName, @@ -105,7 +109,7 @@ impl NamedConceptMgmt for Event { } } -impl crate::event::Event for Event { +impl crate::event::Event for EventImpl { type Notifier = Notifier; type Listener = Listener; type NotifierBuilder = NotifierBuilder; @@ -147,11 +151,13 @@ impl crate::event::Notifier for Notifier #[derive(Debug)] pub struct NotifierBuilder { name: FileName, - config: Configuration, + config: Configuration, _data: PhantomData, } -impl NamedConceptBuilder> for NotifierBuilder { +impl NamedConceptBuilder> + for NotifierBuilder +{ fn new(name: &FileName) -> Self { Self { name: *name, @@ -160,13 +166,13 @@ impl NamedConceptBuilder> for Noti } } - fn config(mut self, config: &Configuration) -> Self { + fn config(mut self, config: &Configuration) -> Self { self.config = *config; self } } -impl crate::event::NotifierBuilder> +impl crate::event::NotifierBuilder> for NotifierBuilder { fn open(self) -> Result, NotifierCreateError> { @@ -275,11 +281,13 @@ impl crate::event::Listener for Listener #[derive(Debug)] pub struct ListenerBuilder { name: FileName, - config: Configuration, + config: Configuration, _data: PhantomData, } -impl NamedConceptBuilder> for ListenerBuilder { +impl NamedConceptBuilder> + for ListenerBuilder +{ fn new(name: &FileName) -> Self { Self { name: *name, @@ -288,13 +296,13 @@ impl NamedConceptBuilder> for List } } - fn config(mut self, config: &Configuration) -> Self { + fn config(mut self, config: &Configuration) -> Self { self.config = *config; self } } -impl crate::event::ListenerBuilder> +impl crate::event::ListenerBuilder> for ListenerBuilder { fn create(self) -> Result, ListenerCreateError> { diff --git a/iceoryx2-cal/src/named_concept.rs b/iceoryx2-cal/src/named_concept.rs index 2dfdf4cab..820e752ef 100644 --- a/iceoryx2-cal/src/named_concept.rs +++ b/iceoryx2-cal/src/named_concept.rs @@ -178,4 +178,14 @@ pub trait NamedConceptMgmt { /// Returns a list of all available concepts with a custom configuration. fn list_cfg(cfg: &Self::Configuration) -> Result, NamedConceptListError>; + + /// The default prefix of every zero copy connection + fn default_prefix() -> FileName { + unsafe { FileName::new_unchecked(b"iox2_") } + } + + /// The default path hint for every zero copy connection + fn default_path_hint() -> Path { + iceoryx2_bb_posix::config::temp_directory() + } } diff --git a/iceoryx2-cal/src/shared_memory/mod.rs b/iceoryx2-cal/src/shared_memory/mod.rs index 96b56c61e..d9e819d53 100644 --- a/iceoryx2-cal/src/shared_memory/mod.rs +++ b/iceoryx2-cal/src/shared_memory/mod.rs @@ -60,21 +60,10 @@ pub mod process_local; use std::fmt::Debug; use iceoryx2_bb_elementary::allocator::DeallocationError; -use iceoryx2_bb_posix::config::TEMP_DIRECTORY; pub use crate::shm_allocator::*; use crate::static_storage::file::{NamedConcept, NamedConceptBuilder, NamedConceptMgmt}; use iceoryx2_bb_system_types::file_name::FileName; -use iceoryx2_bb_system_types::path::Path; - -/// The default suffix of every shared memory -pub const DEFAULT_SUFFIX: FileName = unsafe { FileName::new_unchecked(b".shm") }; - -/// The default prefix of every shared memory -pub const DEFAULT_PREFIX: FileName = unsafe { FileName::new_unchecked(b"iox2_") }; - -/// The default path hint for every shared memory -pub const DEFAULT_PATH_HINT: Path = TEMP_DIRECTORY; /// Failure returned by [`SharedMemoryBuilder::create()`] #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] @@ -159,4 +148,9 @@ pub trait SharedMemory: /// Releases the ownership of the [`SharedMemory`] meaning when it goes out of scope the /// underlying resource will not be removed. fn release_ownership(&mut self); + + /// The default suffix of every shared memory + fn default_suffix() -> FileName { + unsafe { FileName::new_unchecked(b".shm") } + } } diff --git a/iceoryx2-cal/src/shared_memory/posix.rs b/iceoryx2-cal/src/shared_memory/posix.rs index 8e0ef2f2a..345b7904f 100644 --- a/iceoryx2-cal/src/shared_memory/posix.rs +++ b/iceoryx2-cal/src/shared_memory/posix.rs @@ -32,30 +32,46 @@ use crate::static_storage::file::{ const IS_INITIALIZED_STATE_VALUE: u64 = 0xbeefaffedeadbeef; -#[derive(Clone, Debug)] -pub struct Configuration { +#[derive(Debug)] +pub struct Configuration { pub is_memory_locked: bool, pub permission: Permission, pub zero_memory: bool, path: Path, suffix: FileName, prefix: FileName, + _phantom: PhantomData, } -impl Default for Configuration { +impl Default for Configuration { fn default() -> Self { Self { is_memory_locked: false, permission: Permission::OWNER_ALL, zero_memory: true, - path: DEFAULT_PATH_HINT, - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, + path: Memory::::default_path_hint(), + suffix: Memory::::default_suffix(), + prefix: Memory::::default_prefix(), + _phantom: PhantomData, + } + } +} + +impl Clone for Configuration { + fn clone(&self) -> Self { + Self { + is_memory_locked: self.is_memory_locked, + permission: self.permission, + zero_memory: self.zero_memory, + path: self.path, + suffix: self.suffix, + prefix: self.prefix, + _phantom: self._phantom, } } } -impl NamedConceptConfiguration for Configuration { +impl NamedConceptConfiguration for Configuration { fn prefix(mut self, value: FileName) -> Self { self.prefix = value; self @@ -88,7 +104,7 @@ impl NamedConceptConfiguration for Configuration { pub struct Builder { name: FileName, size: usize, - config: Configuration, + config: Configuration, _phantom_allocator: PhantomData, } @@ -116,7 +132,7 @@ impl NamedConceptBuilder> } } - fn config(mut self, config: &Configuration) -> Self { + fn config(mut self, config: &Configuration) -> Self { self.config = config.clone(); self } @@ -305,7 +321,7 @@ impl NamedConcept for Memory { } impl NamedConceptMgmt for Memory { - type Configuration = Configuration; + type Configuration = Configuration; fn does_exist_cfg( name: &FileName, diff --git a/iceoryx2-cal/src/shared_memory/process_local.rs b/iceoryx2-cal/src/shared_memory/process_local.rs index 7f1b37c79..a12bcae04 100644 --- a/iceoryx2-cal/src/shared_memory/process_local.rs +++ b/iceoryx2-cal/src/shared_memory/process_local.rs @@ -69,24 +69,37 @@ static PROCESS_LOCAL_STORAGE: Lazy { suffix: FileName, prefix: FileName, path: Path, + _phantom: PhantomData, } -impl Default for Configuration { +impl Default for Configuration { fn default() -> Self { Self { - path: DEFAULT_PATH_HINT, - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, + path: Memory::::default_path_hint(), + suffix: Memory::::default_suffix(), + prefix: Memory::::default_prefix(), + _phantom: PhantomData, + } + } +} + +impl Clone for Configuration { + fn clone(&self) -> Self { + Self { + suffix: self.suffix, + prefix: self.prefix, + path: self.path, + _phantom: self._phantom, } } } -impl NamedConceptConfiguration for Configuration { +impl NamedConceptConfiguration for Configuration { fn prefix(mut self, value: FileName) -> Self { self.prefix = value; self @@ -119,7 +132,7 @@ impl NamedConceptConfiguration for Configuration { pub struct Builder { name: FileName, size: usize, - config: Configuration, + config: Configuration, _phantom_allocator: PhantomData, } @@ -135,7 +148,7 @@ impl NamedConceptBuilder> } } - fn config(mut self, config: &Configuration) -> Self { + fn config(mut self, config: &Configuration) -> Self { self.config = config.clone(); self } @@ -260,7 +273,7 @@ pub struct Memory { name: FileName, shm: Arc, has_ownership: bool, - config: Configuration, + config: Configuration, _phantom_data: PhantomData, } @@ -288,7 +301,7 @@ impl NamedConcept for Memory { } impl NamedConceptMgmt for Memory { - type Configuration = Configuration; + type Configuration = Configuration; fn list_cfg( config: &Self::Configuration, diff --git a/iceoryx2-cal/src/shared_memory_directory/file_reference_set.rs b/iceoryx2-cal/src/shared_memory_directory/file_reference_set.rs index 878b9d2e9..9c36c98bc 100644 --- a/iceoryx2-cal/src/shared_memory_directory/file_reference_set.rs +++ b/iceoryx2-cal/src/shared_memory_directory/file_reference_set.rs @@ -27,7 +27,7 @@ pub(crate) struct FileReferenceSetId(usize); #[derive(Debug, Clone, Copy)] #[repr(C)] struct Entry { - name: FileName, + name: Option, offset: usize, len: usize, } @@ -35,7 +35,7 @@ struct Entry { impl Entry { const fn default() -> Self { Self { - name: unsafe { FileName::new_unchecked(b"empty") }, + name: None, offset: 0, len: 0, } @@ -94,7 +94,7 @@ impl FileReferenceSet { unsafe { self.entries[id].get().write(Entry { - name: *name, + name: Some(*name), offset, len, }) @@ -115,7 +115,7 @@ impl FileReferenceSet { } if self.counter[i].increment_ref_counter_when_exist() { - if unsafe { &*self.entries[i].get() }.name == *name + if unsafe { &*self.entries[i].get() }.name == Some(*name) && !self.decision_counter[i].does_value_win(current_decision_count) { if self.counter[i].is_initialized() { @@ -194,7 +194,7 @@ impl FileReferenceSet { } pub(crate) fn get_name(&self, id: FileReferenceSetId) -> FileName { - unsafe { &*self.entries[id.0].get() }.name + unsafe { &*self.entries[id.0].get() }.name.unwrap() } pub(crate) fn get_payload(&self, id: FileReferenceSetId, base_address: usize) -> &[u8] { @@ -223,7 +223,7 @@ impl FileReferenceSet { fn find_entry(&self, name: &FileName) -> Option { for id in 0..self.ids.capacity() as usize { if self.counter[id].increment_ref_counter_when_initialized() { - if unsafe { *self.entries[id].get() }.name == *name { + if unsafe { *self.entries[id].get() }.name == Some(*name) { return Some(FileReferenceSetId(id)); } diff --git a/iceoryx2-cal/src/shared_memory_directory/mod.rs b/iceoryx2-cal/src/shared_memory_directory/mod.rs index d1e8c3538..2b25a25c3 100644 --- a/iceoryx2-cal/src/shared_memory_directory/mod.rs +++ b/iceoryx2-cal/src/shared_memory_directory/mod.rs @@ -26,8 +26,8 @@ use std::{alloc::Layout, fmt::Debug, marker::PhantomData}; use crate::shared_memory_directory::file::{File, FileCreator}; const MAX_NUMBER_OF_ENTRIES: usize = 512; -const MGMT_SHM_SUFFIX: FileName = unsafe { FileName::new_unchecked(b".dm") }; -const DATA_SHM_SUFFIX: FileName = unsafe { FileName::new_unchecked(b".dd") }; +const MGMT_SHM_SUFFIX: &[u8] = b".dm"; +const DATA_SHM_SUFFIX: &[u8] = b".dd"; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum SharedMemoryDirectoryCreateFileError { @@ -75,7 +75,7 @@ impl SharedMemoryDirectoryCreator { when MgmtShm::Builder::new(&self.name) .config( &MgmtShm::Configuration::default() - .suffix(MGMT_SHM_SUFFIX), + .suffix(unsafe {FileName::new_unchecked(MGMT_SHM_SUFFIX)}), ) .size(core::mem::size_of::() + core::mem::align_of::() - 1) .create(&::Configuration::default()), @@ -92,7 +92,7 @@ impl SharedMemoryDirectoryCreator { let mut data_shm = fail!(from self, when DataShm::Builder::new(&self.name).config( &DataShm::Configuration::default() - .suffix(DATA_SHM_SUFFIX), + .suffix(unsafe{FileName::new_unchecked(DATA_SHM_SUFFIX)}), ).size(self.size).create(allocator_config), "{} since the data segment could not be created.", msg); @@ -120,7 +120,7 @@ impl SharedMemoryDirectoryCreator { let data_shm = fail!(from self, when DataShm::Builder::new(&self.name) .config( &DataShm::Configuration::default() - .suffix(DATA_SHM_SUFFIX), + .suffix(unsafe{FileName::new_unchecked(DATA_SHM_SUFFIX)}), ) .open(), "{} since the data segment could not be opened.", msg); @@ -128,7 +128,7 @@ impl SharedMemoryDirectoryCreator { let mgmt_shm = fail!(from self, when MgmtShm::Builder::new(&self.name) .config( &MgmtShm::Configuration::default() - .suffix(MGMT_SHM_SUFFIX), + .suffix(unsafe{FileName::new_unchecked(MGMT_SHM_SUFFIX)}), ) .open(), "{} since the management segment could not be opened.", msg); @@ -217,14 +217,14 @@ impl< if !fail!(from origin, when DataShm::does_exist_cfg( name, - &DataShm::Configuration::default().suffix(DATA_SHM_SUFFIX)), + &DataShm::Configuration::default().suffix(unsafe{FileName::new_unchecked(DATA_SHM_SUFFIX)})), "{} \"{}\" exists due to a failure while checking the data segment.", msg, name) { return Ok(false); } let mgmt_result = fail!(from origin, - when MgmtShm::does_exist_cfg(name, &MgmtShm::Configuration::default().suffix(MGMT_SHM_SUFFIX)), + when MgmtShm::does_exist_cfg(name, &MgmtShm::Configuration::default().suffix(unsafe{FileName::new_unchecked(MGMT_SHM_SUFFIX)})), "{} \"{}\" exists due to a failure while checking the management segment.", msg, name ); @@ -236,7 +236,7 @@ impl< let origin = "SharedMemoryDirectory::list()"; Ok(fail!(from origin, when DataShm::list_cfg( - &DataShm::Configuration::default().suffix(DATA_SHM_SUFFIX) + &DataShm::Configuration::default().suffix(unsafe{FileName::new_unchecked(DATA_SHM_SUFFIX)}) ), "{} since the data segments could not be listed.", msg)) } @@ -250,14 +250,14 @@ impl< if !fail!(from origin, when DataShm::remove_cfg( name, - &DataShm::Configuration::default().suffix(DATA_SHM_SUFFIX)), + &DataShm::Configuration::default().suffix(unsafe{FileName::new_unchecked(DATA_SHM_SUFFIX)})), "{} \"{}\" since the data segment could not be removed.", msg, name) { return Ok(false); } let mgmt_result = fail!(from origin, - when MgmtShm::remove_cfg(name, &MgmtShm::Configuration::default().suffix(MGMT_SHM_SUFFIX)), + when MgmtShm::remove_cfg(name, &MgmtShm::Configuration::default().suffix(unsafe{FileName::new_unchecked(MGMT_SHM_SUFFIX)})), "{} \"{}\" since the management segment could not be removed.", msg, name ); diff --git a/iceoryx2-cal/src/static_storage/file.rs b/iceoryx2-cal/src/static_storage/file.rs index 4799accf1..a922548a4 100644 --- a/iceoryx2-cal/src/static_storage/file.rs +++ b/iceoryx2-cal/src/static_storage/file.rs @@ -64,9 +64,9 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { Configuration { - path: DEFAULT_PATH_HINT, - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, + path: Storage::default_path_hint(), + suffix: Storage::default_suffix(), + prefix: Storage::default_prefix(), } } } diff --git a/iceoryx2-cal/src/static_storage/mod.rs b/iceoryx2-cal/src/static_storage/mod.rs index e07349c44..a00072c9e 100644 --- a/iceoryx2-cal/src/static_storage/mod.rs +++ b/iceoryx2-cal/src/static_storage/mod.rs @@ -19,23 +19,12 @@ pub mod process_local; use std::fmt::Debug; use iceoryx2_bb_log::fail; -use iceoryx2_bb_posix::config::TEMP_DIRECTORY; use iceoryx2_bb_system_types::file_name::FileName; -use iceoryx2_bb_system_types::path::Path; use crate::named_concept::{ NamedConcept, NamedConceptBuilder, NamedConceptConfiguration, NamedConceptMgmt, }; -/// The default suffix of every static storage -pub const DEFAULT_SUFFIX: FileName = unsafe { FileName::new_unchecked(b".static_storage") }; - -/// The default prefix of every static storage -pub const DEFAULT_PREFIX: FileName = unsafe { FileName::new_unchecked(b"iox2_") }; - -/// The default path hint for every static storage -pub const DEFAULT_PATH_HINT: Path = TEMP_DIRECTORY; - #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] pub enum StaticStorageCreateError { AlreadyExists, @@ -131,4 +120,9 @@ pub trait StaticStorage: Debug + Sized + NamedConceptMgmt + NamedConcept { /// Acquires the ownership of the static storage. If the object goes out of scope the /// underlying resources are removed. fn acquire_ownership(&mut self); + + /// The default suffix of every static storage + fn default_suffix() -> FileName { + unsafe { FileName::new_unchecked(b".static_storage") } + } } diff --git a/iceoryx2-cal/src/static_storage/process_local.rs b/iceoryx2-cal/src/static_storage/process_local.rs index bb1b2f095..5f399bace 100644 --- a/iceoryx2-cal/src/static_storage/process_local.rs +++ b/iceoryx2-cal/src/static_storage/process_local.rs @@ -79,9 +79,9 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { Self { - path: DEFAULT_PATH_HINT, - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, + path: Storage::default_path_hint(), + suffix: Storage::default_suffix(), + prefix: Storage::default_prefix(), } } } diff --git a/iceoryx2-cal/src/zero_copy_connection/mod.rs b/iceoryx2-cal/src/zero_copy_connection/mod.rs index 8a5f90da2..b8e655dbf 100644 --- a/iceoryx2-cal/src/zero_copy_connection/mod.rs +++ b/iceoryx2-cal/src/zero_copy_connection/mod.rs @@ -17,7 +17,6 @@ use std::fmt::Debug; pub use crate::shared_memory::PointerOffset; use crate::static_storage::file::{NamedConcept, NamedConceptBuilder, NamedConceptMgmt}; -use iceoryx2_bb_posix::config::TEMP_DIRECTORY; pub use iceoryx2_bb_system_types::file_name::FileName; pub use iceoryx2_bb_system_types::path::Path; @@ -94,15 +93,6 @@ pub const DEFAULT_BUFFER_SIZE: usize = 4; pub const DEFAULT_ENABLE_SAFE_OVERFLOW: bool = false; pub const DEFAULT_MAX_BORROWED_SAMPLES: usize = 4; -/// The default suffix of every zero copy connection -pub const DEFAULT_SUFFIX: FileName = unsafe { FileName::new_unchecked(b".rx") }; - -/// The default prefix of every zero copy connection -pub const DEFAULT_PREFIX: FileName = unsafe { FileName::new_unchecked(b"iox2_") }; - -/// The default path hint for every zero copy connection -pub const DEFAULT_PATH_HINT: Path = TEMP_DIRECTORY; - pub trait ZeroCopyConnectionBuilder: NamedConceptBuilder { fn buffer_size(self, value: usize) -> Self; fn enable_safe_overflow(self, value: bool) -> Self; @@ -147,4 +137,9 @@ pub trait ZeroCopyConnection: Sized + NamedConceptMgmt { fn has_configurable_buffer_size() -> bool { false } + + /// The default suffix of every zero copy connection + fn default_suffix() -> FileName { + unsafe { FileName::new_unchecked(b".rx") } + } } diff --git a/iceoryx2-cal/src/zero_copy_connection/posix_shared_memory.rs b/iceoryx2-cal/src/zero_copy_connection/posix_shared_memory.rs index 7a4b39eb6..4de1d2238 100644 --- a/iceoryx2-cal/src/zero_copy_connection/posix_shared_memory.rs +++ b/iceoryx2-cal/src/zero_copy_connection/posix_shared_memory.rs @@ -43,9 +43,9 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { Self { - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, - path_hint: DEFAULT_PATH_HINT, + suffix: Connection::default_suffix(), + prefix: Connection::default_prefix(), + path_hint: Connection::default_path_hint(), } } } diff --git a/iceoryx2-cal/src/zero_copy_connection/process_local.rs b/iceoryx2-cal/src/zero_copy_connection/process_local.rs index 9ff5bb362..401d55013 100644 --- a/iceoryx2-cal/src/zero_copy_connection/process_local.rs +++ b/iceoryx2-cal/src/zero_copy_connection/process_local.rs @@ -57,9 +57,9 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { Self { - suffix: DEFAULT_SUFFIX, - prefix: DEFAULT_PREFIX, - path_hint: DEFAULT_PATH_HINT, + suffix: Connection::default_suffix(), + prefix: Connection::default_prefix(), + path_hint: Connection::default_path_hint(), } } } diff --git a/iceoryx2-cal/tests/communication_channel_trait_tests.rs b/iceoryx2-cal/tests/communication_channel_trait_tests.rs index 7517c0bb2..9c04c5e92 100644 --- a/iceoryx2-cal/tests/communication_channel_trait_tests.rs +++ b/iceoryx2-cal/tests/communication_channel_trait_tests.rs @@ -416,8 +416,9 @@ mod communication_channel { #[test] fn defaults_for_configuration_are_set_correctly>() { let config = ::Configuration::default(); - assert_that!(*config.get_suffix(), eq DEFAULT_SUFFIX); - assert_that!(*config.get_path_hint(), eq DEFAULT_PATH_HINT); + assert_that!(*config.get_suffix(), eq Sut::default_suffix()); + assert_that!(*config.get_path_hint(), eq Sut::default_path_hint()); + assert_that!(*config.get_prefix(), eq Sut::default_prefix()); } //#[cfg(not(any(target_os = "windows")))] diff --git a/iceoryx2-cal/tests/dynamic_storage_trait_tests.rs b/iceoryx2-cal/tests/dynamic_storage_trait_tests.rs index 4f6b385a2..c0a367d53 100644 --- a/iceoryx2-cal/tests/dynamic_storage_trait_tests.rs +++ b/iceoryx2-cal/tests/dynamic_storage_trait_tests.rs @@ -438,8 +438,9 @@ mod dynamic_storage { #[test] fn defaults_for_configuration_are_set_correctly>() { let config = ::Configuration::default(); - assert_that!(*config.get_suffix(), eq DEFAULT_SUFFIX); - assert_that!(*config.get_path_hint(), eq DEFAULT_PATH_HINT); + assert_that!(*config.get_suffix(), eq Sut::default_suffix()); + assert_that!(*config.get_path_hint(), eq Sut::default_path_hint()); + assert_that!(*config.get_prefix(), eq Sut::default_prefix()); } #[instantiate_tests(>)] diff --git a/iceoryx2-cal/tests/event_tests.rs b/iceoryx2-cal/tests/event_tests.rs index c2c64e146..438786e61 100644 --- a/iceoryx2-cal/tests/event_tests.rs +++ b/iceoryx2-cal/tests/event_tests.rs @@ -384,13 +384,14 @@ mod event { #[test] fn defaults_for_configuration_are_set_correctly>() { let config = ::Configuration::default(); - assert_that!(*config.get_suffix(), eq DEFAULT_SUFFIX); - assert_that!(*config.get_path_hint(), eq DEFAULT_PATH_HINT); + assert_that!(*config.get_suffix(), eq Sut::default_suffix()); + assert_that!(*config.get_path_hint(), eq Sut::default_path_hint()); + assert_that!(*config.get_prefix(), eq Sut::default_prefix()); } - #[instantiate_tests(>)] + #[instantiate_tests(>)] mod unix_datagram {} - #[instantiate_tests(>)] + #[instantiate_tests(>)] mod process_local {} } diff --git a/iceoryx2-cal/tests/shared_memory_trait_tests.rs b/iceoryx2-cal/tests/shared_memory_trait_tests.rs index 673f82a8e..c5f9ba5d2 100644 --- a/iceoryx2-cal/tests/shared_memory_trait_tests.rs +++ b/iceoryx2-cal/tests/shared_memory_trait_tests.rs @@ -299,8 +299,9 @@ mod shared_memory { #[test] fn defaults_for_configuration_are_set_correctly>() { let config = ::Configuration::default(); - assert_that!(*config.get_suffix(), eq DEFAULT_SUFFIX); - assert_that!(*config.get_path_hint(), eq DEFAULT_PATH_HINT); + assert_that!(*config.get_suffix(), eq Sut::default_suffix()); + assert_that!(*config.get_path_hint(), eq Sut::default_path_hint()); + assert_that!(*config.get_prefix(), eq Sut::default_prefix()); } #[instantiate_tests(>)] diff --git a/iceoryx2-cal/tests/static_storage_file_tests.rs b/iceoryx2-cal/tests/static_storage_file_tests.rs index 7cfe77398..91ccca7fc 100644 --- a/iceoryx2-cal/tests/static_storage_file_tests.rs +++ b/iceoryx2-cal/tests/static_storage_file_tests.rs @@ -40,7 +40,7 @@ fn static_storage_file_custom_path_and_suffix_works() { let content = "some storage content".to_string(); let config = Configuration::default() .suffix(unsafe { FileName::new_unchecked(b".blubbme") }) - .path_hint(TEST_DIRECTORY); + .path_hint(test_directory()); let storage_guard = Builder::new(&storage_name) .config(&config) @@ -66,7 +66,7 @@ fn static_storage_file_path_is_created_when_it_does_not_exist() { let storage_name = generate_name(); let content = "some more funky content".to_string(); let non_existing_path = - FilePath::from_path_and_file(&TEST_DIRECTORY, &generate_name()).unwrap(); + FilePath::from_path_and_file(&test_directory(), &generate_name()).unwrap(); Directory::remove(&non_existing_path.into()).ok(); let config = Configuration::default() @@ -97,9 +97,12 @@ fn static_storage_file_custom_path_and_suffix_list_storage_works() { let config = Configuration::default() .suffix(unsafe { FileName::new_unchecked(b".blubbme") }) .path_hint( - FilePath::from_path_and_file(&TEST_DIRECTORY, &FileName::new(b"non_existing").unwrap()) - .unwrap() - .into(), + FilePath::from_path_and_file( + &test_directory(), + &FileName::new(b"non_existing").unwrap(), + ) + .unwrap() + .into(), ); let content = "some storage content".to_string(); @@ -117,7 +120,8 @@ fn static_storage_file_custom_path_and_suffix_list_storage_works() { let mut some_files = vec![]; for _i in 0..NUMBER_OF_STORAGES { - let storage_name = FilePath::from_path_and_file(&TEST_DIRECTORY, &generate_name()).unwrap(); + let storage_name = + FilePath::from_path_and_file(&test_directory(), &generate_name()).unwrap(); FileBuilder::new(&storage_name) .creation_mode(CreationMode::PurgeAndCreate) .create() diff --git a/iceoryx2-cal/tests/static_storage_trait_tests.rs b/iceoryx2-cal/tests/static_storage_trait_tests.rs index c6d764a32..4481451bb 100644 --- a/iceoryx2-cal/tests/static_storage_trait_tests.rs +++ b/iceoryx2-cal/tests/static_storage_trait_tests.rs @@ -456,8 +456,9 @@ mod static_storage { #[test] fn defaults_for_configuration_are_set_correctly() { let config = ::Configuration::default(); - assert_that!(*config.get_suffix(), eq DEFAULT_SUFFIX); - assert_that!(*config.get_path_hint(), eq DEFAULT_PATH_HINT); + assert_that!(*config.get_suffix(), eq Sut::default_suffix()); + assert_that!(*config.get_path_hint(), eq Sut::default_path_hint()); + assert_that!(*config.get_prefix(), eq Sut::default_prefix()); } #[instantiate_tests()] diff --git a/iceoryx2-cal/tests/zero_copy_connection_trait_tests.rs b/iceoryx2-cal/tests/zero_copy_connection_trait_tests.rs index c8d5eaa19..e41dc0099 100644 --- a/iceoryx2-cal/tests/zero_copy_connection_trait_tests.rs +++ b/iceoryx2-cal/tests/zero_copy_connection_trait_tests.rs @@ -497,8 +497,9 @@ mod zero_copy_connection { #[test] fn defaults_for_configuration_are_set_correctly() { let config = ::Configuration::default(); - assert_that!(*config.get_suffix(), eq DEFAULT_SUFFIX); - assert_that!(*config.get_path_hint(), eq DEFAULT_PATH_HINT); + assert_that!(*config.get_suffix(), eq Sut::default_suffix()); + assert_that!(*config.get_path_hint(), eq Sut::default_path_hint()); + assert_that!(*config.get_prefix(), eq Sut::default_prefix()); } #[instantiate_tests()] diff --git a/iceoryx2-pal/concurrency-sync/src/condition_variable.rs b/iceoryx2-pal/concurrency-sync/src/condition_variable.rs index 32b10b81d..756150e8a 100644 --- a/iceoryx2-pal/concurrency-sync/src/condition_variable.rs +++ b/iceoryx2-pal/concurrency-sync/src/condition_variable.rs @@ -13,15 +13,18 @@ use core::sync::atomic::{AtomicU32, Ordering}; pub use crate::mutex::Mutex; +use crate::{semaphore::Semaphore, WaitAction, WaitResult}; pub struct ConditionVariable { - counter: AtomicU32, + number_of_waiters: AtomicU32, + semaphore: Semaphore, } impl Default for ConditionVariable { fn default() -> Self { Self { - counter: AtomicU32::new(0), + semaphore: Semaphore::new(0), + number_of_waiters: AtomicU32::new(0), } } } @@ -31,28 +34,37 @@ impl ConditionVariable { Self::default() } - pub fn notify(&self, wake_one_or_all: WakeOneOrAll) { - self.counter.fetch_add(1, Ordering::Relaxed); - wake_one_or_all(&self.counter); + pub fn notify_one(&self, wake_one: WakeOne) { + self.semaphore.post( + wake_one, + 1.min(self.number_of_waiters.load(Ordering::Relaxed)), + ); + } + + pub fn notify_all(&self, wake_all: WakeAll) { + self.semaphore + .post(wake_all, self.number_of_waiters.load(Ordering::Relaxed)); } pub fn wait< WakeOne: Fn(&AtomicU32), - Wait: Fn(&AtomicU32, &u32) -> bool, - MtxWait: Fn(&AtomicU32, &u32) -> bool, + Wait: Fn(&AtomicU32, &u32) -> WaitAction, + MtxWait: Fn(&AtomicU32, &u32) -> WaitAction, >( &self, mtx: &Mutex, mtx_wake_one: WakeOne, wait: Wait, mtx_wait: MtxWait, - ) -> bool { - let counter_value = self.counter.load(Ordering::Relaxed); + ) -> WaitResult { + self.number_of_waiters.fetch_add(1, Ordering::Relaxed); mtx.unlock(mtx_wake_one); - if !wait(&self.counter, &counter_value) { - return false; + if self.semaphore.wait(wait) == WaitResult::Interrupted { + self.number_of_waiters.fetch_sub(1, Ordering::Relaxed); + return WaitResult::Interrupted; } + self.number_of_waiters.fetch_sub(1, Ordering::Relaxed); // this maybe problematic when the wait has a timeout. it is possible that // the timeout is nearly doubled when wait is waken up at the end of the timeout diff --git a/iceoryx2-pal/concurrency-sync/src/lib.rs b/iceoryx2-pal/concurrency-sync/src/lib.rs index ea12bd325..d444448e2 100644 --- a/iceoryx2-pal/concurrency-sync/src/lib.rs +++ b/iceoryx2-pal/concurrency-sync/src/lib.rs @@ -19,3 +19,15 @@ pub mod condition_variable; pub mod mutex; pub mod rwlock; pub mod semaphore; + +#[derive(Debug, PartialEq, Eq)] +pub enum WaitAction { + Continue, + Abort, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum WaitResult { + Interrupted, + Success, +} diff --git a/iceoryx2-pal/concurrency-sync/src/mutex.rs b/iceoryx2-pal/concurrency-sync/src/mutex.rs index ce92953cf..20171a543 100644 --- a/iceoryx2-pal/concurrency-sync/src/mutex.rs +++ b/iceoryx2-pal/concurrency-sync/src/mutex.rs @@ -15,6 +15,8 @@ use core::{ sync::atomic::{AtomicU32, Ordering}, }; +use crate::{WaitAction, WaitResult}; + pub struct Mutex { // we use an AtomicU32 since it should be supported on nearly every platform state: AtomicU32, @@ -33,24 +35,24 @@ impl Mutex { } } - pub fn lock bool>(&self, wait: Wait) -> bool { - if self.uncontested_lock(crate::SPIN_REPETITIONS) { - return true; + pub fn lock WaitAction>(&self, wait: Wait) -> WaitResult { + if self.uncontested_lock(crate::SPIN_REPETITIONS) == WaitResult::Success { + return WaitResult::Success; } loop { - let keep_running = wait(&self.state, &1); + let action = wait(&self.state, &1); if self .state .compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed) .is_ok() { - return true; + return WaitResult::Success; } - if !keep_running { - return false; + if action == WaitAction::Abort { + return WaitResult::Interrupted; } } } @@ -60,15 +62,21 @@ impl Mutex { wake_one(&self.state); } - pub fn try_lock(&self) -> bool { - self.state + pub fn try_lock(&self) -> WaitResult { + if self + .state .compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed) .is_ok() + { + WaitResult::Success + } else { + WaitResult::Interrupted + } } - fn uncontested_lock(&self, retry_limit: u64) -> bool { - if self.try_lock() { - return true; + fn uncontested_lock(&self, retry_limit: u64) -> WaitResult { + if self.try_lock() == WaitResult::Success { + return WaitResult::Success; } let mut retry_counter = 0; @@ -81,10 +89,10 @@ impl Mutex { retry_counter += 1; if retry_limit == retry_counter { - return false; + return WaitResult::Interrupted; } } - true + WaitResult::Success } } diff --git a/iceoryx2-pal/concurrency-sync/src/rwlock.rs b/iceoryx2-pal/concurrency-sync/src/rwlock.rs index 4e74a434e..28c1a2bb9 100644 --- a/iceoryx2-pal/concurrency-sync/src/rwlock.rs +++ b/iceoryx2-pal/concurrency-sync/src/rwlock.rs @@ -15,7 +15,7 @@ use core::{ sync::atomic::{AtomicU32, Ordering}, }; -use crate::SPIN_REPETITIONS; +use crate::{WaitAction, WaitResult, SPIN_REPETITIONS}; const WRITE_LOCKED: u32 = u32::MAX; const UNLOCKED: u32 = 0; @@ -37,14 +37,15 @@ impl RwLockReaderPreference { Self::default() } - pub fn try_read_lock(&self) -> bool { + pub fn try_read_lock(&self) -> WaitResult { let reader_count = self.reader_count.load(Ordering::Relaxed); if reader_count == WRITE_LOCKED { - return false; + return WaitResult::Interrupted; } - self.reader_count + if self + .reader_count .compare_exchange( reader_count, reader_count + 1, @@ -52,9 +53,14 @@ impl RwLockReaderPreference { Ordering::Relaxed, ) .is_ok() + { + WaitResult::Success + } else { + WaitResult::Interrupted + } } - pub fn read_lock bool>(&self, wait: F) -> bool { + pub fn read_lock WaitAction>(&self, wait: F) -> WaitResult { let mut reader_count = self.reader_count.load(Ordering::Relaxed); let mut retry_counter = 0; @@ -66,13 +72,13 @@ impl RwLockReaderPreference { } if !keep_running { - return false; + return WaitResult::Interrupted; } if retry_counter < SPIN_REPETITIONS { retry_counter += 1; spin_loop(); - } else if !wait(&self.reader_count, &reader_count) { + } else if wait(&self.reader_count, &reader_count) == WaitAction::Abort { keep_running = false; } @@ -85,7 +91,7 @@ impl RwLockReaderPreference { Ordering::Acquire, Ordering::Relaxed, ) { - Ok(_) => return true, + Ok(_) => return WaitResult::Success, Err(v) => { reader_count = v; } @@ -103,13 +109,19 @@ impl RwLockReaderPreference { wake_one(&self.reader_count); } - pub fn try_write_lock(&self) -> bool { - self.reader_count + pub fn try_write_lock(&self) -> WaitResult { + if self + .reader_count .compare_exchange(UNLOCKED, WRITE_LOCKED, Ordering::Acquire, Ordering::Relaxed) .is_ok() + { + WaitResult::Success + } else { + WaitResult::Interrupted + } } - pub fn write_lock bool>(&self, wait: F) -> bool { + pub fn write_lock WaitAction>(&self, wait: F) -> WaitResult { let mut retry_counter = 0; let mut reader_count; @@ -122,17 +134,17 @@ impl RwLockReaderPreference { Ordering::Relaxed, ) { Err(v) => reader_count = v, - Ok(_) => return true, + Ok(_) => return WaitResult::Success, }; if !keep_running { - return false; + return WaitResult::Interrupted; } if retry_counter < SPIN_REPETITIONS { retry_counter += 1; spin_loop(); - } else if !wait(&self.reader_count, &reader_count) { + } else if wait(&self.reader_count, &reader_count) == WaitAction::Abort { keep_running = false; } } @@ -158,18 +170,24 @@ impl RwLockWriterPreference { Self::default() } - pub fn try_read_lock(&self) -> bool { + pub fn try_read_lock(&self) -> WaitResult { let state = self.state.load(Ordering::Relaxed); if state % 2 == 1 { - return false; + return WaitResult::Interrupted; } - self.state + if self + .state .compare_exchange(state, state + 2, Ordering::Acquire, Ordering::Relaxed) .is_ok() + { + WaitResult::Success + } else { + WaitResult::Interrupted + } } - pub fn read_lock bool>(&self, wait: F) -> bool { + pub fn read_lock WaitAction>(&self, wait: F) -> WaitResult { let mut state = self.state.load(Ordering::Relaxed); let mut retry_counter = 0; @@ -177,13 +195,13 @@ impl RwLockWriterPreference { loop { if state % 2 == 1 { if !keep_running { - return false; + return WaitResult::Interrupted; } if retry_counter < SPIN_REPETITIONS { retry_counter += 1; spin_loop(); - } else if !wait(&self.state, &state) { + } else if wait(&self.state, &state) == WaitAction::Abort { keep_running = false; } state = self.state.load(Ordering::Relaxed); @@ -194,7 +212,7 @@ impl RwLockWriterPreference { Ordering::Acquire, Ordering::Relaxed, ) { - Ok(_) => return true, + Ok(_) => return WaitResult::Success, Err(v) => state = v, } } @@ -218,14 +236,20 @@ impl RwLockWriterPreference { } } - pub fn try_write_lock(&self) -> bool { - self.state + pub fn try_write_lock(&self) -> WaitResult { + if self + .state .compare_exchange(0, WRITE_LOCKED, Ordering::Acquire, Ordering::Relaxed) .is_ok() + { + WaitResult::Success + } else { + WaitResult::Interrupted + } } pub fn write_lock< - Wait: Fn(&AtomicU32, &u32) -> bool, + Wait: Fn(&AtomicU32, &u32) -> WaitAction, WakeOne: Fn(&AtomicU32), WakeAll: Fn(&AtomicU32), >( @@ -233,7 +257,7 @@ impl RwLockWriterPreference { wait: Wait, wake_one: WakeOne, wake_all: WakeAll, - ) -> bool { + ) -> WaitResult { let mut state = self.state.load(Ordering::Relaxed); let mut keep_running = true; @@ -246,7 +270,7 @@ impl RwLockWriterPreference { Ordering::Acquire, Ordering::Relaxed, ) { - Ok(_) => return true, + Ok(_) => return WaitResult::Success, Err(v) => state = v, } } @@ -264,12 +288,12 @@ impl RwLockWriterPreference { self.writer_wake_counter.fetch_add(1, Ordering::Relaxed); wake_one(&self.writer_wake_counter); wake_all(&self.state); - return false; + return WaitResult::Interrupted; } Err(v) => state = v, } } else { - return false; + return WaitResult::Interrupted; } } } @@ -288,7 +312,7 @@ impl RwLockWriterPreference { retry_counter += 1; } else { let writer_wake_counter = self.writer_wake_counter.load(Ordering::Relaxed); - if !wait(&self.writer_wake_counter, &writer_wake_counter) { + if wait(&self.writer_wake_counter, &writer_wake_counter) == WaitAction::Abort { keep_running = false; } } diff --git a/iceoryx2-pal/concurrency-sync/src/semaphore.rs b/iceoryx2-pal/concurrency-sync/src/semaphore.rs index 70ff2acfb..b0a962cf5 100644 --- a/iceoryx2-pal/concurrency-sync/src/semaphore.rs +++ b/iceoryx2-pal/concurrency-sync/src/semaphore.rs @@ -15,7 +15,7 @@ use core::{ sync::atomic::{AtomicU32, Ordering}, }; -use crate::SPIN_REPETITIONS; +use crate::{WaitAction, WaitResult, SPIN_REPETITIONS}; pub struct Semaphore { value: AtomicU32, @@ -32,12 +32,12 @@ impl Semaphore { self.value.load(Ordering::Relaxed) } - pub fn post(&self, wakeup: WakeUp) { - self.value.fetch_add(1, Ordering::Acquire); + pub fn post(&self, wakeup: WakeUp, value: u32) { + self.value.fetch_add(value, Ordering::Acquire); wakeup(&self.value); } - pub fn wait bool>(&self, wait: Wait) -> bool { + pub fn wait WaitAction>(&self, wait: Wait) -> WaitResult { let mut retry_counter = 0; let mut current_value = self.value.load(Ordering::Relaxed); @@ -49,13 +49,13 @@ impl Semaphore { } if !keep_running { - return false; + return WaitResult::Interrupted; } if retry_counter < SPIN_REPETITIONS { spin_loop(); retry_counter += 1; - } else if !wait(&self.value, ¤t_value) { + } else if wait(&self.value, ¤t_value) == WaitAction::Abort { keep_running = false; } current_value = self.value.load(Ordering::Relaxed); @@ -72,15 +72,15 @@ impl Semaphore { } } - true + WaitResult::Success } - pub fn try_wait(&self) -> bool { + pub fn try_wait(&self) -> WaitResult { let mut current_value = self.value.load(Ordering::Relaxed); loop { if current_value == 0 { - return false; + return WaitResult::Interrupted; } match self.value.compare_exchange_weak( @@ -89,7 +89,7 @@ impl Semaphore { Ordering::Release, Ordering::Relaxed, ) { - Ok(_) => return true, + Ok(_) => return WaitResult::Success, Err(v) => current_value = v, } } diff --git a/iceoryx2-pal/concurrency-sync/tests/condition_variable_tests.rs b/iceoryx2-pal/concurrency-sync/tests/condition_variable_tests.rs index aeb490b75..0b7f48f1c 100644 --- a/iceoryx2-pal/concurrency-sync/tests/condition_variable_tests.rs +++ b/iceoryx2-pal/concurrency-sync/tests/condition_variable_tests.rs @@ -12,94 +12,103 @@ use std::{ hint::spin_loop, - sync::atomic::{AtomicU32, Ordering}, + sync::atomic::{AtomicBool, AtomicU32, Ordering}, time::Duration, }; use iceoryx2_bb_testing::{assert_that, watchdog::Watchdog}; -use iceoryx2_pal_concurrency_sync::{barrier::Barrier, condition_variable::*}; +use iceoryx2_pal_concurrency_sync::{ + barrier::Barrier, condition_variable::*, WaitAction, WaitResult, +}; const TIMEOUT: Duration = Duration::from_millis(25); +struct ThreadInWait { + thread_id: AtomicU32, + thread_in_wait: [AtomicBool; NUMBER_OF_THREADS], +} + +impl ThreadInWait { + fn new() -> Self { + const FALSE: AtomicBool = AtomicBool::new(false); + Self { + thread_id: AtomicU32::new(0), + thread_in_wait: [FALSE; NUMBER_OF_THREADS], + } + } + + fn get_id(&self) -> usize { + self.thread_id.fetch_add(1, Ordering::Relaxed) as usize + } + + fn signal_is_in_wait(&self, id: usize) { + self.thread_in_wait[id].store(true, Ordering::Relaxed); + } + + fn block_until_all_threads_are_waiting(&self) { + loop { + let mut wait_for_thread = false; + for v in &self.thread_in_wait { + if !v.load(Ordering::Relaxed) { + wait_for_thread = true; + break; + } + } + + if !wait_for_thread { + break; + } + } + } +} + #[test] fn condition_variable_notify_one_unblocks_one() { - const NUMBER_OF_THREADS: u32 = 3; + const NUMBER_OF_THREADS: usize = 3; let _watchdog = Watchdog::new(Duration::from_secs(10)); - let barrier = Barrier::new(NUMBER_OF_THREADS + 1); + let barrier = Barrier::new(NUMBER_OF_THREADS as u32 + 1); let sut = ConditionVariable::new(); let mtx = Mutex::new(); let counter = AtomicU32::new(0); let triggered_thread = AtomicU32::new(0); + let thread_in_wait = ThreadInWait::::new(); std::thread::scope(|s| { - s.spawn(|| { - barrier.wait(|_, _| {}, |_| {}); - mtx.lock(|_, _| true); - let wait_result = sut.wait( - &mtx, - |_| {}, - |_, _| { - while triggered_thread.load(Ordering::Relaxed) < 1 { - spin_loop() - } - true - }, - |_, _| true, - ); - counter.fetch_add(1, Ordering::Relaxed); - mtx.unlock(|_| {}); - assert_that!(wait_result, eq true); - }); - - s.spawn(|| { - barrier.wait(|_, _| {}, |_| {}); - mtx.lock(|_, _| true); - let wait_result = sut.wait( - &mtx, - |_| {}, - |_, _| { - while triggered_thread.load(Ordering::Relaxed) < 2 { - spin_loop() - } - true - }, - |_, _| true, - ); - counter.fetch_add(1, Ordering::Relaxed); - mtx.unlock(|_| {}); - assert_that!(wait_result, eq true); - }); - - s.spawn(|| { - barrier.wait(|_, _| {}, |_| {}); - mtx.lock(|_, _| true); - let wait_result = sut.wait( - &mtx, - |_| {}, - |_, _| { - while triggered_thread.load(Ordering::Relaxed) < 3 { - spin_loop() - } - true - }, - |_, _| true, - ); - counter.fetch_add(1, Ordering::Relaxed); - mtx.unlock(|_| {}); - assert_that!(wait_result, eq true); - }); + for _ in 0..NUMBER_OF_THREADS { + s.spawn(|| { + barrier.wait(|_, _| {}, |_| {}); + mtx.lock(|_, _| WaitAction::Continue); + let id = thread_in_wait.get_id(); + let wait_result = sut.wait( + &mtx, + |_| {}, + |_, _| { + thread_in_wait.signal_is_in_wait(id); + while triggered_thread.load(Ordering::Relaxed) < 1 { + spin_loop() + } + WaitAction::Continue + }, + |_, _| WaitAction::Continue, + ); + counter.fetch_add(1, Ordering::Relaxed); + mtx.unlock(|_| {}); + assert_that!(wait_result, eq WaitResult::Success); + }); + } barrier.wait(|_, _| {}, |_| {}); + thread_in_wait.block_until_all_threads_are_waiting(); std::thread::sleep(TIMEOUT); let counter_old = counter.load(Ordering::Relaxed); for i in 0..NUMBER_OF_THREADS { - sut.notify(|_| { + sut.notify_one(|_| { triggered_thread.fetch_add(1, Ordering::Relaxed); }); // this can cause a deadlock but the watchdog takes care of it - while counter.load(Ordering::Relaxed) <= i {} + while counter.load(Ordering::Relaxed) as usize <= i {} } assert_that!(counter_old, eq 0); @@ -108,41 +117,47 @@ fn condition_variable_notify_one_unblocks_one() { #[test] fn condition_variable_notify_all_unblocks_all() { - const NUMBER_OF_THREADS: u32 = 5; - let barrier = Barrier::new(NUMBER_OF_THREADS + 1); + const NUMBER_OF_THREADS: usize = 5; + let _watchdog = Watchdog::new(Duration::from_secs(10)); + let barrier = Barrier::new(NUMBER_OF_THREADS as u32 + 1); let sut = ConditionVariable::new(); let mtx = Mutex::new(); let counter = AtomicU32::new(0); let triggered_thread = AtomicU32::new(0); + let thread_in_wait = ThreadInWait::::new(); std::thread::scope(|s| { let mut threads = vec![]; for _ in 0..NUMBER_OF_THREADS { threads.push(s.spawn(|| { barrier.wait(|_, _| {}, |_| {}); - mtx.lock(|_, _| true); + mtx.lock(|_, _| WaitAction::Continue); + let id = thread_in_wait.get_id(); let wait_result = sut.wait( &mtx, |_| {}, |_, _| { + thread_in_wait.signal_is_in_wait(id); while triggered_thread.load(Ordering::Relaxed) < 1 { spin_loop() } - true + WaitAction::Continue }, - |_, _| true, + |_, _| WaitAction::Continue, ); counter.fetch_add(1, Ordering::Relaxed); mtx.unlock(|_| {}); - assert_that!(wait_result, eq true); + assert_that!(wait_result, eq WaitResult::Success); })); } barrier.wait(|_, _| {}, |_| {}); + + thread_in_wait.block_until_all_threads_are_waiting(); std::thread::sleep(TIMEOUT); let counter_old = counter.load(Ordering::Relaxed); - sut.notify(|_| { + sut.notify_all(|_| { triggered_thread.fetch_add(1, Ordering::Relaxed); }); @@ -151,53 +166,57 @@ fn condition_variable_notify_all_unblocks_all() { } assert_that!(counter_old, eq 0); - assert_that!(counter.load(Ordering::Relaxed), eq NUMBER_OF_THREADS); + assert_that!(counter.load(Ordering::Relaxed), eq NUMBER_OF_THREADS as u32); }); } #[test] fn condition_variable_mutex_is_locked_when_wait_returns() { - const NUMBER_OF_THREADS: u32 = 5; - let barrier = Barrier::new(NUMBER_OF_THREADS + 1); + const NUMBER_OF_THREADS: usize = 5; + let _watchdog = Watchdog::new(Duration::from_secs(10)); + let barrier = Barrier::new(NUMBER_OF_THREADS as u32 + 1); let sut = ConditionVariable::new(); let mtx = Mutex::new(); let counter = AtomicU32::new(0); let triggered_thread = AtomicU32::new(0); + let thread_in_wait = ThreadInWait::::new(); std::thread::scope(|s| { for _ in 0..NUMBER_OF_THREADS { s.spawn(|| { barrier.wait(|_, _| {}, |_| {}); - mtx.lock(|_, _| true); + mtx.lock(|_, _| WaitAction::Continue); + let id = thread_in_wait.get_id(); let wait_result = sut.wait( &mtx, |_| {}, |_, _| { + thread_in_wait.signal_is_in_wait(id); while triggered_thread.load(Ordering::Relaxed) < 1 { spin_loop() } - true + WaitAction::Continue }, - |_, _| true, + |_, _| WaitAction::Continue, ); counter.fetch_add(1, Ordering::Relaxed); - assert_that!(wait_result, eq true); - assert_that!(mtx.try_lock(), eq false); + assert_that!(wait_result, eq WaitResult::Success); + assert_that!(mtx.try_lock(), eq WaitResult::Interrupted); // unlock thread since we own it mtx.unlock(|_| {}); }); } barrier.wait(|_, _| {}, |_| {}); + + thread_in_wait.block_until_all_threads_are_waiting(); std::thread::sleep(TIMEOUT); let counter_old = counter.load(Ordering::Relaxed); - for _ in 0..NUMBER_OF_THREADS { - sut.notify(|_| { - triggered_thread.fetch_add(1, Ordering::Relaxed); - }); - std::thread::sleep(TIMEOUT); - } + sut.notify_all(|_| { + triggered_thread.fetch_add(1, Ordering::Relaxed); + }); + std::thread::sleep(TIMEOUT); assert_that!(counter_old, eq 0); }); @@ -207,7 +226,7 @@ fn condition_variable_mutex_is_locked_when_wait_returns() { fn condition_variable_wait_returns_false_when_functor_returns_false() { let sut = ConditionVariable::new(); let mtx = Mutex::new(); - mtx.lock(|_, _| true); - assert_that!(!sut.wait(&mtx, |_| {}, |_, _| false, |_, _| true), eq true); + mtx.lock(|_, _| WaitAction::Continue); + assert_that!(sut.wait(&mtx, |_| {}, |_, _| WaitAction::Abort, |_, _| WaitAction::Continue), eq WaitResult::Interrupted); mtx.unlock(|_| {}); } diff --git a/iceoryx2-pal/concurrency-sync/tests/mutex_tests.rs b/iceoryx2-pal/concurrency-sync/tests/mutex_tests.rs index fc76c5b3c..28f327d35 100644 --- a/iceoryx2-pal/concurrency-sync/tests/mutex_tests.rs +++ b/iceoryx2-pal/concurrency-sync/tests/mutex_tests.rs @@ -16,7 +16,7 @@ use std::{ }; use iceoryx2_bb_testing::assert_that; -use iceoryx2_pal_concurrency_sync::mutex::*; +use iceoryx2_pal_concurrency_sync::{mutex::*, WaitAction, WaitResult}; const TIMEOUT: Duration = Duration::from_millis(25); @@ -29,7 +29,7 @@ fn mutex_lock_blocks() { sut.try_lock(); let t1 = s.spawn(|| { - sut.lock(|_, _| true); + sut.lock(|_, _| WaitAction::Continue); counter.fetch_add(1, Ordering::Relaxed); sut.unlock(|_| {}); }); @@ -57,15 +57,15 @@ fn mutex_lock_with_timeout_blocks() { let start = Instant::now(); while atomic.load(Ordering::Relaxed) == *value { if start.elapsed() > TIMEOUT * 2 { - return false; + return WaitAction::Abort; } } - true + WaitAction::Continue }); counter.fetch_add(1, Ordering::Relaxed); sut.unlock(|_| {}); - assert_that!(lock_result, eq true); + assert_that!(lock_result, eq WaitResult::Success); }); std::thread::sleep(TIMEOUT); @@ -84,14 +84,14 @@ fn mutex_lock_with_timeout_and_fails_after_timeout() { sut.try_lock(); - assert_that!(!sut.lock(|atomic, value| { + assert_that!(sut.lock(|atomic, value| { let start = Instant::now(); while atomic.load(Ordering::Relaxed) == *value { if start.elapsed() > TIMEOUT { - return false; + return WaitAction::Abort; } } - true - }), eq true); + WaitAction::Continue + }), eq WaitResult::Interrupted); } diff --git a/iceoryx2-pal/concurrency-sync/tests/rwlock_tests.rs b/iceoryx2-pal/concurrency-sync/tests/rwlock_tests.rs index 9564728ab..e3d5de82f 100644 --- a/iceoryx2-pal/concurrency-sync/tests/rwlock_tests.rs +++ b/iceoryx2-pal/concurrency-sync/tests/rwlock_tests.rs @@ -16,7 +16,7 @@ use std::{ }; use iceoryx2_bb_testing::assert_that; -use iceoryx2_pal_concurrency_sync::{barrier::Barrier, rwlock::*}; +use iceoryx2_pal_concurrency_sync::{barrier::Barrier, rwlock::*, WaitAction, WaitResult}; const TIMEOUT: Duration = Duration::from_millis(25); @@ -24,48 +24,48 @@ const TIMEOUT: Duration = Duration::from_millis(25); fn rwlock_reader_preference_try_write_lock_blocks_read_locks() { let sut = RwLockReaderPreference::new(); - assert_that!(sut.try_write_lock(), eq true); - assert_that!(!sut.try_write_lock(), eq true); - assert_that!(!sut.write_lock(|_, _| false), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Success); + assert_that!(sut.try_write_lock(), eq WaitResult::Interrupted); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); - assert_that!(!sut.try_read_lock(), eq true); - assert_that!(!sut.read_lock(|_, _| false), eq true); + assert_that!(sut.try_read_lock(), eq WaitResult::Interrupted); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); } #[test] fn rwlock_reader_preference_multiple_read_locks_block_write_lock() { let sut = RwLockReaderPreference::new(); - assert_that!(sut.try_read_lock(), eq true); - assert_that!(sut.try_read_lock(), eq true); - assert_that!(sut.read_lock(|_, _| false), eq true); - assert_that!(sut.read_lock(|_, _| false), eq true); + assert_that!(sut.try_read_lock(), eq WaitResult::Success); + assert_that!(sut.try_read_lock(), eq WaitResult::Success); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Success); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Success); - assert_that!(!sut.try_write_lock(), eq true); - assert_that!(!sut.write_lock(|_, _| false), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Interrupted); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); } #[test] fn rwlock_reader_preference_write_lock_and_unlock_works() { let sut = RwLockReaderPreference::new(); - assert_that!(sut.write_lock(|_, _| false), eq true); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort), eq WaitResult::Success); - assert_that!(!sut.try_write_lock(), eq true); - assert_that!(!sut.try_read_lock(), eq true); - assert_that!(!sut.read_lock(|_, _| false), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Interrupted); + assert_that!(sut.try_read_lock(), eq WaitResult::Interrupted); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); sut.unlock(|_| {}); - assert_that!(sut.try_write_lock(), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Success); - assert_that!(!sut.write_lock(|_, _| false), eq true); - assert_that!(!sut.try_read_lock(), eq true); - assert_that!(!sut.read_lock(|_, _| false), eq true); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); + assert_that!(sut.try_read_lock(), eq WaitResult::Interrupted); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); sut.unlock(|_| {}); - assert_that!(sut.write_lock(|_, _| false), eq true); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort), eq WaitResult::Success); } #[test] @@ -74,16 +74,16 @@ fn rwlock_reader_preference_try_read_lock_and_unlock_works() { let sut = RwLockReaderPreference::new(); for _ in 0..NUMBER_OF_READ_LOCKS { - assert_that!(sut.try_read_lock(), eq true); - assert_that!(!sut.try_write_lock(), eq true); - assert_that!(!sut.write_lock(|_, _| false), eq true); + assert_that!(sut.try_read_lock(), eq WaitResult::Success); + assert_that!(sut.try_write_lock(), eq WaitResult::Interrupted); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); } for _ in 0..NUMBER_OF_READ_LOCKS { sut.unlock(|_| {}); } - assert_that!(sut.try_write_lock(), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Success); } #[test] @@ -92,16 +92,16 @@ fn rwlock_reader_preference_read_lock_and_unlock_works() { let sut = RwLockReaderPreference::new(); for _ in 0..NUMBER_OF_READ_LOCKS { - assert_that!(sut.read_lock(|_, _| false), eq true); - assert_that!(!sut.try_write_lock(), eq true); - assert_that!(!sut.write_lock(|_, _| false), eq true); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Success); + assert_that!(sut.try_write_lock(), eq WaitResult::Interrupted); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); } for _ in 0..NUMBER_OF_READ_LOCKS { sut.unlock(|_| {}); } - assert_that!(sut.write_lock(|_, _| false), eq true); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort), eq WaitResult::Success); } #[test] @@ -118,11 +118,11 @@ fn rwlock_reader_preference_read_lock_blocks_only_write_locks() { let write_counter = AtomicU32::new(0); std::thread::scope(|s| { - assert_that!(sut.try_read_lock(), eq true); + assert_that!(sut.try_read_lock(), eq WaitResult::Success); for _ in 0..WRITE_THREADS { s.spawn(|| { barrier.wait(|_, _| {}, |_| {}); - sut.write_lock(|_, _| true); + sut.write_lock(|_, _| WaitAction::Continue); write_counter.fetch_add(1, Ordering::Relaxed); sut.unlock(|_| {}); barrier_write.wait(|_, _| {}, |_| {}); @@ -132,7 +132,7 @@ fn rwlock_reader_preference_read_lock_blocks_only_write_locks() { for _ in 0..READ_THREADS { s.spawn(|| { barrier.wait(|_, _| {}, |_| {}); - sut.read_lock(|_, _| true); + sut.read_lock(|_, _| WaitAction::Continue); read_counter.fetch_add(1, Ordering::Relaxed); barrier_read.wait(|_, _| {}, |_| {}); sut.unlock(|_| {}); @@ -171,11 +171,11 @@ fn rwlock_reader_preference_write_lock_blocks_everything() { let write_counter = AtomicU32::new(0); std::thread::scope(|s| { - assert_that!(sut.try_write_lock(), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Success); for _ in 0..WRITE_THREADS { s.spawn(|| { barrier.wait(|_, _| {}, |_| {}); - sut.write_lock(|_, _| true); + sut.write_lock(|_, _| WaitAction::Continue); let current_read_counter = read_counter.load(Ordering::Relaxed); write_counter.fetch_add(1, Ordering::Relaxed); std::thread::sleep(TIMEOUT); @@ -190,7 +190,7 @@ fn rwlock_reader_preference_write_lock_blocks_everything() { for _ in 0..READ_THREADS { s.spawn(|| { barrier.wait(|_, _| {}, |_| {}); - sut.read_lock(|_, _| true); + sut.read_lock(|_, _| WaitAction::Continue); read_counter.fetch_add(1, Ordering::Relaxed); sut.unlock(|_| {}); @@ -226,48 +226,48 @@ fn rwlock_reader_preference_write_lock_blocks_everything() { fn rwlock_writer_preference_try_write_lock_blocks_read_locks() { let sut = RwLockWriterPreference::new(); - assert_that!(sut.try_write_lock(), eq true); - assert_that!(!sut.try_write_lock(), eq true); - assert_that!(!sut.write_lock(|_, _| false, |_| {}, |_| {}), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Success); + assert_that!(sut.try_write_lock(), eq WaitResult::Interrupted); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort, |_| {}, |_| {}), eq WaitResult::Interrupted); - assert_that!(!sut.try_read_lock(), eq true); - assert_that!(!sut.read_lock(|_, _| false), eq true); + assert_that!(sut.try_read_lock(), eq WaitResult::Interrupted); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); } #[test] fn rwlock_writer_preference_multiple_read_locks_block_write_lock() { let sut = RwLockWriterPreference::new(); - assert_that!(sut.try_read_lock(), eq true); - assert_that!(sut.try_read_lock(), eq true); - assert_that!(sut.read_lock(|_, _| false), eq true); - assert_that!(sut.read_lock(|_, _| false), eq true); + assert_that!(sut.try_read_lock(), eq WaitResult::Success); + assert_that!(sut.try_read_lock(), eq WaitResult::Success); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Success); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Success); - assert_that!(!sut.try_write_lock(), eq true); - assert_that!(!sut.write_lock(|_, _| false, |_| {}, |_| {}), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Interrupted); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort, |_| {}, |_| {}), eq WaitResult::Interrupted); } #[test] fn rwlock_writer_preference_write_lock_and_unlock_works() { let sut = RwLockWriterPreference::new(); - assert_that!(sut.write_lock(|_, _| false, |_| {}, |_| {}), eq true); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort, |_| {}, |_| {}), eq WaitResult::Success); - assert_that!(!sut.try_write_lock(), eq true); - assert_that!(!sut.try_read_lock(), eq true); - assert_that!(!sut.read_lock(|_, _| false), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Interrupted); + assert_that!(sut.try_read_lock(), eq WaitResult::Interrupted); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); sut.unlock(|_| {}, |_| {}); - assert_that!(sut.try_write_lock(), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Success); - assert_that!(!sut.write_lock(|_, _| false, |_| {}, |_| {}), eq true); - assert_that!(!sut.try_read_lock(), eq true); - assert_that!(!sut.read_lock(|_, _| false), eq true); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort, |_| {}, |_| {}), eq WaitResult::Interrupted); + assert_that!(sut.try_read_lock(), eq WaitResult::Interrupted); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); sut.unlock(|_| {}, |_| {}); - assert_that!(sut.write_lock(|_, _| false, |_| {}, |_| {}), eq true); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort, |_| {}, |_| {}), eq WaitResult::Success); } #[test] @@ -276,16 +276,16 @@ fn rwlock_writer_preference_try_read_lock_and_unlock_works() { let sut = RwLockWriterPreference::new(); for _ in 0..NUMBER_OF_READ_LOCKS { - assert_that!(sut.try_read_lock(), eq true); - assert_that!(!sut.try_write_lock(), eq true); - assert_that!(!sut.write_lock(|_, _| false, |_| {}, |_| {}), eq true); + assert_that!(sut.try_read_lock(), eq WaitResult::Success); + assert_that!(sut.try_write_lock(), eq WaitResult::Interrupted); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort, |_| {}, |_| {}), eq WaitResult::Interrupted); } for _ in 0..NUMBER_OF_READ_LOCKS { sut.unlock(|_| {}, |_| {}); } - assert_that!(sut.try_write_lock(), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Success); } #[test] @@ -294,16 +294,16 @@ fn rwlock_writer_preference_read_lock_and_unlock_works() { let sut = RwLockWriterPreference::new(); for _ in 0..NUMBER_OF_READ_LOCKS { - assert_that!(sut.read_lock(|_, _| false), eq true); - assert_that!(!sut.try_write_lock(), eq true); - assert_that!(!sut.write_lock(|_, _| false, |_| {}, |_| {}), eq true); + assert_that!(sut.read_lock(|_, _| WaitAction::Abort), eq WaitResult::Success); + assert_that!(sut.try_write_lock(), eq WaitResult::Interrupted); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort, |_| {}, |_| {}), eq WaitResult::Interrupted); } for _ in 0..NUMBER_OF_READ_LOCKS { sut.unlock(|_| {}, |_| {}); } - assert_that!(sut.write_lock(|_, _| false, |_| {}, |_| {}), eq true); + assert_that!(sut.write_lock(|_, _| WaitAction::Abort, |_| {}, |_| {}), eq WaitResult::Success); } #[test] @@ -319,11 +319,11 @@ fn rwlock_writer_preference_write_lock_blocks_everything() { let write_counter = AtomicU32::new(0); std::thread::scope(|s| { - assert_that!(sut.try_write_lock(), eq true); + assert_that!(sut.try_write_lock(), eq WaitResult::Success); for _ in 0..WRITE_THREADS { s.spawn(|| { barrier.wait(|_, _| {}, |_| {}); - sut.write_lock(|_, _| true, |_| {}, |_| {}); + sut.write_lock(|_, _| WaitAction::Continue, |_| {}, |_| {}); let current_read_counter = read_counter.load(Ordering::Relaxed); write_counter.fetch_add(1, Ordering::Relaxed); std::thread::sleep(TIMEOUT); @@ -338,7 +338,7 @@ fn rwlock_writer_preference_write_lock_blocks_everything() { for _ in 0..READ_THREADS { s.spawn(|| { barrier.wait(|_, _| {}, |_| {}); - sut.read_lock(|_, _| true); + sut.read_lock(|_, _| WaitAction::Continue); read_counter.fetch_add(1, Ordering::Relaxed); sut.unlock(|_| {}, |_| {}); diff --git a/iceoryx2-pal/concurrency-sync/tests/semaphore_tests.rs b/iceoryx2-pal/concurrency-sync/tests/semaphore_tests.rs index a3d6eeada..97ca08425 100644 --- a/iceoryx2-pal/concurrency-sync/tests/semaphore_tests.rs +++ b/iceoryx2-pal/concurrency-sync/tests/semaphore_tests.rs @@ -16,7 +16,7 @@ use std::{ }; use iceoryx2_bb_testing::assert_that; -use iceoryx2_pal_concurrency_sync::semaphore::*; +use iceoryx2_pal_concurrency_sync::{semaphore::*, WaitAction, WaitResult}; const TIMEOUT: Duration = Duration::from_millis(25); @@ -26,18 +26,16 @@ fn semaphore_post_and_try_wait_works() { let sut = Semaphore::new(initial_value); for _ in 0..initial_value { - assert_that!(sut.try_wait(), eq true); + assert_that!(sut.try_wait(), eq WaitResult::Success); } - assert_that!(!sut.try_wait(), eq true); + assert_that!(sut.try_wait(), eq WaitResult::Interrupted); - for _ in 0..initial_value { - sut.post(|_| {}); - } + sut.post(|_| {}, initial_value); for _ in 0..initial_value { - assert_that!(sut.try_wait(), eq true); + assert_that!(sut.try_wait(), eq WaitResult::Success); } - assert_that!(!sut.try_wait(), eq true); + assert_that!(sut.try_wait(), eq WaitResult::Interrupted); } #[test] @@ -46,18 +44,16 @@ fn semaphore_post_and_wait_works() { let sut = Semaphore::new(initial_value); for _ in 0..initial_value { - assert_that!(sut.wait(|_, _| false), eq true); + assert_that!(sut.wait(|_, _| WaitAction::Abort), eq WaitResult::Success); } - assert_that!(!sut.wait(|_, _| false), eq true); + assert_that!(sut.wait(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); - for _ in 0..initial_value { - sut.post(|_| {}); - } + sut.post(|_| {}, initial_value); for _ in 0..initial_value { - assert_that!(sut.wait(|_, _| false), eq true); + assert_that!(sut.wait(|_, _| WaitAction::Abort), eq WaitResult::Success); } - assert_that!(!sut.wait(|_, _| false), eq true); + assert_that!(sut.wait(|_, _| WaitAction::Abort), eq WaitResult::Interrupted); } #[test] @@ -68,13 +64,13 @@ fn semaphore_wait_blocks() { std::thread::scope(|s| { s.spawn(|| { - sut.wait(|_, _| true); + sut.wait(|_, _| WaitAction::Continue); counter.fetch_add(1, Ordering::Relaxed); }); std::thread::sleep(TIMEOUT); let old_counter = counter.load(Ordering::Relaxed); - sut.post(|_| {}); + sut.post(|_| {}, 1); assert_that!(old_counter, eq 0); }); 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-pal/posix/src/macos/pthread.rs b/iceoryx2-pal/posix/src/macos/pthread.rs index 06c8ed513..638b32378 100644 --- a/iceoryx2-pal/posix/src/macos/pthread.rs +++ b/iceoryx2-pal/posix/src/macos/pthread.rs @@ -19,7 +19,7 @@ use crate::posix::*; use core::sync::atomic::{AtomicU32, Ordering}; use iceoryx2_pal_concurrency_sync::barrier::Barrier; use iceoryx2_pal_concurrency_sync::mutex::Mutex; -use iceoryx2_pal_concurrency_sync::rwlock::*; +use iceoryx2_pal_concurrency_sync::{rwlock::*, WaitAction, WaitResult}; use std::cell::UnsafeCell; #[derive(Clone, Copy)] @@ -64,7 +64,7 @@ impl ThreadStates { } fn lock(&self) { - self.mtx.lock(|_, _| true); + self.mtx.lock(|_, _| WaitAction::Continue); } fn unlock(&self) { @@ -169,6 +169,35 @@ pub fn wait(atomic: &AtomicU32, expected: &u32) { unsafe { __libcpp_atomic_wait(ptr, monitor) }; } +pub fn timed_wait(atomic: &AtomicU32, expected: &u32, timeout: timespec) { + let sleep_time = timespec { + tv_sec: 0, + tv_nsec: 1000000, + }; + let mut now = timespec::new(); + loop { + if atomic.load(Ordering::Relaxed) != *expected { + return; + } + + unsafe { clock_gettime(CLOCK_REALTIME, &mut now) }; + if now.tv_sec > timeout.tv_sec + || (now.tv_sec == timeout.tv_sec && now.tv_nsec > timeout.tv_nsec) + { + return; + } + + unsafe { + clock_nanosleep( + CLOCK_REALTIME, + 0, + &sleep_time, + core::ptr::null_mut::().cast(), + ) + }; + } +} + pub fn wake_one(atomic: &AtomicU32) { let ptr = (atomic as *const AtomicU32) as *const void; unsafe { __cxx_atomic_notify_one(ptr) }; @@ -408,11 +437,11 @@ pub unsafe fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> int { match (*lock).lock { RwLockType::PreferReader(ref l) => l.read_lock(|atomic, value| { wait(atomic, value); - true + WaitAction::Continue }), RwLockType::PreferWriter(ref l) => l.read_lock(|atomic, value| { wait(atomic, value); - true + WaitAction::Continue }), _ => { return Errno::EINVAL as _; @@ -423,7 +452,7 @@ pub unsafe fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> int { } pub unsafe fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> int { - let has_lock = match (*lock).lock { + let wait_result = match (*lock).lock { RwLockType::PreferReader(ref l) => l.try_read_lock(), RwLockType::PreferWriter(ref l) => l.try_read_lock(), _ => { @@ -431,7 +460,7 @@ pub unsafe fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> int { } }; - if has_lock { + if wait_result == WaitResult::Success { Errno::ESUCCES as _ } else { Errno::EBUSY as _ @@ -454,12 +483,12 @@ pub unsafe fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> int { match (*lock).lock { RwLockType::PreferReader(ref l) => l.write_lock(|atomic, value| { wait(atomic, value); - true + WaitAction::Continue }), RwLockType::PreferWriter(ref l) => l.write_lock( |atomic, value| { wait(atomic, value); - true + WaitAction::Continue }, wake_one, wake_all, @@ -473,7 +502,7 @@ pub unsafe fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> int { } pub unsafe fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> int { - let has_lock = match (*lock).lock { + let wait_result = match (*lock).lock { RwLockType::PreferReader(ref l) => l.try_write_lock(), RwLockType::PreferWriter(ref l) => l.try_write_lock(), _ => { @@ -481,7 +510,7 @@ pub unsafe fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> int { } }; - if has_lock { + if wait_result == WaitResult::Success { Errno::ESUCCES as _ } else { Errno::EBUSY as _ @@ -496,7 +525,7 @@ pub unsafe fn pthread_rwlock_timedwrlock( let mut wait_time = timespec::new(); loop { - let has_lock = match (*lock).lock { + let wait_result = match (*lock).lock { RwLockType::PreferReader(ref l) => l.try_write_lock(), RwLockType::PreferWriter(ref l) => l.try_write_lock(), _ => { @@ -504,7 +533,7 @@ pub unsafe fn pthread_rwlock_timedwrlock( } }; - if has_lock { + if wait_result == WaitResult::Success { return Errno::ESUCCES as _; } else { clock_gettime(CLOCK_REALTIME, &mut current_time); @@ -532,21 +561,21 @@ pub unsafe fn pthread_rwlock_timedrdlock( let mut wait_time = timespec::new(); loop { - let has_lock = match (*lock).lock { + let wait_result = match (*lock).lock { RwLockType::PreferReader(ref l) => l.read_lock(|atomic, value| { wait(atomic, value); - true + WaitAction::Continue }), RwLockType::PreferWriter(ref l) => l.read_lock(|atomic, value| { wait(atomic, value); - true + WaitAction::Continue }), _ => { return Errno::EINVAL as _; } }; - if has_lock { + if wait_result == WaitResult::Success { return Errno::ESUCCES as _; } else { clock_gettime(CLOCK_REALTIME, &mut current_time); @@ -567,12 +596,12 @@ pub unsafe fn pthread_rwlock_timedrdlock( } pub unsafe fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> int { - (*cond).cv.notify(wake_all); + (*cond).cv.notify_all(wake_all); Errno::ESUCCES as _ } pub unsafe fn pthread_cond_signal(cond: *mut pthread_cond_t) -> int { - (*cond).cv.notify(wake_one); + (*cond).cv.notify_one(wake_one); Errno::ESUCCES as _ } @@ -591,11 +620,11 @@ pub unsafe fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *mut pthread_m wake_one, |atomic, value| { wait(atomic, value); - true + WaitAction::Continue }, |atomic, value| { wait(atomic, value); - false + WaitAction::Continue }, ); @@ -607,20 +636,21 @@ pub unsafe fn pthread_cond_timedwait( mutex: *mut pthread_mutex_t, abstime: *const timespec, ) -> int { - (*cond).cv.wait( + match (*cond).cv.wait( &(*mutex).mtx, wake_one, |atomic, value| { - wait(atomic, value); - true + timed_wait(atomic, value, *abstime); + WaitAction::Abort }, |atomic, value| { - wait(atomic, value); - false + timed_wait(atomic, value, *abstime); + WaitAction::Abort }, - ); - - Errno::ESUCCES as _ + ) { + WaitResult::Interrupted => Errno::ETIMEDOUT as _, + WaitResult::Success => Errno::ESUCCES as _, + } } pub unsafe fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> int { @@ -738,7 +768,7 @@ pub unsafe fn pthread_mutex_lock(mtx: *mut pthread_mutex_t) -> int { (*mtx).mtx.lock(|atomic, value| { wait(atomic, value); - true + WaitAction::Continue }); if (*mtx).track_thread_id { @@ -789,7 +819,7 @@ pub unsafe fn pthread_mutex_trylock(mtx: *mut pthread_mutex_t) -> int { }; match (*mtx).mtx.try_lock() { - true => { + WaitResult::Success => { if (*mtx).track_thread_id { (*mtx) .current_owner @@ -798,7 +828,7 @@ pub unsafe fn pthread_mutex_trylock(mtx: *mut pthread_mutex_t) -> int { Errno::ESUCCES as _ } - false => Errno::EBUSY as _, + WaitResult::Interrupted => Errno::EBUSY as _, } } diff --git a/iceoryx2-pal/posix/src/macos/semaphore.rs b/iceoryx2-pal/posix/src/macos/semaphore.rs index 4a6e0227f..52dcf9243 100644 --- a/iceoryx2-pal/posix/src/macos/semaphore.rs +++ b/iceoryx2-pal/posix/src/macos/semaphore.rs @@ -15,6 +15,7 @@ #![allow(unused_variables)] use iceoryx2_pal_concurrency_sync::semaphore::Semaphore; +use iceoryx2_pal_concurrency_sync::{WaitAction, WaitResult}; use crate::posix::pthread::{wait, wake_one}; use crate::posix::Errno; @@ -30,16 +31,16 @@ pub unsafe fn sem_post(sem: *mut sem_t) -> int { return -1; } - (*sem).semaphore.post(wake_one); + (*sem).semaphore.post(wake_one, 1); Errno::set(Errno::ESUCCES); 0 } pub unsafe fn sem_wait(sem: *mut sem_t) -> int { - (*sem).semaphore.wait(|atomic, value| -> bool { + (*sem).semaphore.wait(|atomic, value| -> WaitAction { wait(atomic, value); - true + WaitAction::Continue }); Errno::set(Errno::ESUCCES); @@ -48,11 +49,11 @@ pub unsafe fn sem_wait(sem: *mut sem_t) -> int { pub unsafe fn sem_trywait(sem: *mut sem_t) -> int { match (*sem).semaphore.try_wait() { - true => { + WaitResult::Success => { Errno::set(Errno::ESUCCES); 0 } - false => { + WaitResult::Interrupted => { Errno::set(Errno::EAGAIN); -1 } diff --git a/iceoryx2-pal/posix/src/windows/pthread.rs b/iceoryx2-pal/posix/src/windows/pthread.rs index b3f909381..d1f01dc8c 100644 --- a/iceoryx2-pal/posix/src/windows/pthread.rs +++ b/iceoryx2-pal/posix/src/windows/pthread.rs @@ -25,6 +25,7 @@ use std::{ use iceoryx2_pal_concurrency_sync::rwlock::*; use iceoryx2_pal_concurrency_sync::{barrier::Barrier, mutex::Mutex}; +use iceoryx2_pal_concurrency_sync::{WaitAction, WaitResult}; use windows_sys::Win32::{ Foundation::{CloseHandle, ERROR_TIMEOUT, STILL_ACTIVE, WAIT_FAILED}, System::{ @@ -92,7 +93,7 @@ impl ThreadStates { INFINITE, ) }; } - true + WaitAction::Continue }); } @@ -492,7 +493,7 @@ pub unsafe fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> int { 4, INFINITE, )}; - true + WaitAction::Continue }), RwLockType::PreferWriter(ref l) => l.read_lock(|atomic, value| { win32call! {WaitOnAddress( @@ -501,7 +502,7 @@ pub unsafe fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> int { 4, INFINITE, )}; - true + WaitAction::Continue }), _ => { return Errno::EINVAL as _; @@ -512,7 +513,7 @@ pub unsafe fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> int { } pub unsafe fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> int { - let has_lock = match (*lock).lock { + let wait_result = match (*lock).lock { RwLockType::PreferReader(ref l) => l.try_read_lock(), RwLockType::PreferWriter(ref l) => l.try_read_lock(), _ => { @@ -520,7 +521,7 @@ pub unsafe fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> int { } }; - if has_lock { + if wait_result == WaitResult::Success { Errno::ESUCCES as _ } else { Errno::EBUSY as _ @@ -557,7 +558,7 @@ pub unsafe fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> int { 4, INFINITE, )}; - true + WaitAction::Continue }), RwLockType::PreferWriter(ref l) => l.write_lock( |atomic, value| { @@ -567,7 +568,7 @@ pub unsafe fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> int { 4, INFINITE, )}; - true + WaitAction::Continue }, |atomic| { win32call! { WakeByAddressSingle((atomic as *const AtomicU32).cast()) }; @@ -585,7 +586,7 @@ pub unsafe fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> int { } pub unsafe fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> int { - let has_lock = match (*lock).lock { + let wait_result = match (*lock).lock { RwLockType::PreferReader(ref l) => l.try_write_lock(), RwLockType::PreferWriter(ref l) => l.try_write_lock(), _ => { @@ -593,7 +594,7 @@ pub unsafe fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> int { } }; - if has_lock { + if wait_result == WaitResult::Success { Errno::ESUCCES as _ } else { Errno::EBUSY as _ @@ -611,7 +612,7 @@ pub unsafe fn pthread_rwlock_timedwrlock( - now.as_millis() as i64, ); - let has_lock = match (*lock).lock { + let wait_result = match (*lock).lock { RwLockType::PreferReader(ref l) => l.write_lock(|atomic, value| { win32call! { WaitOnAddress( (atomic as *const AtomicU32).cast(), @@ -619,7 +620,7 @@ pub unsafe fn pthread_rwlock_timedwrlock( 4, timeout as _, ), ignore ERROR_TIMEOUT }; - true + WaitAction::Continue }), RwLockType::PreferWriter(ref l) => l.write_lock( |atomic, value| { @@ -629,7 +630,7 @@ pub unsafe fn pthread_rwlock_timedwrlock( 4, timeout as _, ), ignore ERROR_TIMEOUT}; - true + WaitAction::Continue }, |atomic| { WakeByAddressSingle((atomic as *const AtomicU32).cast()); @@ -643,7 +644,7 @@ pub unsafe fn pthread_rwlock_timedwrlock( } }; - if has_lock { + if wait_result == WaitResult::Success { Errno::ESUCCES as _ } else { Errno::ETIMEDOUT as _ @@ -661,7 +662,7 @@ pub unsafe fn pthread_rwlock_timedrdlock( - now.as_millis() as i64, ); - let has_lock = match (*lock).lock { + let wait_result = match (*lock).lock { RwLockType::PreferReader(ref l) => l.read_lock(|atomic, value| { win32call! { WaitOnAddress( (atomic as *const AtomicU32).cast(), @@ -669,7 +670,7 @@ pub unsafe fn pthread_rwlock_timedrdlock( 4, timeout as _, ), ignore ERROR_TIMEOUT }; - true + WaitAction::Continue }), RwLockType::PreferWriter(ref l) => l.read_lock(|atomic, value| { win32call! {WaitOnAddress( @@ -678,14 +679,14 @@ pub unsafe fn pthread_rwlock_timedrdlock( 4, timeout as _, ), ignore ERROR_TIMEOUT}; - true + WaitAction::Continue }), _ => { return Errno::EINVAL as _; } }; - if has_lock { + if wait_result == WaitResult::Success { Errno::ESUCCES as _ } else { Errno::ETIMEDOUT as _ @@ -693,14 +694,14 @@ pub unsafe fn pthread_rwlock_timedrdlock( } pub unsafe fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> int { - (*cond).cv.notify(|atomic| { + (*cond).cv.notify_all(|atomic| { WakeByAddressAll((atomic as *const AtomicU32).cast()); }); Errno::ESUCCES as _ } pub unsafe fn pthread_cond_signal(cond: *mut pthread_cond_t) -> int { - (*cond).cv.notify(|atomic| { + (*cond).cv.notify_one(|atomic| { WakeByAddressSingle((atomic as *const AtomicU32).cast()); }); Errno::ESUCCES as _ @@ -728,7 +729,7 @@ pub unsafe fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *mut pthread_m 4, INFINITE, )}; - true + WaitAction::Continue }, |atomic, value| { win32call! {WaitOnAddress( @@ -737,7 +738,7 @@ pub unsafe fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *mut pthread_m 4, INFINITE, )}; - false + WaitAction::Continue }, ); @@ -755,7 +756,7 @@ pub unsafe fn pthread_cond_timedwait( (*abstime).tv_sec * 1000 + (*abstime).tv_nsec as i64 / 1000000 - now.as_millis() as i64, ); - (*cond).cv.wait( + match (*cond).cv.wait( &(*mutex).mtx, |atomic| { win32call! { WakeByAddressSingle((atomic as *const AtomicU32).cast()) }; @@ -767,7 +768,7 @@ pub unsafe fn pthread_cond_timedwait( 4, timeout as _, ), ignore ERROR_TIMEOUT }; - true + WaitAction::Abort }, |atomic, value| { win32call! { WaitOnAddress( @@ -776,11 +777,12 @@ pub unsafe fn pthread_cond_timedwait( 4, timeout as _, ), ignore ERROR_TIMEOUT }; - false + WaitAction::Abort }, - ); - - Errno::ESUCCES as _ + ) { + WaitResult::Success => Errno::ESUCCES as _, + WaitResult::Interrupted => Errno::ETIMEDOUT as _, + } } pub unsafe fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> int { @@ -898,7 +900,7 @@ pub unsafe fn pthread_mutex_lock(mtx: *mut pthread_mutex_t) -> int { 4, INFINITE, ) }; - true + WaitAction::Continue }); if (*mtx).track_thread_id { @@ -937,9 +939,9 @@ pub unsafe fn pthread_mutex_timedlock( 4, timeout as _, ), ignore ERROR_TIMEOUT }; - false + WaitAction::Abort }) { - true => { + WaitResult::Success => { if (*mtx).track_thread_id { (*mtx) .current_owner @@ -948,7 +950,7 @@ pub unsafe fn pthread_mutex_timedlock( Errno::ESUCCES as _ } - false => Errno::ETIMEDOUT as _, + WaitResult::Interrupted => Errno::ETIMEDOUT as _, } } @@ -960,7 +962,7 @@ pub unsafe fn pthread_mutex_trylock(mtx: *mut pthread_mutex_t) -> int { }; match (*mtx).mtx.try_lock() { - true => { + WaitResult::Success => { if (*mtx).track_thread_id { (*mtx) .current_owner @@ -969,7 +971,7 @@ pub unsafe fn pthread_mutex_trylock(mtx: *mut pthread_mutex_t) -> int { Errno::ESUCCES as _ } - false => Errno::EBUSY as _, + WaitResult::Interrupted => Errno::EBUSY as _, } } diff --git a/iceoryx2-pal/posix/src/windows/semaphore.rs b/iceoryx2-pal/posix/src/windows/semaphore.rs index aa3a6536d..7e68c823c 100644 --- a/iceoryx2-pal/posix/src/windows/semaphore.rs +++ b/iceoryx2-pal/posix/src/windows/semaphore.rs @@ -19,6 +19,7 @@ use std::time::SystemTime; use std::time::UNIX_EPOCH; use iceoryx2_pal_concurrency_sync::semaphore::Semaphore; +use iceoryx2_pal_concurrency_sync::{WaitAction, WaitResult}; use windows_sys::Win32::System::Threading::WaitOnAddress; use windows_sys::Win32::System::Threading::WakeByAddressSingle; use windows_sys::Win32::System::Threading::INFINITE; @@ -37,16 +38,19 @@ pub unsafe fn sem_post(sem: *mut sem_t) -> int { return -1; } - (*sem).semaphore.post(|atomic| { - WakeByAddressSingle((atomic as *const AtomicU32).cast()); - }); + (*sem).semaphore.post( + |atomic| { + WakeByAddressSingle((atomic as *const AtomicU32).cast()); + }, + 1, + ); Errno::set(Errno::ESUCCES); 0 } pub unsafe fn sem_wait(sem: *mut sem_t) -> int { - (*sem).semaphore.wait(|atomic, value| -> bool { + (*sem).semaphore.wait(|atomic, value| -> WaitAction { WaitOnAddress( (atomic as *const AtomicU32).cast(), (value as *const u32).cast(), @@ -54,7 +58,7 @@ pub unsafe fn sem_wait(sem: *mut sem_t) -> int { INFINITE, ); - true + WaitAction::Continue }); Errno::set(Errno::ESUCCES); @@ -63,11 +67,11 @@ pub unsafe fn sem_wait(sem: *mut sem_t) -> int { pub unsafe fn sem_trywait(sem: *mut sem_t) -> int { match (*sem).semaphore.try_wait() { - true => { + WaitResult::Success => { Errno::set(Errno::ESUCCES); 0 } - false => { + WaitResult::Interrupted => { Errno::set(Errno::EAGAIN); -1 } @@ -79,7 +83,7 @@ pub unsafe fn sem_timedwait(sem: *mut sem_t, abs_timeout: *const timespec) -> in let milli_seconds = (*abs_timeout).tv_sec * 1000 + (*abs_timeout).tv_nsec as i64 / 1000000 - now.as_millis() as i64; - match (*sem).semaphore.wait(|atomic, value| -> bool { + match (*sem).semaphore.wait(|atomic, value| -> WaitAction { WaitOnAddress( (atomic as *const AtomicU32).cast(), (value as *const u32).cast(), @@ -87,13 +91,13 @@ pub unsafe fn sem_timedwait(sem: *mut sem_t, abs_timeout: *const timespec) -> in milli_seconds as _, ); - false + WaitAction::Abort }) { - true => { + WaitResult::Success => { Errno::set(Errno::ESUCCES); 0 } - false => { + WaitResult::Interrupted => { Errno::set(Errno::ETIMEDOUT); -1 } diff --git a/iceoryx2-pal/posix/src/windows/signal.rs b/iceoryx2-pal/posix/src/windows/signal.rs index 3964b68f2..83eb3c991 100644 --- a/iceoryx2-pal/posix/src/windows/signal.rs +++ b/iceoryx2-pal/posix/src/windows/signal.rs @@ -15,6 +15,7 @@ #![allow(unused_variables)] use iceoryx2_pal_concurrency_sync::mutex::Mutex; +use iceoryx2_pal_concurrency_sync::WaitAction; use windows_sys::Win32::{ Foundation::{FALSE, TRUE}, System::{ @@ -54,14 +55,14 @@ impl SigAction { } fn get(&self) -> sigaction_t { - self.mtx.lock(|_, _| true); + self.mtx.lock(|_, _| WaitAction::Continue); let ret_val = unsafe { *self.action.get() }; self.mtx.unlock(|_| {}); ret_val } fn set(&self, value: sigaction_t) -> sigaction_t { - self.mtx.lock(|_, _| true); + self.mtx.lock(|_, _| WaitAction::Continue); let ret_val = unsafe { *self.action.get() }; unsafe { *self.action.get() = value }; self.mtx.unlock(|_| {}); diff --git a/iceoryx2-pal/posix/src/windows/win32_handle_translator.rs b/iceoryx2-pal/posix/src/windows/win32_handle_translator.rs index 06b68f441..e8a8ac0a0 100644 --- a/iceoryx2-pal/posix/src/windows/win32_handle_translator.rs +++ b/iceoryx2-pal/posix/src/windows/win32_handle_translator.rs @@ -19,6 +19,7 @@ use windows_sys::Win32::{ use crate::posix::{c_string_length, ntohs, types::*}; use core::{cell::UnsafeCell, panic}; use iceoryx2_pal_concurrency_sync::mutex::Mutex; +use iceoryx2_pal_concurrency_sync::WaitAction; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use super::win32_udp_port_to_uds_name::{PortToUds, MAX_UDS_NAME_LEN}; @@ -141,7 +142,7 @@ impl HandleTranslator { INFINITE, ); } - true + WaitAction::Continue }); } diff --git a/iceoryx2/src/config.rs b/iceoryx2/src/config.rs index fbdc843db..60c793f75 100644 --- a/iceoryx2/src/config.rs +++ b/iceoryx2/src/config.rs @@ -102,13 +102,11 @@ use crate::service::port_factory::publisher::UnableToDeliverStrategy; /// Path to the default config file #[cfg(target_os = "windows")] -pub const DEFAULT_CONFIG_FILE: FilePath = - unsafe { FilePath::new_unchecked(b"config\\iceoryx2_win.toml") }; +pub const DEFAULT_CONFIG_FILE: &[u8] = b"config\\iceoryx2_win.toml"; /// Path to the default config file #[cfg(not(target_os = "windows"))] -pub const DEFAULT_CONFIG_FILE: FilePath = - unsafe { FilePath::new_unchecked(b"config/iceoryx2.toml") }; +pub const DEFAULT_CONFIG_FILE: &[u8] = b"config/iceoryx2.toml"; /// Failures occurring while creating a new [`Config`] object with [`Config::from_file()`] or /// [`Config::setup_global_config_from_file()`] @@ -331,7 +329,10 @@ impl Config { /// config was already populated. pub fn get_global_config() -> &'static Config { if !ICEORYX2_CONFIG.is_initialized() - && Config::setup_global_config_from_file(&DEFAULT_CONFIG_FILE).is_err() + && Config::setup_global_config_from_file(unsafe { + &FilePath::new_unchecked(DEFAULT_CONFIG_FILE) + }) + .is_err() { warn!(from "Config::get_global_config()", "Unable to load default config file, populate config with default values."); ICEORYX2_CONFIG.set_value(Config::default()); diff --git a/iceoryx2/src/port/event_id.rs b/iceoryx2/src/port/event_id.rs index 892929c79..8c0efadbd 100644 --- a/iceoryx2/src/port/event_id.rs +++ b/iceoryx2/src/port/event_id.rs @@ -46,12 +46,12 @@ pub struct EventId(u64); impl EventId { /// Creates a new [`EventId`] from a given integer value. - pub fn new(value: u64) -> Self { + pub const fn new(value: u64) -> Self { EventId(value) } /// Returns the underlying integer value of the [`EventId`]. - pub fn as_u64(&self) -> u64 { + pub const fn as_u64(&self) -> u64 { self.0 } } diff --git a/iceoryx2/src/service/config_scheme.rs b/iceoryx2/src/service/config_scheme.rs index c00e87a83..0d516ff05 100644 --- a/iceoryx2/src/service/config_scheme.rs +++ b/iceoryx2/src/service/config_scheme.rs @@ -73,7 +73,7 @@ pub(crate) fn static_config_storage_config<'config, Service: crate::service::Det generate_default_config::<::Configuration>( "static_config_storage_config", &global_config.global.prefix, - &global_config.global.service.dynamic_config_storage_suffix, + &global_config.global.service.static_config_storage_suffix, &path_hint, ) } diff --git a/iceoryx2/src/service/messaging_pattern.rs b/iceoryx2/src/service/messaging_pattern.rs index db6adb32c..3ff417ded 100644 --- a/iceoryx2/src/service/messaging_pattern.rs +++ b/iceoryx2/src/service/messaging_pattern.rs @@ -31,6 +31,8 @@ //! [`Listener`](crate::port::listener::Listener)s. //! //! **Note:** This does **not** send or receive POSIX signals nor is it based on them. +use std::fmt::Display; + use crate::service::static_config::event; use crate::service::static_config::publish_subscribe; use serde::{Deserialize, Serialize}; @@ -44,6 +46,24 @@ pub enum MessagingPattern { Event(event::StaticConfig), } +impl Display for MessagingPattern { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + MessagingPattern::Event(_) => write!(f, "Event"), + MessagingPattern::PublishSubscribe(_) => write!(f, "PublishSubscribe"), + } + } +} + +impl From for u32 { + fn from(value: MessagingPattern) -> Self { + match value { + MessagingPattern::Event(_) => 0, + MessagingPattern::PublishSubscribe(_) => 1, + } + } +} + impl MessagingPattern { pub(crate) fn is_same_pattern(&self, rhs: &MessagingPattern) -> bool { match self { diff --git a/iceoryx2/src/service/process_local.rs b/iceoryx2/src/service/process_local.rs index c37baa5c9..9adc7708c 100644 --- a/iceoryx2/src/service/process_local.rs +++ b/iceoryx2/src/service/process_local.rs @@ -58,7 +58,7 @@ impl<'config> crate::service::Details<'config> for Service<'config> { type ServiceNameHasher = hash::sha1::Sha1; type SharedMemory = shared_memory::process_local::Memory; type Connection = zero_copy_connection::process_local::Connection; - type Event = event::process_local::Event; + type Event = event::process_local::EventImpl; fn from_state(state: ServiceState<'config, Self::StaticStorage, Self::DynamicStorage>) -> Self { Self { state } diff --git a/iceoryx2/src/service/service_name.rs b/iceoryx2/src/service/service_name.rs index 2144d2292..389e358b1 100644 --- a/iceoryx2/src/service/service_name.rs +++ b/iceoryx2/src/service/service_name.rs @@ -33,6 +33,7 @@ pub struct ServiceName { } impl ServiceName { + /// Creates a new [`ServiceName`]. The name is not allowed to be empty. pub fn new(name: &str) -> Result { if name.is_empty() { return Err(SemanticStringError::InvalidName); @@ -45,7 +46,8 @@ impl ServiceName { }) } - fn as_str(&self) -> &str { + /// Returns a str reference to the [`ServiceName`] + pub fn as_str(&self) -> &str { // SAFETY: `ServieName` was created from a `&str` and therefore this conversion is safe unsafe { std::str::from_utf8_unchecked(self.value.as_bytes()) } } diff --git a/iceoryx2/src/service/static_config/mod.rs b/iceoryx2/src/service/static_config/mod.rs index 12e3637bc..b39e49af7 100644 --- a/iceoryx2/src/service/static_config/mod.rs +++ b/iceoryx2/src/service/static_config/mod.rs @@ -37,15 +37,26 @@ pub struct StaticConfig { pub(crate) messaging_pattern: MessagingPattern, } +fn create_uuid( + service_name: &ServiceName, + messaging_pattern: &MessagingPattern, +) -> Hasher { + let pattern_and_service = (>::into(messaging_pattern.clone())) + .to_string() + + service_name.as_str(); + Hasher::new(pattern_and_service.as_bytes()) +} + impl StaticConfig { pub(crate) fn new_event( service_name: &ServiceName, config: &config::Config, ) -> Self { + let messaging_pattern = MessagingPattern::Event(event::StaticConfig::new(config)); Self { - uuid: Hasher::new(service_name.as_bytes()).as_hex_string(), + uuid: create_uuid::(service_name, &messaging_pattern).as_hex_string(), service_name: *service_name, - messaging_pattern: MessagingPattern::Event(event::StaticConfig::new(config)), + messaging_pattern, } } @@ -53,12 +64,12 @@ impl StaticConfig { service_name: &ServiceName, config: &config::Config, ) -> Self { + let messaging_pattern = + MessagingPattern::PublishSubscribe(publish_subscribe::StaticConfig::new(config)); Self { - uuid: Hasher::new(service_name.as_bytes()).as_hex_string(), + uuid: create_uuid::(service_name, &messaging_pattern).as_hex_string(), service_name: *service_name, - messaging_pattern: MessagingPattern::PublishSubscribe( - publish_subscribe::StaticConfig::new(config), - ), + messaging_pattern, } } diff --git a/iceoryx2/src/service/zero_copy.rs b/iceoryx2/src/service/zero_copy.rs index ca93e991e..cfd63279d 100644 --- a/iceoryx2/src/service/zero_copy.rs +++ b/iceoryx2/src/service/zero_copy.rs @@ -58,7 +58,7 @@ impl<'config> crate::service::Details<'config> for Service<'config> { type ServiceNameHasher = hash::sha1::Sha1; type SharedMemory = shared_memory::posix::Memory; type Connection = zero_copy_connection::posix_shared_memory::Connection; - type Event = event::unix_datagram_socket::Event; + type Event = event::unix_datagram_socket::EventImpl; fn from_state(state: ServiceState<'config, Self::StaticStorage, Self::DynamicStorage>) -> Self { Self { state } 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, diff --git a/iceoryx2/tests/service_tests.rs b/iceoryx2/tests/service_tests.rs new file mode 100644 index 000000000..1cbe11b2e --- /dev/null +++ b/iceoryx2/tests/service_tests.rs @@ -0,0 +1,62 @@ +// Copyright (c) 2023 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#[generic_tests::define] +mod service { + use iceoryx2::port::event_id::EventId; + use iceoryx2::service::{service_name::ServiceName, Service}; + use iceoryx2_bb_posix::unique_system_id::UniqueSystemId; + use iceoryx2_bb_testing::assert_that; + + fn generate_name() -> ServiceName { + ServiceName::new(&format!( + "service_tests_{}", + UniqueSystemId::new().unwrap().value() + )) + .unwrap() + } + + #[test] + fn same_name_with_different_messaging_pattern_is_allowed() { + let service_name = generate_name(); + let sut_pub_sub = Sut::new(&service_name).publish_subscribe().create::(); + assert_that!(sut_pub_sub, is_ok); + let sut_pub_sub = sut_pub_sub.unwrap(); + + let sut_event = Sut::new(&service_name).event().create(); + assert_that!(sut_event, is_ok); + let sut_event = sut_event.unwrap(); + + let sut_subscriber = sut_pub_sub.subscriber().create().unwrap(); + let sut_publisher = sut_pub_sub.publisher().create().unwrap(); + + let mut sut_listener = sut_event.listener().create().unwrap(); + let sut_notifier = sut_event.notifier().create().unwrap(); + + const SAMPLE_VALUE: u64 = 891231211; + sut_publisher.send_copy(SAMPLE_VALUE).unwrap(); + let received_sample = sut_subscriber.receive().unwrap().unwrap(); + assert_that!(*received_sample, eq SAMPLE_VALUE); + + const EVENT_ID: EventId = EventId::new(10123101301); + sut_notifier.notify_with_custom_event_id(EVENT_ID).unwrap(); + let received_event = sut_listener.try_wait().unwrap(); + assert_that!(received_event, len 1); + assert_that!(received_event[0], eq EVENT_ID); + } + + #[instantiate_tests()] + mod zero_copy {} + + #[instantiate_tests()] + mod process_local {} +}