diff --git a/CMakeLists.txt b/CMakeLists.txt index edde187..0a9ef9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,9 @@ target_include_directories( add_executable(strings ${CMAKE_CURRENT_SOURCE_DIR}/app/strings.c) target_link_libraries(strings PRIVATE c-libs) +add_executable(rc ${CMAKE_CURRENT_SOURCE_DIR}/app/rc.c) +target_link_libraries(rc PRIVATE c-libs) + include(CTest) if(BUILD_TESTING) find_package(PkgConfig REQUIRED) @@ -30,25 +33,26 @@ endif() include(CMakePackageConfigHelpers) include(GNUInstallDirs) -install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - install( TARGETS c-libs EXPORT c-libs - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin) + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/c-libs + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install( EXPORT c-libs FILE c-libsTargets.cmake NAMESPACE c-libs:: - DESTINATION lib/cmake/c-libs) + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/c-libs) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/c-libsConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/c-libsConfig.cmake - INSTALL_DESTINATION lib/cmake/c-libs) + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/c-libs) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/c-libsConfig.cmake - DESTINATION lib/cmake/c-libs) + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/c-libs) diff --git a/app/rc.c b/app/rc.c new file mode 100644 index 0000000..2fe0e80 --- /dev/null +++ b/app/rc.c @@ -0,0 +1,35 @@ +#include +#include +#include + +void do_stuff(char *rc_s) { printf("Ptr %p -> %s\n", rc_s, rc_s); } + +char *mk_rc_str(const char *s) { + char *rc_s = rc_new(20); + strncpy(rc_s, s, 20); + return rc_s; +} + +void rc_info(void *rc) { printf("RC: %d, WRC: %d\n", rc_rc(rc), rc_wrc(rc)); } + +static char *global_rc_s; + +int main() { + char *rc_s = mk_rc_str("Hello World!"); + + global_rc_s = rc_ref(rc_s); + rc_info(rc_s); + rc_unref(rc_s); + rc_info(global_rc_s); + + do_stuff(global_rc_s); + + global_rc_s = rc_realloc(global_rc_s, 20480); + memset(global_rc_s, 'A', 20480); + global_rc_s[50] = '\0'; + do_stuff(global_rc_s); + + rc_unref(global_rc_s); + + return 0; +} diff --git a/flake.nix b/flake.nix index e563792..3a121a4 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,9 @@ flake = { overlays.default = final: prev: { - c-libs = final.callPackage ./nix/c-libs.nix {}; + c-libs = (final.callPackage ./nix/c-libs.nix {}).overrideAttrs { + enableShared = true; + }; }; }; @@ -49,6 +51,8 @@ shellHook = '' export CMAKE_EXPORT_COMPILE_COMMANDS=ON export BUILD_TESTING=ON + export MANPATH="${pkgs.man-pages-posix}/share/man:$MANPATH" + export MANPATH="${pkgs.man-pages}/share/man:$MANPATH" ''; }; }; diff --git a/include/c-libs/rcmem.h b/include/c-libs/rcmem.h new file mode 100644 index 0000000..0c4d4b3 --- /dev/null +++ b/include/c-libs/rcmem.h @@ -0,0 +1,108 @@ +#ifndef CLIBS_RCMEM_H +#define CLIBS_RCMEM_H +#define _GNU_SOURCE + +#include +#include +#include +#include + +typedef struct { + uint32_t rc; + uint32_t wrc; + size_t len; +} RCHeader; + +void *rc_new(size_t size) { + RCHeader *hdr = mmap(NULL, sizeof(RCHeader) + size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + + if (hdr == MAP_FAILED) { + return NULL; + } + + hdr->rc = 1; + hdr->len = size; + + return hdr + 1; +} + +void *rc_ref(void *ptr) { + RCHeader *hdr = ((RCHeader *)ptr) - 1; + hdr->rc += 1; + + return ptr; +} + +void *rc_wref(void *ptr) { + RCHeader *hdr = ((RCHeader *)ptr) - 1; + hdr->wrc += 1; + + return ptr; +} + +uint32_t rc_rc(void *ptr) { + RCHeader *hdr = ((RCHeader *)ptr) - 1; + + return hdr->rc; +} + +uint32_t rc_wrc(void *ptr) { + RCHeader *hdr = ((RCHeader *)ptr) - 1; + + return hdr->wrc; +} + +void *rc_clone(void *ptr) { + RCHeader *hdr = ((RCHeader *)ptr) - 1; + + size_t len = sizeof(RCHeader) + hdr->len; + + RCHeader *chdr = mmap(NULL, len, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + + memcpy(chdr, hdr, len); + + return chdr + 1; +} + +void *rc_realloc(void *ptr, size_t size) { + RCHeader *hdr = ((RCHeader *)ptr) - 1; + size_t old_size = sizeof(RCHeader) + hdr->len; + size_t new_size = sizeof(RCHeader) + size; + + RCHeader *new = mremap(hdr, old_size, new_size, MREMAP_MAYMOVE); + new->len = size; + + if (new == MAP_FAILED) { + return NULL; + } + + return new + 1; +} + +uint32_t rc_wunref(void *ptr) { + RCHeader *hdr = ((RCHeader *)ptr) - 1; + hdr->wrc -= 1; + uint32_t wrc = hdr->wrc; + + if (!hdr->wrc && !hdr->rc) { + munmap(hdr, sizeof(RCHeader) + hdr->len); + } + + return wrc; +} + +uint32_t rc_unref(void *ptr) { + RCHeader *hdr = ((RCHeader *)ptr) - 1; + hdr->rc -= 1; + uint32_t rc = hdr->rc; + + if (!hdr->wrc && !hdr->rc) { + munmap(hdr, sizeof(RCHeader) + hdr->len); + } + + return rc; +} + +#endif diff --git a/nix/c-libs.nix b/nix/c-libs.nix index d36065b..c456365 100644 --- a/nix/c-libs.nix +++ b/nix/c-libs.nix @@ -10,12 +10,12 @@ stdenv.mkDerivation (finalAttrs: { pname = "c-libs"; version = "0.1.0"; src = ../.; - outputs = ["out" "dev"]; nativeBuildInputs = [cmake] ++ lib.optional finalAttrs.doCheck pkg-config; buildInputs = [] ++ lib.optional finalAttrs.doCheck criterion; cmakeFlags = [ (lib.cmakeBool "BUILD_TESTING" finalAttrs.doCheck) + (lib.cmakeBool "BUILD_SHARED_LIBS" finalAttrs.enableShared or false) ]; doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;