Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for custom / user-defined allocators #231

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion .github/workflows/emscripten.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Compile debug
run: |
mkdir build
emcmake cmake -E env CFLAGS="-DZ_LINK_WS=1 -DZ_LINK_TCP=0 -DZ_LINK_UDP_MULTICAST=0 -DZ_LINK_UDP_UNICAST=0 -DZ_SCOUTING_UDP=0" cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_C_STANDARD=11 -DBUILD_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=OFF -DBUILD_MULTICAST=OFF -DBUILD_INTEGRATION=OFF -DBUILD_TOOLS=OFF -DZENOH_DEBUG=3 -H. -Bbuild
emcmake cmake -E env CFLAGS="-DZ_LINK_WS=1 -DZ_LINK_TCP=0 -DZ_LINK_UDP_MULTICAST=0 -DZ_LINK_UDP_UNICAST=0 -DZ_SCOUTING_UDP=0" cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_C_STANDARD=11 -DBUILD_WITH_CUSTOM_ALLOCATOR=OFF -DBUILD_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=OFF -DBUILD_MULTICAST=OFF -DBUILD_INTEGRATION=OFF -DBUILD_TOOLS=OFF -DZENOH_DEBUG=3 -H. -Bbuild
make -C build


6 changes: 5 additions & 1 deletion BSDmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ BUILD_TYPE?=Release
# Accepted values: ON, OFF
BUILD_EXAMPLES?=ON

# Build with custom / user allocators. This sets the BUILD_WITH_CUSTOM_ALLOCATOR variable.
# Accepted values: ON, OFF
BUILD_WITH_CUSTOM_ALLOCATOR?=OFF

# Build testing. This sets the BUILD_TESTING variable.
# Accepted values: ON, OFF
BUILD_TESTING?=ON
Expand Down Expand Up @@ -58,7 +62,7 @@ CROSSIMG_PREFIX=zenoh-pico_
# NOTES:
# - ARM: old versions of dockcross/dockcross were creating some issues since they used an old GCC (4.8.3) which lacks <stdatomic.h> (even using -std=gnu11)

CMAKE_OPT=-DZENOH_DEBUG=$(ZENOH_DEBUG) -DBUILD_EXAMPLES=$(BUILD_EXAMPLES) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DBUILD_TESTING=$(BUILD_TESTING) -DBUILD_MULTICAST=$(BUILD_MULTICAST) -DBUILD_INTEGRATION=$(BUILD_INTEGRATION) -DBUILD_TOOLS=$(BUILD_TOOLS) -DBUILD_SHARED_LIBS=$(BUILD_SHARED_LIBS) -H.
CMAKE_OPT=-DZENOH_DEBUG=$(ZENOH_DEBUG) -DBUILD_EXAMPLES=$(BUILD_EXAMPLES) -DBUILD_WITH_CUSTOM_ALLOCATOR=$(BUILD_WITH_CUSTOM_ALLOCATOR) -D -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DBUILD_TESTING=$(BUILD_TESTING) -DBUILD_MULTICAST=$(BUILD_MULTICAST) -DBUILD_INTEGRATION=$(BUILD_INTEGRATION) -DBUILD_TOOLS=$(BUILD_TOOLS) -DBUILD_SHARED_LIBS=$(BUILD_SHARED_LIBS) -H.

all: make

Expand Down
75 changes: 65 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,72 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/zenoh-pico
COMPONENT Headers
)

if(BUILD_EXAMPLES)
add_subdirectory(examples)
milyin marked this conversation as resolved.
Show resolved Hide resolved
endif()
if(BUILD_WITH_CUSTOM_ALLOCATOR)
add_definitions(-DZ_CUSTOM_ALLOCATOR=1)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/examples)

if(UNIX)
if(CMAKE_C_STANDARD MATCHES "99")
add_executable(z_pub_ualloc ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_pub_ualloc.c)
else()
add_executable(z_pub_ualloc ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_pub_ualloc.c)
endif()

target_link_libraries(z_pub_ualloc ${Libname})
endif()
else()
if(BUILD_EXAMPLES)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/examples)

