diff options
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | meson.build | 10 | ||||
-rw-r--r-- | src/jalv.c | 4 | ||||
-rw-r--r-- | src/jalv_config.h | 2 | ||||
-rw-r--r-- | src/jalv_console.c | 6 | ||||
-rw-r--r-- | src/jalv_gtk.c | 2 | ||||
-rw-r--r-- | src/state.c | 2 | ||||
-rw-r--r-- | src/worker.c | 6 | ||||
-rw-r--r-- | src/zix/allocator.c | 96 | ||||
-rw-r--r-- | src/zix/allocator.h | 186 | ||||
-rw-r--r-- | src/zix/attributes.h | 81 | ||||
-rw-r--r-- | src/zix/common.h | 55 | ||||
-rw-r--r-- | src/zix/ring.c | 278 | ||||
-rw-r--r-- | src/zix/ring.h | 215 | ||||
-rw-r--r-- | src/zix/sem.h | 229 | ||||
-rw-r--r-- | src/zix/thread.h | 117 | ||||
-rw-r--r-- | subprojects/zix.wrap | 8 | ||||
-rw-r--r-- | test/meson.build | 1 |
18 files changed, 32 insertions, 1272 deletions
@@ -1,3 +1,9 @@ +jalv (1.6.9) stable; urgency=medium + + * Switch to external zix dependency + + -- David Robillard <d@drobilla.net> Wed, 16 Nov 2022 15:50:45 +0000 + jalv (1.6.8) stable; urgency=medium * Add Gtk plugin selector UI and desktop file diff --git a/meson.build b/meson.build index 9ebc14f..72f14e0 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ # SPDX-License-Identifier: 0BSD OR ISC project('jalv', ['c', 'cpp'], - version: '1.6.8', + version: '1.6.9', license: 'ISC', meson_version: '>= 0.56.0', default_options: [ @@ -48,6 +48,10 @@ m_dep = cc.find_library('m', required: false) thread_dep = dependency('threads') +zix_dep = dependency('zix-0', + version: '>= 0.3.0', + fallback: ['zix', 'zix_dep']) + serd_dep = dependency('serd-0', version: '>= 0.30.0', fallback: ['serd', 'serd_dep']) @@ -114,7 +118,6 @@ endif platform_defines = [ '-DJALV_VERSION="@0@"'.format(meson.project_version()), - '-DZIX_STATIC', ] suil_defines = ['-DHAVE_SUIL=@0@'.format(suil_dep.found().to_int())] @@ -221,8 +224,6 @@ sources = backend_sources + files( 'src/state.c', 'src/symap.c', 'src/worker.c', - 'src/zix/allocator.c', - 'src/zix/ring.c', ) common_dependencies = [ @@ -233,6 +234,7 @@ common_dependencies = [ sratom_dep, suil_dep, thread_dep, + zix_dep, ] # Internal JACK client library @@ -41,7 +41,7 @@ #include "serd/serd.h" #include "sratom/sratom.h" #include "symap.h" -#include "zix/common.h" +#include "zix/attributes.h" #include "zix/ring.h" #include "zix/sem.h" @@ -740,7 +740,7 @@ int jalv_update(Jalv* jalv) { // Check quit flag and close if set - if (zix_sem_try_wait(&jalv->done)) { + if (!zix_sem_try_wait(&jalv->done)) { jalv_frontend_close(jalv); return 0; } diff --git a/src/jalv_config.h b/src/jalv_config.h index 0e57a18..3d0133e 100644 --- a/src/jalv_config.h +++ b/src/jalv_config.h @@ -27,7 +27,7 @@ #define JALV_CONFIG_H // Define version unconditionally so a warning will catch a mismatch -#define JALV_VERSION "1.6.8" +#define JALV_VERSION "1.6.9" #if !defined(JALV_NO_DEFAULT_CONFIG) diff --git a/src/jalv_console.c b/src/jalv_console.c index 277f290..0c8dd06 100644 --- a/src/jalv_console.c +++ b/src/jalv_console.c @@ -13,7 +13,7 @@ #include "lilv/lilv.h" #include "lv2/ui/ui.h" -#include "zix/common.h" +#include "zix/attributes.h" #include "zix/sem.h" #if USE_SUIL @@ -273,7 +273,7 @@ jalv_run_custom_ui(Jalv* jalv) show_iface->show(suil_instance_get_handle(jalv->ui_instance)); // Drive idle interface until interrupted - while (!zix_sem_try_wait(&jalv->done)) { + while (zix_sem_try_wait(&jalv->done)) { jalv_update(jalv); if (idle_iface->idle(suil_instance_get_handle(jalv->ui_instance))) { break; @@ -320,7 +320,7 @@ jalv_frontend_open(Jalv* jalv) { if (!jalv_run_custom_ui(jalv) && !jalv->opts.non_interactive) { // Primitive command prompt for setting control values - while (!zix_sem_try_wait(&jalv->done)) { + while (zix_sem_try_wait(&jalv->done)) { char line[1024]; printf("> "); if (fgets(line, sizeof(line), stdin)) { diff --git a/src/jalv_gtk.c b/src/jalv_gtk.c index 7a8d942..e89d7a6 100644 --- a/src/jalv_gtk.c +++ b/src/jalv_gtk.c @@ -21,7 +21,7 @@ #include "lv2/ui/ui.h" #include "lv2/urid/urid.h" #include "suil/suil.h" -#include "zix/common.h" +#include "zix/attributes.h" #include "zix/sem.h" LV2_DISABLE_DEPRECATION_WARNINGS diff --git a/src/state.c b/src/state.c index d8002f4..3ae7954 100644 --- a/src/state.c +++ b/src/state.c @@ -13,7 +13,7 @@ #include "lv2/core/lv2.h" #include "lv2/state/state.h" #include "lv2/urid/urid.h" -#include "zix/common.h" +#include "zix/attributes.h" #include "zix/sem.h" #include <stdbool.h> diff --git a/src/worker.c b/src/worker.c index 63df419..0dca657 100644 --- a/src/worker.c +++ b/src/worker.c @@ -5,9 +5,9 @@ #include "lv2/core/lv2.h" #include "lv2/worker/worker.h" -#include "zix/common.h" #include "zix/ring.h" #include "zix/sem.h" +#include "zix/status.h" #include "zix/thread.h" #include <stdio.h> @@ -103,7 +103,7 @@ jalv_worker_launch(JalvWorker* const worker) ZixRing* const requests = zix_ring_new(NULL, MAX_PACKET_SIZE); if (!requests) { - zix_thread_join(worker->thread, NULL); + zix_thread_join(worker->thread); zix_sem_destroy(&worker->sem); return ZIX_STATUS_NO_MEM; } @@ -156,7 +156,7 @@ jalv_worker_exit(JalvWorker* const worker) if (worker && worker->threaded) { worker->exit = true; zix_sem_post(&worker->sem); - zix_thread_join(worker->thread, NULL); + zix_thread_join(worker->thread); worker->threaded = false; } } diff --git a/src/zix/allocator.c b/src/zix/allocator.c deleted file mode 100644 index 310ef33..0000000 --- a/src/zix/allocator.c +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2011-2021 David Robillard <d@drobilla.net> -// SPDX-License-Identifier: ISC - -#include "zix/allocator.h" - -#include "zix/attributes.h" - -#include "jalv_config.h" - -#ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN 1 -# include <malloc.h> -# include <windows.h> -#endif - -#include <stdlib.h> - -ZIX_MALLOC_FUNC -static void* -zix_default_malloc(ZixAllocator* const allocator, const size_t size) -{ - (void)allocator; - return malloc(size); -} - -ZIX_MALLOC_FUNC -static void* -zix_default_calloc(ZixAllocator* const allocator, - const size_t nmemb, - const size_t size) -{ - (void)allocator; - return calloc(nmemb, size); -} - -static void* -zix_default_realloc(ZixAllocator* const allocator, - void* const ptr, - const size_t size) -{ - (void)allocator; - return realloc(ptr, size); -} - -static void -zix_default_free(ZixAllocator* const allocator, void* const ptr) -{ - (void)allocator; - free(ptr); -} - -ZIX_MALLOC_FUNC -static void* -zix_default_aligned_alloc(ZixAllocator* const allocator, - const size_t alignment, - const size_t size) -{ - (void)allocator; - -#if defined(_WIN32) - return _aligned_malloc(size, alignment); -#elif USE_POSIX_MEMALIGN - void* ptr = NULL; - const int ret = posix_memalign(&ptr, alignment, size); - return ret ? NULL : ptr; -#else - return NULL; -#endif -} - -static void -zix_default_aligned_free(ZixAllocator* const allocator, void* const ptr) -{ - (void)allocator; - -#if defined(_WIN32) - _aligned_free(ptr); -#else - free(ptr); -#endif -} - -ZixAllocator* -zix_default_allocator(void) -{ - static ZixAllocator default_allocator = { - zix_default_malloc, - zix_default_calloc, - zix_default_realloc, - zix_default_free, - zix_default_aligned_alloc, - zix_default_aligned_free, - }; - - return &default_allocator; -} diff --git a/src/zix/allocator.h b/src/zix/allocator.h deleted file mode 100644 index bcffda5..0000000 --- a/src/zix/allocator.h +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2021 David Robillard <d@drobilla.net> -// SPDX-License-Identifier: ISC - -#ifndef ZIX_ALLOCATOR_H -#define ZIX_ALLOCATOR_H - -#include "zix/attributes.h" - -#include <stddef.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** - @addtogroup zix - @{ - @name Allocator - @{ -*/ - -struct ZixAllocatorImpl; - -/** - A memory allocator. - - This object-like structure provides an interface like the standard C - functions malloc(), calloc(), realloc(), free(), and aligned_alloc(). It - contains function pointers that differ from their standard counterparts by - taking a context parameter (a pointer to this struct), which allows the user - to implement custom stateful allocators. -*/ -typedef struct ZixAllocatorImpl ZixAllocator; - -/** - General malloc-like memory allocation function. - - This works like the standard C malloc(), except has an additional handle - parameter for implementing stateful allocators without static data. -*/ -typedef void* ZIX_ALLOCATED (*ZixMallocFunc)( // - ZixAllocator* ZIX_NULLABLE allocator, - size_t size); - -/** - General calloc-like memory allocation function. - - This works like the standard C calloc(), except has an additional handle - parameter for implementing stateful allocators without static data. -*/ -typedef void* ZIX_ALLOCATED (*ZixCallocFunc)( // - ZixAllocator* ZIX_NULLABLE allocator, - size_t nmemb, - size_t size); - -/** - General realloc-like memory reallocation function. - - This works like the standard C remalloc(), except has an additional handle - parameter for implementing stateful allocators without static data. -*/ -typedef void* ZIX_ALLOCATED (*ZixReallocFunc)( // - ZixAllocator* ZIX_NULLABLE allocator, - void* ZIX_NULLABLE ptr, - size_t size); - -/** - General free-like memory deallocation function. - - This works like the standard C remalloc(), except has an additional handle - parameter for implementing stateful allocators without static data. -*/ -typedef void (*ZixFreeFunc)( // - ZixAllocator* ZIX_NULLABLE allocator, - void* ZIX_NULLABLE ptr); - -/** - General aligned_alloc-like memory deallocation function. - - This works like the standard C aligned_alloc(), except has an additional - handle parameter for implementing stateful allocators without static data. -*/ -typedef void* ZIX_ALLOCATED (*ZixAlignedAllocFunc)( // - ZixAllocator* ZIX_NULLABLE allocator, - size_t alignment, - size_t size); - -/** - General aligned memory deallocation function. - - This works like the standard C free(), but must be used to free memory - allocated with the aligned_alloc() method of the allocator. This allows - portability to systems (like Windows) that can not use the same free function - in these cases. -*/ -typedef void (*ZixAlignedFreeFunc)( // - ZixAllocator* ZIX_NULLABLE allocator, - void* ZIX_NULLABLE ptr); - -/// Definition of ZixAllocator -struct ZixAllocatorImpl { - ZixMallocFunc ZIX_NONNULL malloc; - ZixCallocFunc ZIX_NONNULL calloc; - ZixReallocFunc ZIX_NONNULL realloc; - ZixFreeFunc ZIX_NONNULL free; - ZixAlignedAllocFunc ZIX_NONNULL aligned_alloc; - ZixAlignedFreeFunc ZIX_NONNULL aligned_free; -}; - -/// Return the default allocator which simply uses the system allocator -ZIX_CONST_API -ZixAllocator* ZIX_NONNULL -zix_default_allocator(void); - -/// Convenience wrapper that defers to malloc() if allocator is null -static inline void* ZIX_ALLOCATED -zix_malloc(ZixAllocator* const ZIX_NULLABLE allocator, const size_t size) -{ - ZixAllocator* const actual = allocator ? allocator : zix_default_allocator(); - - return actual->malloc(actual, size); -} - -/// Convenience wrapper that defers to calloc() if allocator is null -static inline void* ZIX_ALLOCATED -zix_calloc(ZixAllocator* const ZIX_NULLABLE allocator, - const size_t nmemb, - const size_t size) -{ - ZixAllocator* const actual = allocator ? allocator : zix_default_allocator(); - - return actual->calloc(actual, nmemb, size); -} - -/// Convenience wrapper that defers to realloc() if allocator is null -static inline void* ZIX_ALLOCATED -zix_realloc(ZixAllocator* const ZIX_NULLABLE allocator, - void* const ZIX_NULLABLE ptr, - const size_t size) -{ - ZixAllocator* const actual = allocator ? allocator : zix_default_allocator(); - - return actual->realloc(actual, ptr, size); -} - -/// Convenience wrapper that defers to free() if allocator is null -static inline void -zix_free(ZixAllocator* const ZIX_NULLABLE allocator, - void* const ZIX_NULLABLE ptr) -{ - ZixAllocator* const actual = allocator ? allocator : zix_default_allocator(); - - actual->free(actual, ptr); -} - -/// Convenience wrapper that defers to the system allocator if allocator is null -static inline void* ZIX_ALLOCATED -zix_aligned_alloc(ZixAllocator* const ZIX_NULLABLE allocator, - const size_t alignment, - const size_t size) -{ - ZixAllocator* const actual = allocator ? allocator : zix_default_allocator(); - - return actual->aligned_alloc(actual, alignment, size); -} - -/// Convenience wrapper that defers to the system allocator if allocator is null -static inline void -zix_aligned_free(ZixAllocator* const ZIX_NULLABLE allocator, - void* const ZIX_NULLABLE ptr) -{ - ZixAllocator* const actual = allocator ? allocator : zix_default_allocator(); - - actual->aligned_free(actual, ptr); -} - -/** - @} - @} -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ZIX_ALLOCATOR_H */ diff --git a/src/zix/attributes.h b/src/zix/attributes.h deleted file mode 100644 index 602fac8..0000000 --- a/src/zix/attributes.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2021 David Robillard <d@drobilla.net> -// SPDX-License-Identifier: ISC - -#ifndef ZIX_ATTRIBUTES_H -#define ZIX_ATTRIBUTES_H - -/** - @addtogroup zix - @{ -*/ - -// ZIX_API must be used to decorate things in the public API -#ifndef ZIX_API -# if defined(_WIN32) && !defined(ZIX_STATIC) && defined(ZIX_INTERNAL) -# define ZIX_API __declspec(dllexport) -# elif defined(_WIN32) && !defined(ZIX_STATIC) -# define ZIX_API __declspec(dllimport) -# elif defined(__GNUC__) -# define ZIX_API __attribute__((visibility("default"))) -# else -# define ZIX_API -# endif -#endif - -// GCC pure/const/malloc attributes -#ifdef __GNUC__ -# define ZIX_PURE_FUNC __attribute__((pure)) -# define ZIX_CONST_FUNC __attribute__((const)) -# define ZIX_MALLOC_FUNC __attribute__((malloc)) -#else -# define ZIX_PURE_FUNC -# define ZIX_CONST_FUNC -# define ZIX_MALLOC_FUNC -#endif - -#define ZIX_PURE_API \ - ZIX_API \ - ZIX_PURE_FUNC - -#define ZIX_CONST_API \ - ZIX_API \ - ZIX_CONST_FUNC - -#define ZIX_MALLOC_API \ - ZIX_API \ - ZIX_MALLOC_FUNC - -// Printf-like format functions -#ifdef __GNUC__ -# define ZIX_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) -#else -# define ZIX_LOG_FUNC(fmt, arg1) -#endif - -// Unused parameter macro to suppresses warnings and make it impossible to use -#if defined(__cplusplus) -# define ZIX_UNUSED(name) -#elif defined(__GNUC__) -# define ZIX_UNUSED(name) name##_unused __attribute__((__unused__)) -#elif defined(_MSC_VER) -# define ZIX_UNUSED(name) __pragma(warning(suppress : 4100)) name -#else -# define ZIX_UNUSED(name) name -#endif - -// Clang nullability annotations -#if defined(__clang__) && __clang_major__ >= 7 -# define ZIX_NONNULL _Nonnull -# define ZIX_NULLABLE _Nullable -# define ZIX_ALLOCATED _Null_unspecified -#else -# define ZIX_NONNULL -# define ZIX_NULLABLE -# define ZIX_ALLOCATED -#endif - -/** - @} -*/ - -#endif /* ZIX_ATTRIBUTES_H */ diff --git a/src/zix/common.h b/src/zix/common.h deleted file mode 100644 index 5919fa9..0000000 --- a/src/zix/common.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016-2020 David Robillard <d@drobilla.net> -// SPDX-License-Identifier: ISC - -#ifndef ZIX_COMMON_H -#define ZIX_COMMON_H - -#include "zix/attributes.h" - -#include <stdbool.h> - -/** - @addtogroup zix - @{ -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - ZIX_STATUS_SUCCESS, - ZIX_STATUS_ERROR, - ZIX_STATUS_NO_MEM, - ZIX_STATUS_NOT_FOUND, - ZIX_STATUS_EXISTS, - ZIX_STATUS_BAD_ARG, - ZIX_STATUS_BAD_PERMS, - ZIX_STATUS_REACHED_END -} ZixStatus; - -/// Return a string describing a status code -ZIX_CONST_API -const char* -zix_strerror(ZixStatus status); - -/// Function for comparing two elements -typedef int (*ZixComparator)(const void* a, - const void* b, - const void* user_data); - -/// Function for testing equality of two elements -typedef bool (*ZixEqualFunc)(const void* a, const void* b); - -/// Function to destroy an element -typedef void (*ZixDestroyFunc)(void* ptr, const void* user_data); - -/** - @} -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ZIX_COMMON_H */ diff --git a/src/zix/ring.c b/src/zix/ring.c deleted file mode 100644 index d2d3195..0000000 --- a/src/zix/ring.c +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2011-2022 David Robillard <d@drobilla.net> -// SPDX-License-Identifier: ISC - -#include "zix/ring.h" -#include "zix/common.h" - -#include "jalv_config.h" - -#include <stdlib.h> -#include <string.h> - -#if USE_MLOCK -# include <sys/mman.h> -# define ZIX_MLOCK(ptr, size) mlock((ptr), (size)) -#elif defined(_WIN32) -# include <windows.h> -# define ZIX_MLOCK(ptr, size) VirtualLock((ptr), (size)) -#else -# pragma message("warning: No memory locking, possible RT violations") -# define ZIX_MLOCK(ptr, size) -#endif - -/* - Note that for simplicity, only x86 and x64 are supported with MSVC. Hopefully - stdatomic.h support arrives before anyone cares about running this code on - Windows on ARM. -*/ -#if defined(_MSC_VER) -# include <intrin.h> -#endif - -struct ZixRingImpl { - ZixAllocator* allocator; ///< User allocator - uint32_t write_head; ///< Read index into buf - uint32_t read_head; ///< Write index into buf - uint32_t size; ///< Size (capacity) in bytes - uint32_t size_mask; ///< Mask for fast modulo - char* buf; ///< Contents -}; - -static inline uint32_t -zix_atomic_load(const uint32_t* const ptr) -{ -#if defined(_MSC_VER) - const uint32_t val = *ptr; - _ReadBarrier(); - return val; -#else - return __atomic_load_n(ptr, __ATOMIC_ACQUIRE); -#endif -} - -static inline void -zix_atomic_store(uint32_t* const ptr, // NOLINT(readability-non-const-parameter) - const uint32_t val) -{ -#if defined(_MSC_VER) - _WriteBarrier(); - *ptr = val; -#else - __atomic_store_n(ptr, val, __ATOMIC_RELEASE); -#endif -} - -static inline uint32_t -next_power_of_two(uint32_t size) -{ - // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 - size--; - size |= size >> 1U; - size |= size >> 2U; - size |= size >> 4U; - size |= size >> 8U; - size |= size >> 16U; - size++; - return size; -} - -ZixRing* -zix_ring_new(ZixAllocator* const allocator, const uint32_t size) -{ - ZixRing* ring = (ZixRing*)zix_malloc(allocator, sizeof(ZixRing)); - - if (ring) { - ring->allocator = allocator; - ring->write_head = 0; - ring->read_head = 0; - ring->size = next_power_of_two(size); - ring->size_mask = ring->size - 1; - - if (!(ring->buf = (char*)zix_malloc(allocator, ring->size))) { - zix_free(allocator, ring); - return NULL; - } - } - - return ring; -} - -void -zix_ring_free(ZixRing* const ring) -{ - if (ring) { - zix_free(ring->allocator, ring->buf); - zix_free(ring->allocator, ring); - } -} - -void -zix_ring_mlock(ZixRing* const ring) -{ - ZIX_MLOCK(ring, sizeof(ZixRing)); - ZIX_MLOCK(ring->buf, ring->size); -} - -void -zix_ring_reset(ZixRing* const ring) -{ - ring->write_head = 0; - ring->read_head = 0; -} - -/* - General pattern for public thread-safe functions below: start with a single - atomic load of the "other's" index, then do whatever work, and finally end - with a single atomic store to "your" index (if it is changed). -*/ - -static inline uint32_t -read_space_internal(const ZixRing* const ring, - const uint32_t r, - const uint32_t w) -{ - return (w - r) & ring->size_mask; -} - -uint32_t -zix_ring_read_space(const ZixRing* const ring) -{ - const uint32_t w = zix_atomic_load(&ring->write_head); - - return read_space_internal(ring, ring->read_head, w); -} - -static inline uint32_t -write_space_internal(const ZixRing* const ring, - const uint32_t r, - const uint32_t w) -{ - return (r - w - 1U) & ring->size_mask; -} - -uint32_t -zix_ring_write_space(const ZixRing* const ring) -{ - const uint32_t r = zix_atomic_load(&ring->read_head); - - return write_space_internal(ring, r, ring->write_head); -} - -uint32_t -zix_ring_capacity(const ZixRing* const ring) -{ - return ring->size - 1; -} - -static inline uint32_t -peek_internal(const ZixRing* const ring, - const uint32_t r, - const uint32_t w, - const uint32_t size, - void* const dst) -{ - if (read_space_internal(ring, r, w) < size) { - return 0; - } - - if (r + size < ring->size) { - memcpy(dst, &ring->buf[r], size); - } else { - const uint32_t first_size = ring->size - r; - memcpy(dst, &ring->buf[r], first_size); - memcpy((char*)dst + first_size, &ring->buf[0], size - first_size); - } - - return size; -} - -uint32_t -zix_ring_peek(ZixRing* const ring, void* const dst, const uint32_t size) -{ - const uint32_t w = zix_atomic_load(&ring->write_head); - - return peek_internal(ring, ring->read_head, w, size, dst); -} - -uint32_t -zix_ring_read(ZixRing* const ring, void* const dst, const uint32_t size) -{ - const uint32_t w = zix_atomic_load(&ring->write_head); - const uint32_t r = ring->read_head; - if (!peek_internal(ring, r, w, size, dst)) { - return 0; - } - - zix_atomic_store(&ring->read_head, (r + size) & ring->size_mask); - return size; -} - -uint32_t -zix_ring_skip(ZixRing* const ring, const uint32_t size) -{ - const uint32_t w = zix_atomic_load(&ring->write_head); - const uint32_t r = ring->read_head; - if (read_space_internal(ring, r, w) < size) { - return 0; - } - - zix_atomic_store(&ring->read_head, (r + size) & ring->size_mask); - return size; -} - -ZixRingTransaction -zix_ring_begin_write(ZixRing* const ring) -{ - const uint32_t r = zix_atomic_load(&ring->read_head); - const uint32_t w = ring->write_head; - - const ZixRingTransaction tx = {r, w}; - return tx; -} - -ZixStatus -zix_ring_amend_write(ZixRing* const ring, - ZixRingTransaction* const tx, - const void* const src, - const uint32_t size) -{ - const uint32_t r = tx->read_head; - const uint32_t w = tx->write_head; - if (write_space_internal(ring, r, w) < size) { - return ZIX_STATUS_NO_MEM; - } - - const uint32_t end = w + size; - if (end <= ring->size) { - memcpy(&ring->buf[w], src, size); - tx->write_head = end & ring->size_mask; - } else { - const uint32_t size1 = ring->size - w; - const uint32_t size2 = size - size1; - memcpy(&ring->buf[w], src, size1); - memcpy(&ring->buf[0], (const char*)src + size1, size2); - tx->write_head = size2; - } - - return ZIX_STATUS_SUCCESS; -} - -ZixStatus -zix_ring_commit_write(ZixRing* const ring, const ZixRingTransaction* const tx) -{ - zix_atomic_store(&ring->write_head, tx->write_head); - return ZIX_STATUS_SUCCESS; -} - -uint32_t -zix_ring_write(ZixRing* const ring, const void* src, const uint32_t size) -{ - ZixRingTransaction tx = zix_ring_begin_write(ring); - - if (zix_ring_amend_write(ring, &tx, src, size) || - zix_ring_commit_write(ring, &tx)) { - return 0; - } - - return size; -} diff --git a/src/zix/ring.h b/src/zix/ring.h deleted file mode 100644 index 872f963..0000000 --- a/src/zix/ring.h +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2011-2022 David Robillard <d@drobilla.net> -// SPDX-License-Identifier: ISC - -#ifndef ZIX_RING_H -#define ZIX_RING_H - -#include "zix/allocator.h" -#include "zix/attributes.h" -#include "zix/common.h" - -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** - @addtogroup zix - @{ - @name Ring - @{ -*/ - -/** - A lock-free ring buffer. - - Thread-safe (with a few noted exceptions) for a single reader and single - writer, and realtime-safe on both ends. -*/ -typedef struct ZixRingImpl ZixRing; - -/** - A transaction for writing data in multiple parts. - - The simple zix_ring_write() can be used to write an atomic message that will - immediately be visible to the reader, but transactions allow data to be - written in several chunks before being "committed" and becoming readable. - This can be useful for things like prefixing messages with a header without - needing an allocated buffer to construct the "packet". -*/ -typedef struct { - uint32_t read_head; ///< Read head at the start of the transaction - uint32_t write_head; ///< Write head if the transaction were committed -} ZixRingTransaction; - -/** - Create a new ring. - @param size Size in bytes (note this may be rounded up). - - At most `size` - 1 bytes may be stored in the ring at once. -*/ -ZIX_MALLOC_API -ZixRing* ZIX_ALLOCATED -zix_ring_new(ZixAllocator* ZIX_NULLABLE allocator, uint32_t size); - -/// Destroy a ring -ZIX_API -void -zix_ring_free(ZixRing* ZIX_NULLABLE ring); - -/** - Lock the ring data into physical memory. - - This function is NOT thread safe or real-time safe, but it should be called - after zix_ring_new() to lock all ring memory to avoid page faults while - using the ring. -*/ -ZIX_API -void -zix_ring_mlock(ZixRing* ZIX_NONNULL ring); - -/** - Reset (empty) a ring. - - This function is NOT thread-safe, it may only be called when there is no - reader or writer. -*/ -ZIX_API -void -zix_ring_reset(ZixRing* ZIX_NONNULL ring); - -/** - Return the number of bytes of space available for reading. - - Reader only. -*/ -ZIX_PURE_API -uint32_t -zix_ring_read_space(const ZixRing* ZIX_NONNULL ring); - -/** - Return the number of bytes of space available for writing. - - Writer only. -*/ -ZIX_PURE_API -uint32_t -zix_ring_write_space(const ZixRing* ZIX_NONNULL ring); - -/** - Return the capacity (the total write space when empty). - - This function returns a constant for any given ring, and may (but usually - shouldn't) be called anywhere. -*/ -ZIX_PURE_API -uint32_t -zix_ring_capacity(const ZixRing* ZIX_NONNULL ring); - -/** - Read from the ring without advancing the read head. - - Reader only. -*/ -ZIX_API -uint32_t -zix_ring_peek(ZixRing* ZIX_NONNULL ring, void* ZIX_NONNULL dst, uint32_t size); - -/** - Read from the ring and advance the read head. - - Reader only. -*/ -ZIX_API -uint32_t -zix_ring_read(ZixRing* ZIX_NONNULL ring, void* ZIX_NONNULL dst, uint32_t size); - -/** - Skip data in the ring (advance read head without reading). - - Reader only. -*/ -ZIX_API -uint32_t -zix_ring_skip(ZixRing* ZIX_NONNULL ring, uint32_t size); - -/** - Write data to the ring. - - Writer only. -*/ -ZIX_API -uint32_t -zix_ring_write(ZixRing* ZIX_NONNULL ring, - const void* ZIX_NONNULL src, - uint32_t size); - -/** - Begin a write. - - The returned transaction is initially empty. Data can be written to it by - calling zix_ring_amend_write() one or more times, then finishing with - zix_ring_commit_write(). - - Note that the returned "transaction" is not meant to be long-lived: a call - to this function should be (more or less) immediately followed by calls to - zix_ring_amend_write() then a call to zix_ring_commit_write(). - - @param ring The ring to write data to. - @return A new empty transaction. -*/ -ZixRingTransaction -zix_ring_begin_write(ZixRing* ZIX_NONNULL ring); - -/** - Amend the current write with some data. - - The data is written immediately after the previously amended data, as if - they were written contiguously with a single write call. This data is not - visible to the reader until zix_ring_commit_write() is called. - - If any call to this function returns an error, then the transaction is - invalid and must not be committed. No cleanup is necessary for an invalid - transaction. Any bytes written while attempting the transaction will remain - in the free portion of the buffer and be overwritten by subsequent writes. - - @param ring The ring this transaction is writing to. - @param tx The active transaction, from zix_ring_begin_write(). - @param src Pointer to the data to write. - @param size Length of data to write in bytes. - @return #ZIX_STATUS_NO_MEM or #ZIX_STATUS_SUCCESS. -*/ -ZixStatus -zix_ring_amend_write(ZixRing* ZIX_NONNULL ring, - ZixRingTransaction* ZIX_NONNULL tx, - const void* ZIX_NONNULL src, - uint32_t size); - -/** - Commit the current write. - - This atomically updates the state of the ring, so that the reader will - observe the data written during the transaction. - - This function usually shouldn't be called for any transaction which - zix_ring_amend_write() returned an error for. - - @param ring The ring this transaction is writing to. - @param tx The active transaction, from zix_ring_begin_write(). - @return #ZIX_STATUS_SUCCESS. -*/ -ZixStatus -zix_ring_commit_write(ZixRing* ZIX_NONNULL ring, - const ZixRingTransaction* ZIX_NONNULL tx); - -/** - @} - @} -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ZIX_RING_H */ diff --git a/src/zix/sem.h b/src/zix/sem.h deleted file mode 100644 index 0337f03..0000000 --- a/src/zix/sem.h +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2012-2020 David Robillard <d@drobilla.net> -// SPDX-License-Identifier: ISC - -#ifndef ZIX_SEM_H -#define ZIX_SEM_H - -#include "zix/attributes.h" -#include "zix/common.h" - -#ifdef __APPLE__ -# include <mach/mach.h> -#elif defined(_WIN32) -# include <limits.h> -# include <windows.h> -#else -# include <errno.h> -# include <semaphore.h> -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdbool.h> - -/** - @addtogroup zix - @{ - @name Semaphore - @{ -*/ - -struct ZixSemImpl; - -/** - A counting semaphore. - - This is an integer that is always positive, and has two main operations: - increment (post) and decrement (wait). If a decrement can not be performed - (i.e. the value is 0) the caller will be blocked until another thread posts - and the operation can succeed. - - Semaphores can be created with any starting value, but typically this will - be 0 so the semaphore can be used as a simple signal where each post - corresponds to one wait. - - Semaphores are very efficient (much moreso than a mutex/cond pair). In - particular, at least on Linux, post is async-signal-safe, which means it - does not block and will not be interrupted. If you need to signal from - a realtime thread, this is the most appropriate primitive to use. -*/ -typedef struct ZixSemImpl ZixSem; - -/// Create and initialize `sem` to `initial` -static inline ZixStatus -zix_sem_init(ZixSem* ZIX_NONNULL sem, unsigned initial); - -/// Destroy `sem` -static inline void -zix_sem_destroy(ZixSem* ZIX_NONNULL sem); - -/** - Increment and signal any waiters. - - Realtime safe. -*/ -static inline void -zix_sem_post(ZixSem* ZIX_NONNULL sem); - -/** - Wait until count is > 0, then decrement. - - Obviously not realtime safe. -*/ -static inline ZixStatus -zix_sem_wait(ZixSem* ZIX_NONNULL sem); - -/** - Non-blocking version of wait(). - - @return true if decrement was successful (lock was acquired). -*/ -static inline bool -zix_sem_try_wait(ZixSem* ZIX_NONNULL sem); - -/** - @cond -*/ - -#ifdef __APPLE__ - -struct ZixSemImpl { - semaphore_t sem; -}; - -static inline ZixStatus -zix_sem_init(ZixSem* ZIX_NONNULL sem, unsigned val) -{ - return semaphore_create( - mach_task_self(), &sem->sem, SYNC_POLICY_FIFO, (int)val) - ? ZIX_STATUS_ERROR - : ZIX_STATUS_SUCCESS; -} - -static inline void -zix_sem_destroy(ZixSem* ZIX_NONNULL sem) -{ - semaphore_destroy(mach_task_self(), sem->sem); -} - -static inline void -zix_sem_post(ZixSem* ZIX_NONNULL sem) -{ - semaphore_signal(sem->sem); -} - -static inline ZixStatus -zix_sem_wait(ZixSem* ZIX_NONNULL sem) -{ - if (semaphore_wait(sem->sem) != KERN_SUCCESS) { - return ZIX_STATUS_ERROR; - } - return ZIX_STATUS_SUCCESS; -} - -static inline bool -zix_sem_try_wait(ZixSem* ZIX_NONNULL sem) -{ - const mach_timespec_t zero = {0, 0}; - return semaphore_timedwait(sem->sem, zero) == KERN_SUCCESS; -} - -#elif defined(_WIN32) - -struct ZixSemImpl { - HANDLE sem; -}; - -static inline ZixStatus -zix_sem_init(ZixSem* ZIX_NONNULL sem, unsigned initial) -{ - sem->sem = CreateSemaphore(NULL, (LONG)initial, LONG_MAX, NULL); - return (sem->sem) ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR; -} - -static inline void -zix_sem_destroy(ZixSem* ZIX_NONNULL sem) -{ - CloseHandle(sem->sem); -} - -static inline void -zix_sem_post(ZixSem* ZIX_NONNULL sem) -{ - ReleaseSemaphore(sem->sem, 1, NULL); -} - -static inline ZixStatus -zix_sem_wait(ZixSem* ZIX_NONNULL sem) -{ - if (WaitForSingleObject(sem->sem, INFINITE) != WAIT_OBJECT_0) { - return ZIX_STATUS_ERROR; - } - return ZIX_STATUS_SUCCESS; -} - -static inline bool -zix_sem_try_wait(ZixSem* ZIX_NONNULL sem) -{ - return WaitForSingleObject(sem->sem, 0) == WAIT_OBJECT_0; -} - -#else /* !defined(__APPLE__) && !defined(_WIN32) */ - -struct ZixSemImpl { - sem_t sem; -}; - -static inline ZixStatus -zix_sem_init(ZixSem* ZIX_NONNULL sem, unsigned initial) -{ - return sem_init(&sem->sem, 0, initial) ? ZIX_STATUS_ERROR - : ZIX_STATUS_SUCCESS; -} - -static inline void -zix_sem_destroy(ZixSem* ZIX_NONNULL sem) -{ - sem_destroy(&sem->sem); -} - -static inline void -zix_sem_post(ZixSem* ZIX_NONNULL sem) -{ - sem_post(&sem->sem); -} - -static inline ZixStatus -zix_sem_wait(ZixSem* ZIX_NONNULL sem) -{ - while (sem_wait(&sem->sem)) { - if (errno != EINTR) { - return ZIX_STATUS_ERROR; - } - /* Otherwise, interrupted, so try again. */ - } - - return ZIX_STATUS_SUCCESS; -} - -static inline bool -zix_sem_try_wait(ZixSem* ZIX_NONNULL sem) -{ - return (sem_trywait(&sem->sem) == 0); -} - -#endif - -/** - @endcond - @} - @} -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ZIX_SEM_H */ diff --git a/src/zix/thread.h b/src/zix/thread.h deleted file mode 100644 index 74bb19b..0000000 --- a/src/zix/thread.h +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2012-2020 David Robillard <d@drobilla.net> -// SPDX-License-Identifier: ISC - -#ifndef ZIX_THREAD_H -#define ZIX_THREAD_H - -#include "zix/common.h" - -#ifdef _WIN32 -# include <windows.h> -#else -# include <errno.h> -# include <pthread.h> -#endif - -#include <stddef.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** - @addtogroup zix - @{ - @name Thread - @{ -*/ - -#ifdef _WIN32 -typedef HANDLE ZixThread; -#else -typedef pthread_t ZixThread; -#endif - -/** - Initialize `thread` to a new thread. - - The thread will immediately be launched, calling `function` with `arg` - as the only parameter. -*/ -static inline ZixStatus -zix_thread_create(ZixThread* thread, - size_t stack_size, - void* (*function)(void*), - void* arg); - -/// Join `thread` (block until `thread` exits) -static inline ZixStatus -zix_thread_join(ZixThread thread, void** retval); - -#ifdef _WIN32 - -static inline ZixStatus -zix_thread_create(ZixThread* thread, - size_t stack_size, - void* (*function)(void*), - void* arg) -{ - *thread = CreateThread( - NULL, stack_size, (LPTHREAD_START_ROUTINE)function, arg, 0, NULL); - return *thread ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR; -} - -static inline ZixStatus -zix_thread_join(ZixThread thread, void** retval) -{ - (void)retval; - - return WaitForSingleObject(thread, INFINITE) ? ZIX_STATUS_SUCCESS - : ZIX_STATUS_ERROR; -} - -#else /* !defined(_WIN32) */ - -static inline ZixStatus -zix_thread_create(ZixThread* thread, - size_t stack_size, - void* (*function)(void*), - void* arg) -{ - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, stack_size); - - const int ret = pthread_create(thread, NULL, function, arg); - pthread_attr_destroy(&attr); - - switch (ret) { - case EAGAIN: - return ZIX_STATUS_NO_MEM; - case EINVAL: - return ZIX_STATUS_BAD_ARG; - case EPERM: - return ZIX_STATUS_BAD_PERMS; - } - - return ret ? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS; -} - -static inline ZixStatus -zix_thread_join(ZixThread thread, void** retval) -{ - return pthread_join(thread, retval) ? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS; -} - -#endif - -/** - @} - @} -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ZIX_THREAD_H */ diff --git a/subprojects/zix.wrap b/subprojects/zix.wrap new file mode 100644 index 0000000..de5c5b9 --- /dev/null +++ b/subprojects/zix.wrap @@ -0,0 +1,8 @@ +# Copyright 2022 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +[wrap-git] +url = https://gitlab.com/drobilla/zix.git +push-url = ssh://git@gitlab.com:drobilla/zix.git +revision = master +depth = 1 diff --git a/test/meson.build b/test/meson.build index 7036cd1..a4c4571 100644 --- a/test/meson.build +++ b/test/meson.build @@ -35,5 +35,6 @@ test( 'test_symap', files('../src/symap.c'), c_args: ['-DSYMAP_STANDALONE'], + dependencies: [zix_dep], ), ) |