Skip to content

Commit

Permalink
[eclipse-iceoryx#210] Use union when multiple types are in storage
Browse files Browse the repository at this point in the history
  • Loading branch information
elBoberido committed Jul 14, 2024
1 parent 2f79e1c commit aa3c7ee
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 46 deletions.
2 changes: 1 addition & 1 deletion iceoryx2-ffi/ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
The type erasure is usually done in two stages with `iox2_foo_storage_t` and `iox2_foo_t`.

The `iox2_foo_storage_t` is the storage for the Rust type `Option<Foo>` and must match the size and alignment of `Option<Foo>`.
If the internal storage must hold multiple types, the size and alignment is respectively the max value of the types.
If the internal storage must hold multiple types, a union can be used.
The struct is not supposed to be used standalone but always in combination with an `iox2_foo_t`.
Assuming the size is 160 and the alignment is 8, then the storage is defined as following
```rs
Expand Down
83 changes: 43 additions & 40 deletions iceoryx2-ffi/ffi/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ use crate::{

use iceoryx2::node::{NodeListFailure, NodeView};
use iceoryx2::prelude::*;
use iceoryx2::service;
use iceoryx2_bb_elementary::math::max;
use iceoryx2_bb_elementary::static_assert::*;

use core::ffi::{c_int, c_void};
use core::mem::{align_of, size_of, MaybeUninit};
use core::mem::{align_of, size_of, ManuallyDrop, MaybeUninit};
use std::alloc::{alloc, dealloc, Layout};

// BEGIN type definition
Expand All @@ -49,46 +47,60 @@ impl IntoCInt for NodeListFailure {
}
}

pub(crate) union NodeUnion {
ipc: ManuallyDrop<Node<zero_copy::Service>>,
local: ManuallyDrop<Node<process_local::Service>>,
}

impl NodeUnion {
pub(crate) fn new_ipc(node: Node<zero_copy::Service>) -> Self {
Self {
ipc: ManuallyDrop::new(node),
}
}
pub(crate) fn new_local(node: Node<process_local::Service>) -> Self {
Self {
local: ManuallyDrop::new(node),
}
}
}

#[repr(C)]
#[repr(align(8))] // magic number; the larger one of align_of::<Node<zero_copy::Service>>() and align_of::<Node<process_local::Service>>()
#[repr(align(8))] // alignment of Option<NodeUnion>
pub struct iox2_node_storage_t {
internal: [u8; 8], // magic number; the larger one of size_of::<Node<zero_copy::Service>>() and size_of::<Node<process_local::Service>>()
internal: [u8; 16], // magic number obtained with size_of::<Option<NodeUnion>>()
}

impl iox2_node_storage_t {
const fn assert_storage_layout() {
const MAX_NODE_ALIGNMENT: usize = max(
align_of::<Option<Node<zero_copy::Service>>>(),
align_of::<Option<Node<process_local::Service>>>(),
);
const MAX_NODE_SIZE: usize = max(
size_of::<Option<Node<zero_copy::Service>>>(),
size_of::<Option<Node<process_local::Service>>>(),
static_assert_ge::<
{ align_of::<iox2_node_storage_t>() },
{ align_of::<Option<NodeUnion>>() },
>();
static_assert_ge::<{ size_of::<iox2_node_storage_t>() }, { size_of::<Option<NodeUnion>>() }>(
);
static_assert_ge::<{ align_of::<iox2_node_storage_t>() }, { MAX_NODE_ALIGNMENT }>();
static_assert_ge::<{ size_of::<iox2_node_storage_t>() }, { MAX_NODE_SIZE }>();
}

fn init<Service: service::Service>(&mut self, node: Node<Service>) {
fn init(&mut self, node: NodeUnion) {
iox2_node_storage_t::assert_storage_layout();

unsafe { &mut *(self as *mut Self).cast::<MaybeUninit<Option<Node<Service>>>>() }
unsafe { &mut *(self as *mut Self).cast::<MaybeUninit<Option<NodeUnion>>>() }
.write(Some(node));
}

unsafe fn as_option_mut<Service: service::Service>(&mut self) -> &mut Option<Node<Service>> {
&mut *(self as *mut Self).cast::<Option<Node<Service>>>()
unsafe fn as_option_mut(&mut self) -> &mut Option<NodeUnion> {
&mut *(self as *mut Self).cast::<Option<NodeUnion>>()
}

unsafe fn as_option_ref<Service: service::Service>(&self) -> &Option<Node<Service>> {
&*(self as *const Self).cast::<Option<Node<Service>>>()
unsafe fn as_option_ref(&self) -> &Option<NodeUnion> {
&*(self as *const Self).cast::<Option<NodeUnion>>()
}

unsafe fn _as_mut<Service: service::Service>(&mut self) -> &mut Node<Service> {
unsafe fn as_mut(&mut self) -> &mut NodeUnion {
self.as_option_mut().as_mut().unwrap()
}

unsafe fn as_ref<Service: service::Service>(&self) -> &Node<Service> {
unsafe fn as_ref(&self) -> &NodeUnion {
self.as_option_ref().as_ref().unwrap()
}
}
Expand All @@ -103,10 +115,10 @@ pub struct iox2_node_t {
}

impl iox2_node_t {
pub(crate) fn init<Service: service::Service>(
pub(crate) fn init(
&mut self,
service_type: iox2_service_type_e,
node: Node<Service>,
node: NodeUnion,
deleter: fn(*mut iox2_node_t),
) {
self.service_type = service_type;
Expand Down Expand Up @@ -183,11 +195,9 @@ pub unsafe extern "C" fn iox2_node_name(node_handle: iox2_node_h) -> iox2_node_n
let node_struct = &mut *iox2_node_t::cast(node_handle);

match node_struct.service_type {
iox2_service_type_e::IPC => {
node_struct.node.as_ref::<zero_copy::Service>().name() as *const _ as *const _
}
iox2_service_type_e::IPC => node_struct.node.as_ref().ipc.name() as *const _ as *const _,
iox2_service_type_e::LOCAL => {
node_struct.node.as_ref::<process_local::Service>().name() as *const _ as *const _
node_struct.node.as_ref().local.name() as *const _ as *const _
}
}
}
Expand All @@ -204,11 +214,9 @@ pub unsafe extern "C" fn iox2_node_config(node_handle: iox2_node_h) -> iox2_conf
let node_struct = &mut *iox2_node_t::cast(node_handle);

match node_struct.service_type {
iox2_service_type_e::IPC => {
node_struct.node.as_ref::<zero_copy::Service>().config() as *const _ as *const _
}
iox2_service_type_e::IPC => node_struct.node.as_ref().ipc.config() as *const _ as *const _,
iox2_service_type_e::LOCAL => {
node_struct.node.as_ref::<process_local::Service>().config() as *const _ as *const _
node_struct.node.as_ref().local.config() as *const _ as *const _
}
}
}
Expand Down Expand Up @@ -367,18 +375,13 @@ pub unsafe extern "C" fn iox2_node_drop(node_handle: iox2_node_h) {

match node_struct.service_type {
iox2_service_type_e::IPC => {
std::ptr::drop_in_place(
node_struct.node.as_option_mut::<zero_copy::Service>() as *mut _
);
(node_struct.deleter)(node_struct);
ManuallyDrop::drop(&mut node_struct.node.as_mut().ipc);
}
iox2_service_type_e::LOCAL => {
std::ptr::drop_in_place(
node_struct.node.as_option_mut::<process_local::Service>() as *mut _
);
(node_struct.deleter)(node_struct);
ManuallyDrop::drop(&mut node_struct.node.as_mut().local);
}
}
(node_struct.deleter)(node_struct);
}

// END C API
Expand Down
10 changes: 5 additions & 5 deletions iceoryx2-ffi/ffi/src/node_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use crate::{
iox2_node_h, iox2_node_name_drop, iox2_node_name_h, iox2_node_name_t, iox2_node_t,
iox2_service_type_e, IntoCInt, IOX2_OK,
iox2_service_type_e, IntoCInt, NodeUnion, IOX2_OK,
};

use iceoryx2::node::NodeCreationFailure;
Expand Down Expand Up @@ -46,9 +46,9 @@ impl IntoCInt for NodeCreationFailure {
}

#[repr(C)]
#[repr(align(8))] // alignment of NodeBuilder
#[repr(align(8))] // alignment of Option<NodeBuilder>
pub struct iox2_node_builder_storage_t {
internal: [u8; 18432], // magic number obtained with size_of::<NodeBuilder>()
internal: [u8; 18432], // magic number obtained with size_of::<Option<NodeBuilder>>()
}

impl iox2_node_builder_storage_t {
Expand Down Expand Up @@ -280,15 +280,15 @@ pub unsafe extern "C" fn iox2_node_builder_create(
match service_type {
iox2_service_type_e::IPC => match node_builder.create::<zero_copy::Service>() {
Ok(node) => unsafe {
(*node_struct_ptr).init(service_type, node, deleter);
(*node_struct_ptr).init(service_type, NodeUnion::new_ipc(node), deleter);
},
Err(error) => {
return error.into_c_int();
}
},
iox2_service_type_e::LOCAL => match node_builder.create::<process_local::Service>() {
Ok(node) => unsafe {
(*node_struct_ptr).init(service_type, node, deleter);
(*node_struct_ptr).init(service_type, NodeUnion::new_local(node), deleter);
},
Err(error) => {
return error.into_c_int();
Expand Down

0 comments on commit aa3c7ee

Please sign in to comment.