From 0dece152672bd9ba8d9f05486cb6dfce2c030dc4 Mon Sep 17 00:00:00 2001 From: yellowhatter Date: Sat, 25 May 2024 21:19:22 +0300 Subject: [PATCH] - more additions to the API - C Provider and Client API tests --- src/shm/provider/alloc_layout_impl.rs | 8 +- src/shm/provider/shared_memory_provider.rs | 9 +- .../shared_memory_provider_backend.rs | 1 - .../provider/shared_memory_provider_impl.rs | 18 +- src/shm/provider/types.rs | 23 +- tests/z_api_shm_test.c | 219 ++++++++++++++++-- 6 files changed, 240 insertions(+), 38 deletions(-) diff --git a/src/shm/provider/alloc_layout_impl.rs b/src/shm/provider/alloc_layout_impl.rs index fab539a49..7e395a538 100644 --- a/src/shm/provider/alloc_layout_impl.rs +++ b/src/shm/provider/alloc_layout_impl.rs @@ -18,7 +18,7 @@ use zenoh::prelude::*; use zenoh::shm::AllocPolicy; use crate::{ - errors::{z_error_t, Z_EINVAL, Z_OK}, transmute::{Inplace, TransmuteFromHandle, TransmuteUninitPtr}, z_owned_buf_alloc_result_t + errors::{z_error_t, Z_EINVAL, Z_OK}, transmute::{Inplace, TransmuteCopy, TransmuteFromHandle, TransmuteUninitPtr}, z_owned_buf_alloc_result_t }; use super::{alloc_layout::{z_loaned_alloc_layout_t, z_owned_alloc_layout_t, CSHMLayout}, shared_memory_provider::z_loaned_shared_memory_provider_t, types::z_alloc_alignment_t}; @@ -33,7 +33,7 @@ pub(crate) fn alloc_layout_new( super::shared_memory_provider::CSHMProvider::Posix(provider) => { match provider .alloc(size) - .with_alignment(alignment.into()) + .with_alignment(alignment.transmute_copy()) .into_layout() { Ok(layout) => CSHMLayout::Posix(layout), @@ -46,7 +46,7 @@ pub(crate) fn alloc_layout_new( super::shared_memory_provider::CSHMProvider::Dynamic(provider) => { match provider .alloc(size) - .with_alignment(alignment.into()) + .with_alignment(alignment.transmute_copy()) .into_layout() { Ok(layout) => CSHMLayout::Dynamic(layout), @@ -59,7 +59,7 @@ pub(crate) fn alloc_layout_new( super::shared_memory_provider::CSHMProvider::DynamicThreadsafe(provider) => { match provider .alloc(size) - .with_alignment(alignment.into()) + .with_alignment(alignment.transmute_copy()) .into_layout() { Ok(layout) => CSHMLayout::DynamicThreadsafe(layout), diff --git a/src/shm/provider/shared_memory_provider.rs b/src/shm/provider/shared_memory_provider.rs index 9aea0ae23..85380127d 100644 --- a/src/shm/provider/shared_memory_provider.rs +++ b/src/shm/provider/shared_memory_provider.rs @@ -38,7 +38,7 @@ use super::{ shared_memory_provider_backend::{ zc_shared_memory_provider_backend_callbacks_t, DynamicSharedMemoryProviderBackend, }, - shared_memory_provider_impl::{alloc, alloc_async, defragment, garbage_collect, map}, + shared_memory_provider_impl::{alloc, alloc_async, available, defragment, garbage_collect, map}, types::z_alloc_alignment_t, }; @@ -248,6 +248,13 @@ pub extern "C" fn z_shared_memory_provider_garbage_collect( garbage_collect(provider); } +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_available( + provider: &z_loaned_shared_memory_provider_t, +) -> usize { + available(provider) +} + #[no_mangle] pub extern "C" fn z_shared_memory_provider_map( out_result: *mut MaybeUninit, diff --git a/src/shm/provider/shared_memory_provider_backend.rs b/src/shm/provider/shared_memory_provider_backend.rs index f80d112f8..d6315fbb7 100644 --- a/src/shm/provider/shared_memory_provider_backend.rs +++ b/src/shm/provider/shared_memory_provider_backend.rs @@ -38,7 +38,6 @@ pub struct zc_shared_memory_provider_backend_callbacks_t { defragment_fn: unsafe extern "C" fn(*mut c_void) -> usize, available_fn: unsafe extern "C" fn(*mut c_void) -> usize, layout_for_fn: unsafe extern "C" fn(*mut c_void, *mut z_owned_memory_layout_t), - drop_fn: unsafe extern "C" fn(*mut c_void), } #[derive(Debug)] diff --git a/src/shm/provider/shared_memory_provider_impl.rs b/src/shm/provider/shared_memory_provider_impl.rs index 6bbaf70ec..e872110d6 100644 --- a/src/shm/provider/shared_memory_provider_impl.rs +++ b/src/shm/provider/shared_memory_provider_impl.rs @@ -20,7 +20,7 @@ use zenoh::shm::{AllocPolicy, AsyncAllocPolicy, SharedMemoryProvider}; use crate::context::{Context, DroppableContext, ThreadsafeContext}; use crate::errors::{z_error_t, Z_EINVAL, Z_OK}; -use crate::transmute::{Inplace, TransmuteFromHandle, TransmuteUninitPtr}; +use crate::transmute::{Inplace, TransmuteCopy, TransmuteFromHandle, TransmuteUninitPtr}; use crate::{z_owned_buf_alloc_result_t, z_owned_shm_mut_t}; use super::chunk::z_allocated_chunk_t; @@ -132,6 +132,20 @@ pub(crate) fn garbage_collect(provider: &z_loaned_shared_memory_provider_t) { } } +pub(crate) fn available(provider: &z_loaned_shared_memory_provider_t) -> usize { + match provider.transmute_ref() { + super::shared_memory_provider::CSHMProvider::Posix(provider) => { + provider.available() + } + super::shared_memory_provider::CSHMProvider::Dynamic(provider) => { + provider.available() + } + super::shared_memory_provider::CSHMProvider::DynamicThreadsafe(provider) => { + provider.available() + } + } +} + #[no_mangle] pub(crate) fn map( out_result: *mut MaybeUninit, @@ -172,7 +186,7 @@ fn alloc_impl< ) -> z_error_t { let result = provider .alloc(size) - .with_alignment(alignment.into()) + .with_alignment(alignment.transmute_copy()) .with_policy::() .wait(); diff --git a/src/shm/provider/types.rs b/src/shm/provider/types.rs index c16cfd1fe..4c11773b2 100644 --- a/src/shm/provider/types.rs +++ b/src/shm/provider/types.rs @@ -20,7 +20,7 @@ use zenoh_util::core::zerror; use crate::{ errors::{z_error_t, Z_EINVAL, Z_OK}, transmute::{ - unwrap_ref_unchecked, Inplace, TransmuteIntoHandle, TransmuteRef, TransmuteUninitPtr, + unwrap_ref_unchecked, Inplace, TransmuteCopy, TransmuteFromHandle, TransmuteIntoHandle, TransmuteRef, TransmuteUninitPtr }, z_loaned_buf_alloc_result_t, z_loaned_chunk_alloc_result_t, z_loaned_memory_layout_t, z_owned_buf_alloc_result_t, z_owned_chunk_alloc_result_t, z_owned_memory_layout_t, @@ -66,15 +66,12 @@ impl From for ZAllocError { // An AllocAlignment. #[repr(C)] +#[derive(Clone, Copy)] pub struct z_alloc_alignment_t { - pub pow: u8, + pow: u8, } -impl From for AllocAlignment { - fn from(value: z_alloc_alignment_t) -> Self { - Self::new(value.pow) - } -} +decl_transmute_copy!(AllocAlignment, z_alloc_alignment_t); decl_transmute_owned!(Option, z_owned_memory_layout_t); decl_transmute_handle!(MemoryLayout, z_loaned_memory_layout_t); @@ -126,6 +123,18 @@ pub extern "C" fn z_memory_layout_drop(this: &mut z_owned_memory_layout_t) { let _ = this.transmute_mut().take(); } +/// Deletes Memory Layout +#[no_mangle] +pub extern "C" fn z_memory_layout_get_data( + out_size: &mut MaybeUninit, + out_alignment: &mut MaybeUninit, + this: &z_loaned_memory_layout_t, +) { + let layout = this.transmute_ref(); + out_size.write(layout.size()); + out_alignment.write(layout.alignment().transmute_copy() ); +} + decl_transmute_owned!(Option, z_owned_chunk_alloc_result_t); decl_transmute_handle!(ChunkAllocResult, z_loaned_chunk_alloc_result_t); diff --git a/tests/z_api_shm_test.c b/tests/z_api_shm_test.c index 62b123855..76d90ae6a 100644 --- a/tests/z_api_shm_test.c +++ b/tests/z_api_shm_test.c @@ -113,34 +113,23 @@ bool test_allocation(const z_loaned_shared_memory_provider_t* provider, size_t s return false; } -int run_provider() { - const size_t total_size = 4096; - const size_t buf_ok_size = 1024; - const size_t buf_err_size = 8192; - - z_alloc_alignment_t alignment = {4}; - - z_owned_memory_layout_t layout; - ASSERT_OK(z_memory_layout_new(&layout, total_size, alignment)); - ASSERT_CHECK(layout); - - z_owned_shared_memory_provider_t provider; - ASSERT_OK(z_posix_shared_memory_provider_new(&provider, z_loan(layout))); - ASSERT_CHECK(provider); - +int test_provider(z_owned_shared_memory_provider_t* provider, z_alloc_alignment_t alignment, size_t buf_ok_size, + size_t buf_err_size) { // test allocation OK for (int i = 0; i < 100; ++i) { - ASSERT_TRUE(test_allocation(z_loan(provider), buf_ok_size, alignment)); + ASSERT_TRUE(test_allocation(z_loan(*provider), buf_ok_size, alignment)); } // test allocation ERROR - ASSERT_TRUE(!test_allocation(z_loan(provider), buf_err_size, alignment)); + if (buf_err_size) { + ASSERT_TRUE(!test_allocation(z_loan(*provider), buf_err_size, alignment)); + } // OK layouted allocations { // make OK allocation layout z_owned_alloc_layout_t alloc_layout; - ASSERT_OK(z_alloc_layout_new(&alloc_layout, z_loan(provider), buf_ok_size, alignment)); + ASSERT_OK(z_alloc_layout_new(&alloc_layout, z_loan(*provider), buf_ok_size, alignment)); ASSERT_CHECK(alloc_layout); // test layouted allocation OK for (int i = 0; i < 100; ++i) { @@ -151,10 +140,10 @@ int run_provider() { } // ERR layouted allocation - { + if (buf_err_size) { // make ERR allocation layout z_owned_alloc_layout_t alloc_layout; - ASSERT_OK(z_alloc_layout_new(&alloc_layout, z_loan(provider), buf_err_size, alignment)); + ASSERT_OK(z_alloc_layout_new(&alloc_layout, z_loan(*provider), buf_err_size, alignment)); ASSERT_CHECK(alloc_layout); // test layouted allocation ERROR ASSERT_TRUE(!test_layouted_allocation(z_loan(alloc_layout))); @@ -163,8 +152,149 @@ int run_provider() { } // additional functions - z_shared_memory_provider_defragment(z_loan(provider)); - z_shared_memory_provider_garbage_collect(z_loan(provider)); + z_shared_memory_provider_defragment(z_loan(*provider)); + z_shared_memory_provider_garbage_collect(z_loan(*provider)); + + return 0; +} + +typedef struct { + uint8_t* bytes; + bool* busy_flags; + size_t count; + size_t available; +} test_provider_context; + +void delete_fn(void* context) { + test_provider_context* c = (test_provider_context*)context; + free(c->bytes); + free(c->busy_flags); +} +void alloc_fn(void* context, const struct z_loaned_memory_layout_t* layout, + struct z_owned_chunk_alloc_result_t* result) { + assert(context); + assert(layout); + assert(result); + + // check size and alignment + size_t size = 0; + z_alloc_alignment_t alignment; + z_memory_layout_get_data(&size, &alignment, layout); + assert(size == 1); + assert(alignment.pow == 0); + + // perform allocation + test_provider_context* c = (test_provider_context*)context; + for (int i = 0; i < c->count; ++i) { + if (!c->busy_flags[i]) { + c->busy_flags[i] = true; + c->available--; + + z_allocated_chunk_t chunk; + chunk.data = &c->bytes[i]; + uint64_t ptr = (uint64_t)(chunk.data); + chunk.descriptpr.chunk = ptr & 0xFFFFFFFF; + chunk.descriptpr.len = 1; + chunk.descriptpr.segment = (ptr >> 32) & 0xFFFFFFFF; + + z_chunk_alloc_result_new_ok(result, chunk); + return; + } + } + z_chunk_alloc_result_new_error(result, Z_ALLOC_ERROR_OUT_OF_MEMORY); +} +void free_fn(void* context, const struct z_chunk_descriptor_t* chunk) { + assert(context); + assert(chunk); + + assert(chunk->len == 1); + + // restore data ptr from chunk descriptor + void* data = (void*)(((uint64_t)chunk->chunk) | ((((uint64_t)chunk->segment) << 32) & 0xFFFFFFFF00000000)); + + // calc index from data ptr + test_provider_context* c = (test_provider_context*)context; + int64_t index = (int64_t)data - (int64_t)c->bytes; + assert(index >= 0); + assert(index < c->count); + + // mark this entry as free + c->busy_flags[index] = false; + c->available++; +} +size_t defragment_fn(void* context) { + assert(context); + return 0; +} +size_t available_fn(void* context) { + assert(context); + + test_provider_context* c = (test_provider_context*)context; + return c->available; +} +void layout_for_fn(void* context, struct z_owned_memory_layout_t* layout) { + assert(context); + assert(layout); + + assert(z_check(*layout)); + + // check size and alignment + size_t size = 0; + z_alloc_alignment_t alignment; + z_memory_layout_get_data(&size, &alignment, z_loan(*layout)); + + if (size != 1 || alignment.pow != 0) { + z_memory_layout_drop(layout); + } +} + +int run_c_provider() { + const z_protocol_id_t id = 100500; + const size_t size = 1024; + + // init test context + test_provider_context test_context; + test_context.available = size; + test_context.count = size; + test_context.busy_flags = malloc(sizeof(bool) * size); + test_context.bytes = malloc(sizeof(uint8_t) * size); + zc_context_t context = {&test_context, &delete_fn}; + + // init callbacks + zc_shared_memory_provider_backend_callbacks_t callbacks = {&alloc_fn, &free_fn, &defragment_fn, &available_fn, + &layout_for_fn}; + // create provider + z_owned_shared_memory_provider_t provider; + z_shared_memory_provider_new(&provider, id, context, callbacks); + + ASSERT_CHECK(provider) + + z_alloc_alignment_t alignment = {0}; + + ASSERT_OK(test_provider(&provider, alignment, 1, 0)); + + z_drop(z_move(provider)); + ASSERT_CHECK_ERR(provider); + + return 0; +} + +int run_posix_provider() { + const size_t total_size = 4096; + const size_t buf_ok_size = total_size / 4; + const size_t buf_err_size = total_size * 2; + + z_alloc_alignment_t alignment = {4}; + + z_owned_memory_layout_t layout; + ASSERT_OK(z_memory_layout_new(&layout, total_size, alignment)); + ASSERT_CHECK(layout); + + z_owned_shared_memory_provider_t provider; + ASSERT_OK(z_posix_shared_memory_provider_new(&provider, z_loan(layout))); + ASSERT_CHECK(provider); + + ASSERT_OK(test_provider(&provider, alignment, buf_ok_size, buf_err_size)); z_drop(z_move(provider)); ASSERT_CHECK_ERR(provider); @@ -219,10 +349,53 @@ int run_client_storage() { return 0; } +void delete_client_fn(void* context) { assert(context == NULL); } +void delete_segment_fn(void* context) {} + +uint8_t* map_fn(void* context, z_chunk_id_t chunk) { + return (uint8_t*)((uint64_t)chunk | ((((uint64_t)context) << 32) & 0xFFFFFFFF00000000)); +} + +bool attach_fn(void* context, z_segment_id_t id, struct z_shared_memory_segment_t* out_segment) { + assert(context == NULL); + out_segment->context.context.ptr = (void*)(uint64_t)id; + out_segment->context.delete_fn = &delete_segment_fn; + out_segment->callbacks.map_fn = &map_fn; + return true; +} + +int run_c_client() { + zc_owned_shared_memory_client_list_t list; + ASSERT_OK(zc_shared_memory_client_list_new(&list)); + ASSERT_CHECK(list); + + zc_threadsafe_context_t context = {NULL, &delete_client_fn}; + zc_shared_memory_client_callbacks_t callbacks = {&attach_fn}; + z_owned_shared_memory_client_t client; + ASSERT_OK(z_shared_memory_client_new(&client, context, callbacks)); + ASSERT_CHECK(client); + + ASSERT_OK(zc_shared_memory_client_list_add_client(100500, z_move(client), z_loan_mut(list))); + ASSERT_CHECK_ERR(client); + + z_owned_shared_memory_client_storage_t storage; + ASSERT_OK(z_shared_memory_client_storage_new(&storage, z_loan(list), true)); + ASSERT_CHECK(storage); + + z_drop(z_move(storage)); + ASSERT_CHECK_ERR(storage); + + z_drop(z_move(list)); + ASSERT_CHECK_ERR(list); + return 0; +} + int main() { - ASSERT_OK(run_provider()); + ASSERT_OK(run_posix_provider()); + ASSERT_OK(run_c_provider()); ASSERT_OK(run_default_client_storage()); ASSERT_OK(run_global_client_storage()); ASSERT_OK(run_client_storage()); + ASSERT_OK(run_c_client()); return 0; }