Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ impl iceoryx2::service::Service for CustomServiceVariant {
type ConfigSerializer = iceoryx2_cal::serialize::recommended::Recommended;
type PersistentDynamicStorage<T: Debug + Send + Sync + ZeroCopySend + 'static> =
iceoryx2_cal::dynamic_storage::recommended::PersistentIpc<T>;
type Bag = iceoryx2_cal::bag::recommended::Recommended;
// use a dynamic storage based on a file
type DynamicStorage<T: Debug + Send + Sync + ZeroCopySend + 'static> =
iceoryx2_cal::dynamic_storage::file::Storage<T>;
Expand Down
1 change: 1 addition & 0 deletions iceoryx2-bb/elementary-traits/src/zero_copy_send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ unsafe impl ZeroCopySend for () {}
unsafe impl<T: ZeroCopySend> ZeroCopySend for [T] {}
unsafe impl<T: ZeroCopySend, const N: usize> ZeroCopySend for [T; N] {}
unsafe impl<T: ZeroCopySend> ZeroCopySend for core::mem::MaybeUninit<T> {}
unsafe impl<T: ZeroCopySend> ZeroCopySend for core::marker::PhantomData<T> {}

// Note: `ZeroCopySend` cannot be implemented for tuples because `#[repr(C)]` can only be applied
// to structs, enums, and unions.
Expand Down
73 changes: 73 additions & 0 deletions iceoryx2-cal/src/bag/default_bag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) 2026 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

//! The default implementation for the [`BagFamily`] concept and the [`Bag`] trait.

use crate::bag::{Bag, BagAddFailure, BagFamily, BagHandle, BagRemoveError, BagState, BagType};

use iceoryx2_bb_lock_free::mpmc::container::Container;
use iceoryx2_bb_lock_free::mpmc::robust_unique_index_set::OwnerId;
use iceoryx2_bb_lock_free::mpmc::unique_index_set_enums::{ReleaseMode, ReleaseState};

#[derive(Debug)]
pub struct DefaultBag;

impl BagFamily for DefaultBag {
type Bag<T: BagType> = Container<T>;
}

impl<T: BagType> Bag<T> for Container<T> {
fn capacity(&self) -> usize {
self.capacity()
}

fn len(&self) -> usize {
self.len()
}

fn is_empty(&self) -> bool {
self.is_empty()
}

unsafe fn add(
&self,
value: T,
owner_id: OwnerId,
) -> Result<(*const T, BagHandle), BagAddFailure> {
unsafe { self.add(value, owner_id) }
}

unsafe fn remove(
&self,
handle: BagHandle,
mode: ReleaseMode,
) -> Result<ReleaseState, BagRemoveError> {
unsafe { self.remove(handle, mode) }
}

unsafe fn get_state(&self) -> BagState<T> {
unsafe { self.get_state() }
}

unsafe fn recover<F: FnMut(T) -> bool>(
&self,
dead_owner_id: OwnerId,
predicate: F,
mode: ReleaseMode,
) -> ReleaseState {
unsafe { self.recover(dead_owner_id, predicate, mode) }
}

unsafe fn update_state(&self, previous_state: &mut BagState<T>) -> bool {
unsafe { self.update_state(previous_state) }
}
}
149 changes: 149 additions & 0 deletions iceoryx2-cal/src/bag/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright (c) 2026 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

//! Offers an interface to a container to concurrently add, remove and access
//! values with a fixed position for the lifetime of the data. The data in the
//! container is not necessarily ordered.
//!
//! # Example
//!
//! ```
//! use core::ptr::NonNull;
//!
//! use iceoryx2_bb_container::queue::RelocatableContainer;
//! use iceoryx2_bb_elementary_traits::allocator::{Allocate, AllocationError};
//! use iceoryx2_cal::bag::*;
//!
//! fn create_bag<B: BagFamily, T: BagType, A: Allocate<NonNull<u8>>>(
//! capacity: usize,
//! allocator: A,
//! ) -> Result<B::Bag<T>, AllocationError> {
//! let mut bag = unsafe { B::Bag::<T>::new_uninit(capacity) };
//! unsafe {
//! bag.init(&allocator)?;
//! }
//! Ok(bag)
//! }
//! ```