if(UNIX)
if(CMAKE_C_STANDARD MATCHES "99")
add_executable(z_put ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_put.c)
add_executable(z_pub ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_pub.c)
add_executable(z_pub_st ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_pub_st.c)
add_executable(z_sub ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_sub.c)
add_executable(z_sub_st ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_sub_st.c)
add_executable(z_pull ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_pull.c)
add_executable(z_get ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_get.c)
add_executable(z_queryable ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_queryable.c)
add_executable(z_info ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_info.c)
add_executable(z_scout ${PROJECT_SOURCE_DIR}/examples/unix/c99/z_scout.c)
else()
add_executable(z_put ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_put.c)
add_executable(z_pub ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_pub.c)
add_executable(z_pub_st ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_pub_st.c)
add_executable(z_sub ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_sub.c)
add_executable(z_sub_st ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_sub_st.c)
add_executable(z_pull ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_pull.c)
add_executable(z_get ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_get.c)
add_executable(z_queryable ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_queryable.c)
add_executable(z_info ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_info.c)
add_executable(z_scout ${PROJECT_SOURCE_DIR}/examples/unix/c11/z_scout.c)
endif()
elseif (MSVC)
add_executable(z_put ${PROJECT_SOURCE_DIR}/examples/windows/z_put.c)
add_executable(z_pub ${PROJECT_SOURCE_DIR}/examples/windows/z_pub.c)
add_executable(z_pub_st ${PROJECT_SOURCE_DIR}/examples/windows/z_pub_st.c)
add_executable(z_sub ${PROJECT_SOURCE_DIR}/examples/windows/z_sub.c)
add_executable(z_sub_st ${PROJECT_SOURCE_DIR}/examples/windows/z_sub_st.c)
add_executable(z_pull ${PROJECT_SOURCE_DIR}/examples/windows/z_pull.c)
add_executable(z_get ${PROJECT_SOURCE_DIR}/examples/windows/z_get.c)
add_executable(z_queryable ${PROJECT_SOURCE_DIR}/examples/windows/z_queryable.c)
add_executable(z_info ${PROJECT_SOURCE_DIR}/examples/windows/z_info.c)
add_executable(z_scout ${PROJECT_SOURCE_DIR}/examples/windows/z_scout.c)
endif()

target_link_libraries(z_put ${Libname})
target_link_libraries(z_pub ${Libname})
target_link_libraries(z_pub_st ${Libname})
target_link_libraries(z_sub ${Libname})
target_link_libraries(z_sub_st ${Libname})
target_link_libraries(z_pull ${Libname})
target_link_libraries(z_get ${Libname})
target_link_libraries(z_queryable ${Libname})
target_link_libraries(z_info ${Libname})
target_link_libraries(z_scout ${Libname})
endif()

if(UNIX OR MSVC)
if(BUILD_TOOLS)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tools)
add_executable(z_keyexpr_canonizer ${PROJECT_SOURCE_DIR}/tools/z_keyexpr_canonizer.c)
Expand All @@ -236,25 +297,19 @@ if(UNIX OR MSVC)
add_executable(z_iobuf_test ${PROJECT_SOURCE_DIR}/tests/z_iobuf_test.c)
add_executable(z_msgcodec_test ${PROJECT_SOURCE_DIR}/tests/z_msgcodec_test.c)
add_executable(z_keyexpr_test ${PROJECT_SOURCE_DIR}/tests/z_keyexpr_test.c)
add_executable(z_api_null_drop_test ${PROJECT_SOURCE_DIR}/tests/z_api_null_drop_test.c)
milyin marked this conversation as resolved.
Show resolved Hide resolved
add_executable(z_api_double_drop_test ${PROJECT_SOURCE_DIR}/tests/z_api_double_drop_test.c)

target_link_libraries(z_data_struct_test ${Libname})
target_link_libraries(z_endpoint_test ${Libname})
target_link_libraries(z_iobuf_test ${Libname})
target_link_libraries(z_msgcodec_test ${Libname})
target_link_libraries(z_keyexpr_test ${Libname})
target_link_libraries(z_api_null_drop_test ${Libname})
target_link_libraries(z_api_double_drop_test ${Libname})