pub mod default_bag;
pub mod recommended;

use core::fmt::Debug;

use iceoryx2_bb_container::queue::RelocatableContainer;
use iceoryx2_bb_elementary_traits::zero_copy_send::ZeroCopySend;

use iceoryx2_bb_lock_free::mpmc::container::{
ContainerAddFailure, ContainerHandle, ContainerRemoveError, ContainerState,
};
use iceoryx2_bb_lock_free::mpmc::robust_unique_index_set::OwnerId;
use iceoryx2_bb_lock_free::mpmc::unique_index_set_enums::{ReleaseMode, ReleaseState};

pub type BagHandle = ContainerHandle;
pub type BagState<T> = ContainerState<T>;
pub type BagAddFailure = ContainerAddFailure;
pub type BagRemoveError = ContainerRemoveError;

/// A super trait defining the trait bounds of a [`Bag`] type
pub trait BagType: Copy + Debug + ZeroCopySend {}
impl<T: Copy + Debug + ZeroCopySend> BagType for T {}

/// The [`BagFamily`] provides the associated type for the concrete type implementing the concept
pub trait BagFamily: Debug + 'static {
type Bag<T: BagType>: Debug + Send + Sync + ZeroCopySend + RelocatableContainer + Bag<T>;
}

/// The [`Bag`] trait provides access to an unordered container with fix position for the data
/// during its lifetime
pub trait Bag<T: BagType>: Debug {
/// Returns the capacity of the bag.
fn capacity(&self) -> usize;

/// Returns the current len of the bag
fn len(&self) -> usize;

/// Returns true if the container is empty, otherwise false
fn is_empty(&self) -> bool;

/// Adds a new element to the [`Bag`]. If there is no more space available it returns
/// [`None`], otherwise [`Some`] containing the the index value to the underlying element.
///
/// Must be released with [`Bag::remove()`].
///
/// # Safety
///
/// * Ensure that [`Bag::init()`](RelocatableContainer::init()) was called before calling this method
///
unsafe fn add(
&self,
value: T,
owner_id: OwnerId,
) -> Result<(*const T, BagHandle), BagAddFailure>;

/// Useful in IPC context when an application holding the UniqueIndex has died.
///
/// # Safety
///
/// * Ensure that [`Bag::init()`](RelocatableContainer::init()) was called before calling this method
/// * Ensure that no one else possesses the [`BagHandle`] and the index was unrecoverable
/// lost
/// * Ensure that the `handle` was acquired by the same [`Bag`]
/// with [`Bag::add()`], otherwise the method will panic.
///
/// **Important:** If the [`BagHandle`] still exists it causes double frees or freeing an index
/// which was allocated afterwards
///
unsafe fn remove(
&self,
handle: BagHandle,
mode: ReleaseMode,
) -> Result<ReleaseState, BagRemoveError>;

/// Returns [`BagState`] which contains all elements of this bag. Be aware that
/// this state can be out of date as soon as it is returned from this function.
///
/// # Safety
///
/// * Ensure that [`Bag::init()`](RelocatableContainer::init()) was called before calling this method
///
unsafe fn get_state(&self) -> BagState<T>;

/// Recovers and releases all entries the dead [`OwnerId`] owned. It assumes that the dead owner
/// maybe died while adding some entry, therefore it removes all entries where the
/// [`OwnerId`] does not contain any data or where there was data and the provided predicate
/// returned [`true`].
///
/// # Safety
///
/// * Ensure that [`Bag::init()`](RelocatableContainer::init()) was called before calling this method
/// * All existing [`BagHandle`] that belong to the [`OwnerId`] must never be removed with
/// [`Bag::remove()`] otherwise we corrupt the state.
///
unsafe fn recover<F: FnMut(T) -> bool>(
&self,
dead_owner_id: OwnerId,
predicate: F,
mode: ReleaseMode,
) -> ReleaseState;

/// Syncs the [`BagState`] with the current state of the [`Bag`]. If the state has
/// changed it returns true, otherwise false.
///
/// # Safety
///
/// * Ensure that [`Bag::init()`](RelocatableContainer::init()) was called before calling this method
/// * Ensure that the input argument `previous_state` was acquired by the same [`Bag`]
/// with [`Bag::get_state()`], otherwise the method will panic.
///
unsafe fn update_state(&self, previous_state: &mut BagState<T>) -> bool;
}
16 changes: 16 additions & 0 deletions iceoryx2-cal/src/bag/recommended.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2026 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