enable_testing()
add_test(z_data_struct_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_data_struct_test)
add_test(z_endpoint_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_endpoint_test)
add_test(z_iobuf_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_iobuf_test)
add_test(z_msgcodec_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_msgcodec_test)
add_test(z_keyexpr_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_keyexpr_test)
add_test(z_api_null_drop_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_api_null_drop_test)
add_test(z_api_double_drop_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_api_double_drop_test)
endif()

if(BUILD_MULTICAST)
Expand Down
6 changes: 5 additions & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ BUILD_TYPE?=Release
# Accepted values: ON, OFF
BUILD_EXAMPLES?=ON

# Build with custom / user allocators. This sets the BUILD_WITH_CUSTOM_ALLOCATOR variable.
# Accepted values: ON, OFF
BUILD_WITH_CUSTOM_ALLOCATOR?=OFF

# Build testing. This sets the BUILD_TESTING variable.
# Accepted values: ON, OFF
BUILD_TESTING?=ON
Expand Down Expand Up @@ -58,7 +62,7 @@ CROSSIMG_PREFIX=zenoh-pico_
# NOTES:
# - ARM: old versions of dockcross/dockcross were creating some issues since they used an old GCC (4.8.3) which lacks <stdatomic.h> (even using -std=gnu11)

CMAKE_OPT=-DZENOH_DEBUG=$(ZENOH_DEBUG) -DBUILD_EXAMPLES=$(BUILD_EXAMPLES) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DBUILD_TESTING=$(BUILD_TESTING) -DBUILD_MULTICAST=$(BUILD_MULTICAST) -DBUILD_INTEGRATION=$(BUILD_INTEGRATION) -DBUILD_TOOLS=$(BUILD_TOOLS) -DBUILD_SHARED_LIBS=$(BUILD_SHARED_LIBS) -H.
CMAKE_OPT=-DZENOH_DEBUG=$(ZENOH_DEBUG) -DBUILD_EXAMPLES=$(BUILD_EXAMPLES) -DBUILD_WITH_CUSTOM_ALLOCATOR=$(BUILD_WITH_CUSTOM_ALLOCATOR) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DBUILD_TESTING=$(BUILD_TESTING) -DBUILD_MULTICAST=$(BUILD_MULTICAST) -DBUILD_INTEGRATION=$(BUILD_INTEGRATION) -DBUILD_TOOLS=$(BUILD_TOOLS) -DBUILD_SHARED_LIBS=$(BUILD_SHARED_LIBS) -H.

all: make

Expand Down
199 changes: 199 additions & 0 deletions examples/unix/c11/z_pub_ualloc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
//
// Copyright (c) 2022 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
//
// Contributors:
// ZettaScale Zenoh Team, <[email protected]>
//

#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <zenoh-pico.h>

// First Fit custom / user defined allocators
#define WORD uint64_t // FIXME: not true for other architectues like 32-bits architectures
#define VAS_SIZE 1 * 1024 * 1024 // Virtual address space in bytes

typedef struct z_m_block_hdr_t {
size_t size; // Block size
struct z_m_block_t *next; // The next block in the list
_Bool is_used; // Whether this block is currently being used
} z_m_block_hdr_t;

typedef struct z_m_block_t {
z_m_block_hdr_t hdr;
WORD data[1]; // Payload pointer. Note: this MUST always be the last member in the struct.
} z_m_block_t;

z_mutex_t mut;
void *z_heap_start = NULL; // Heap start. It must be explicitly initialized
void *z_heap_end = NULL; // Heap end. Defined for convenience to avoid computing
// it multiple times
z_m_block_t *p_brk = NULL; // Program break identifying the top of our local heap

void *z_minit(size_t size) {
z_heap_start = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (z_heap_start == MAP_FAILED) {
z_heap_start = NULL;
z_heap_end = NULL;
} else {
z_heap_end = z_heap_start + (size * sizeof(uint8_t));
}

z_m_block_t *new_block = z_heap_start;
if (((uint8_t *)new_block + (sizeof(z_m_block_hdr_t) + 0)) <= (uint8_t *)z_heap_end) {
*new_block = (z_m_block_t){.hdr = {.next = NULL, .is_used = true, .size = 0}};
p_brk = (z_m_block_t *)((uint8_t *)new_block->data + new_block->hdr.size);
}

return z_heap_start;
}

void z_muninit(void *start, size_t size) { munmap(start, size); }

// Align the size to the word size.
size_t z_malign(size_t size) {
size_t aligned_size = (size + sizeof(WORD) - 1) & ~(sizeof(WORD) - 1);
return aligned_size;
}

// Allocates a block of memory of size bytes, following a first fit strategy.
// Due to allignment extra bytes might be allocated.
void *z_malloc(size_t size) {
z_mutex_lock(&mut);
WORD *ret = NULL;
size_t aligned_size = z_malign(size);

z_m_block_t *block = z_heap_start;
_Bool found = false;
while (block->hdr.next != NULL) {
block = block->hdr.next;
if (block->hdr.is_used == false && block->hdr.size >= aligned_size) {
found = true;
break;
}
}

if (found == true) {
ret = block->data;
block->hdr.is_used = true;
} else {
z_m_block_t *new_block = p_brk;
if (((uint8_t *)new_block + (sizeof(z_m_block_hdr_t) + aligned_size)) <= (uint8_t *)z_heap_end) {
*new_block = (z_m_block_t){.hdr = {.next = NULL, .is_used = true, .size = aligned_size}};
ret = new_block->data;
block->hdr.next = new_block;
p_brk = (z_m_block_t *)((uint8_t *)new_block->data + new_block->hdr.size);
}
}
z_mutex_unlock(&mut);

return ret;
}

void z_free(void *ptr) {
z_mutex_lock(&mut);
z_m_block_t *block = ptr - sizeof(z_m_block_hdr_t);
block->hdr.is_used = false;
z_mutex_unlock(&mut);
}
//

int main(int argc, char **argv) {
if (z_minit(VAS_SIZE) == NULL) {
printf("Failed to reserve memory\n");
}

const char *keyexpr = "demo/example/zenoh-pico-pub";
const char *value = "Pub from Pico!";
const char *mode = "client";
char *locator = NULL;

int opt;
while ((opt = getopt(argc, argv, "k:v:e:m:")) != -1) {
switch (opt) {
case 'k':
keyexpr = optarg;
break;
case 'v':
value = optarg;
break;
case 'e':
locator = optarg;
break;
case 'm':
mode = optarg;
break;
case '?':
if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm') {
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
} else {
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
}
return 1;
default:
return -1;
}
}

z_owned_config_t config = z_config_default();
zp_config_insert(z_loan(config), Z_CONFIG_MODE_KEY, z_string_make(mode));
if (locator != NULL) {
zp_config_insert(z_loan(config), Z_CONFIG_PEER_KEY, z_string_make(locator));
}

printf("Opening session...\n");
z_owned_session_t s = z_open(z_move(config));
if (!z_check(s)) {
printf("Unable to open session!\n");
return -1;
}

// Start read and lease tasks for zenoh-pico
if (zp_start_read_task(z_loan(s), NULL) < 0 || zp_start_lease_task(z_loan(s), NULL) < 0) {
printf("Unable to start read and lease tasks");
return -1;
}

printf("Declaring publisher for '%s'...\n", keyexpr);
z_owned_publisher_t pub = z_declare_publisher(z_loan(s), z_keyexpr(keyexpr), NULL);
if (!z_check(pub)) {
printf("Unable to declare publisher for key expression!\n");
return -1;
}

char *buf = (char *)malloc(256);
for (int idx = 0; 1; ++idx) {
sleep(1);
snprintf(buf, 256, "[%4d] %s", idx, value);
printf("Putting Data ('%s': '%s')...\n", keyexpr, buf);

z_publisher_put_options_t options = z_publisher_put_options_default();
options.encoding = z_encoding(Z_ENCODING_PREFIX_TEXT_PLAIN, NULL);
z_publisher_put(z_loan(pub), (const uint8_t *)buf, strlen(buf), &options);
}

z_undeclare_publisher(z_move(pub));

// Stop read and lease tasks for zenoh-pico
zp_stop_read_task(z_loan(s));
zp_stop_lease_task(z_loan(s));

z_close(z_move(s));

free(buf);

z_muninit(z_heap_start, VAS_SIZE);

return 0;
}
Loading