/// Provides the recommended
/// [`BagFamily`](crate::bag::BagFamily) concept implementation
/// for the target.
pub type Recommended = crate::bag::default_bag::DefaultBag;
1 change: 1 addition & 0 deletions iceoryx2-cal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extern crate alloc;
extern crate iceoryx2_bb_loggers;

pub mod arc_sync_policy;
pub mod bag;
pub mod communication_channel;
pub mod dynamic_storage;
pub mod event;
Expand Down
4 changes: 2 additions & 2 deletions iceoryx2/conformance-tests/src/node_death.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ pub mod node_death {

fn does_support_persistency<S: iceoryx2::service::Service>() -> bool {
<S as Service>::DynamicStorage::<
iceoryx2::service::dynamic_config::DynamicConfig,
>::does_support_persistency()
iceoryx2::service::dynamic_config::DynamicConfig<S::Bag>,
>::does_support_persistency()
}

#[conformance_test]
Expand Down
16 changes: 8 additions & 8 deletions iceoryx2/src/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ use iceoryx2_bb_elementary::CallbackProgression;
use iceoryx2_bb_elementary::scope_guard::ScopeGuardBuilder;
use iceoryx2_bb_elementary_traits::testing::abandonable::Abandonable;
use iceoryx2_bb_elementary_traits::zero_copy_send::ZeroCopySend;
use iceoryx2_bb_lock_free::mpmc::container::ContainerHandle;
use iceoryx2_bb_posix::adaptive_wait::{AdaptiveWaitBuilder, AdaptiveWaitStrategy};
use iceoryx2_bb_posix::clock::Time;
use iceoryx2_bb_posix::clock::{NanosleepError, nanosleep};
Expand All @@ -177,6 +176,7 @@ use iceoryx2_bb_posix::mutex::MutexType;
use iceoryx2_bb_posix::process::Process;
use iceoryx2_bb_posix::signal::SignalHandler;
use iceoryx2_bb_system_types::file_name::FileName;
use iceoryx2_cal::bag::BagHandle;
use iceoryx2_cal::named_concept::{NamedConceptPathHintRemoveError, NamedConceptRemoveError};
use iceoryx2_cal::{
monitoring::*, named_concept::NamedConceptListError, serialize::*, static_storage::*,
Expand Down Expand Up @@ -842,7 +842,7 @@ fn remove_node<Service: service::Service>(

#[derive(Debug)]
pub(crate) struct RegisteredServices {
handle: MutexHandle<BTreeMap<ServiceHash, (ContainerHandle, u64)>>,
handle: MutexHandle<BTreeMap<ServiceHash, (BagHandle, u64)>>,
}

impl RegisteredServices {
Expand All @@ -863,9 +863,9 @@ impl RegisteredServices {
}

fn insert(
services: &mut BTreeMap<ServiceHash, (ContainerHandle, u64)>,
services: &mut BTreeMap<ServiceHash, (BagHandle, u64)>,
service_hash: ServiceHash,
handle: ContainerHandle,
handle: BagHandle,
) {
if services.insert(service_hash, (handle, 1)).is_some() {
fatal_panic!(from "RegisteredServices::insert()",
Expand All @@ -874,7 +874,7 @@ impl RegisteredServices {
}
}

pub(crate) fn add(&self, service_hash: &ServiceHash, handle: ContainerHandle) {
pub(crate) fn add(&self, service_hash: &ServiceHash, handle: BagHandle) {
let mut guard = fatal_panic!(
from self,
when self.mutex().lock(),
Expand All @@ -884,7 +884,7 @@ impl RegisteredServices {
Self::insert(&mut guard, *service_hash, handle);
}

pub(crate) fn add_or<F: FnMut() -> Result<ContainerHandle, OpenDynamicStorageFailure>>(
pub(crate) fn add_or<F: FnMut() -> Result<BagHandle, OpenDynamicStorageFailure>>(
&self,
service_hash: &ServiceHash,
mut or_callback: F,
Expand All @@ -907,7 +907,7 @@ impl RegisteredServices {
Ok(())
}

pub(crate) fn remove<F: FnMut(ContainerHandle)>(
pub(crate) fn remove<F: FnMut(BagHandle)>(
&self,
service_hash: &ServiceHash,
mut cleanup_call: F,
Expand All @@ -929,7 +929,7 @@ impl RegisteredServices {
drop(guard);
}

fn mutex(&self) -> Mutex<'_, '_, BTreeMap<ServiceHash, (ContainerHandle, u64)>> {
fn mutex(&self) -> Mutex<'_, '_, BTreeMap<ServiceHash, (BagHandle, u64)>> {
// Safe - the mutex is initialized when constructing the struct and
// not interacted with by anything else.
unsafe { Mutex::from_handle(&self.handle) }
Expand Down
9 changes: 5 additions & 4 deletions iceoryx2/src/port/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ use iceoryx2_bb_elementary_traits::allocator::{AllocationGrowError, ContentPlace
use iceoryx2_bb_elementary_traits::iceoryx_send::IceoryxSend;
use iceoryx2_bb_elementary_traits::testing::abandonable::Abandonable;
use iceoryx2_bb_elementary_traits::zero_copy_send::ZeroCopySend;
use iceoryx2_bb_lock_free::mpmc::container::{ContainerHandle, ContainerState};
use iceoryx2_bb_memory::heap_allocator::HeapAllocator;
use iceoryx2_cal::bag::Bag;
use iceoryx2_cal::bag::{BagHandle, BagState};
use iceoryx2_cal::shared_memory::ShmPointer;
use iceoryx2_cal::shm_allocator::PointerOffset;
use iceoryx2_cal::zero_copy_connection::{CHANNEL_STATE_CLOSED, CHANNEL_STATE_OPEN};
Expand Down Expand Up @@ -176,8 +177,8 @@ pub struct ClientSharedState<Service: service::Service> {
pub(crate) config: LocalClientConfig,
pub(crate) request_sender: Sender<Service, RequestResponseResources<Service>>,
pub(crate) response_receiver: Receiver<Service, RequestResponseResources<Service>>,
client_handle: UnsafeCell<Option<ContainerHandle>>,
server_list_state: UnsafeCell<ContainerState<ServerDetails>>,
client_handle: UnsafeCell<Option<BagHandle>>,
server_list_state: UnsafeCell<BagState<ServerDetails>>,
pub(crate) available_channel_ids: UnsafeCell<Queue<ChannelId>>,
pub(crate) active_request_counter: AtomicUsize,
pub(crate) max_active_requests: usize,
Expand Down Expand Up @@ -661,7 +662,7 @@ impl<
.dynamic_storage()
.get()
.request_response()
.add_client_id(client_details)
.register_client_id(client_details)
{
Some(v) => v,
None => {
Expand Down
Loading
Loading