From 2127aeb544a4ace1363de1127577a409b048251c Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 18 Jan 2026 19:48:12 +0100 Subject: [PATCH 1/8] gh-769: Add libuv dep, update ci workflows and add smoke test --- .devcontainer/Containerfile | 1 + .github/workflows/macos.yml | 2 +- .github/workflows/ubuntu.yml | 1 + cmake/Modules/Findlibuv.cmake | 61 ++++++++++++++++++ conanfile.py | 4 ++ misc/experimental/CMakeLists.txt | 1 + misc/experimental/libuv/CMakeLists.txt | 31 +++++++++ .../libuv/src/libuv_smoke_test.cc | 64 +++++++++++++++++++ 8 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 cmake/Modules/Findlibuv.cmake create mode 100644 misc/experimental/libuv/CMakeLists.txt create mode 100644 misc/experimental/libuv/src/libuv_smoke_test.cc diff --git a/.devcontainer/Containerfile b/.devcontainer/Containerfile index 622f1fd2b..cc2b2f8ca 100644 --- a/.devcontainer/Containerfile +++ b/.devcontainer/Containerfile @@ -68,6 +68,7 @@ RUN DEBIAN_FRONTEND="noninteractive" sudo apt-get update && \ libjansson-dev \ libxml2-dev \ libzip-dev \ + libuv1-dev \ rapidjson-dev \ uuid-dev && \ sudo apt-get clean diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index eceb860b5..f8279ae81 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -80,7 +80,7 @@ jobs: uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c #v3.3.0 - name: Install dependencies run: | - brew install lcov jansson rapidjson libzip ccache ninja openssl@1.1 google-benchmark + brew install lcov jansson rapidjson libzip ccache ninja openssl@1.1 google-benchmark libuv - name: Prepare ccache timestamp id: ccache_cache_timestamp run: | diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index dc0964f4a..f2a0e5147 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -123,6 +123,7 @@ jobs: libjansson-dev \ libcurl4-openssl-dev \ libbenchmark-dev \ + libuv1-dev \ default-jdk \ cmake \ libffi-dev \ diff --git a/cmake/Modules/Findlibuv.cmake b/cmake/Modules/Findlibuv.cmake new file mode 100644 index 000000000..4c71e79f6 --- /dev/null +++ b/cmake/Modules/Findlibuv.cmake @@ -0,0 +1,61 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# - Try to find libuv +# Once done this will define +# libuv_FOUND - System has libuv +# LIBUV_INCLUDE_DIR - The libuv include directory +# LIBUV_LIBRARY - The libuv library +# uv - Imported target for libuv + +find_package(libuv CONFIG QUIET) + +if (NOT libuv_FOUND) + find_package(PkgConfig QUIET) + if (PkgConfig_FOUND) + pkg_check_modules(LIBUV QUIET libuv) + endif () +endif () + +if (NOT libuv_FOUND) + find_path(LIBUV_INCLUDE_DIR + NAMES uv.h + HINTS ${LIBUV_INCLUDEDIR} ${LIBUV_INCLUDE_DIRS} + ) + + find_library(LIBUV_LIBRARY + NAMES uv libuv + HINTS ${LIBUV_LIBDIR} ${LIBUV_LIBRARY_DIRS} + ) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(libuv DEFAULT_MSG LIBUV_LIBRARY LIBUV_INCLUDE_DIR) + mark_as_advanced(LIBUV_INCLUDE_DIR LIBUV_LIBRARY) +endif () + +if (libuv_FOUND AND NOT TARGET libuv::uv AND TARGET libuv::libuv) + #Note: libuv cmake config possible defines libuv::libuv target + # and conan libuv package defines uv target + # so create an alias target uv for consistency + add_library(libuv::uv ALIAS libuv::libuv) +elseif (libuv_FOUND AND NOT TARGET libuv::uv AND LIBUV_LIBRARY AND LIBUV_INCLUDE_DIR) + add_library(libuv::uv SHARED IMPORTED) + set_target_properties(libuv::uv PROPERTIES + IMPORTED_LOCATION "${LIBUV_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${LIBUV_INCLUDE_DIR}" + ) +endif () diff --git a/conanfile.py b/conanfile.py index bb1c63907..bf4925354 100644 --- a/conanfile.py +++ b/conanfile.py @@ -336,6 +336,8 @@ def configure(self): self.options['mosquitto'].shared = True if self.options.enable_testing: self.options['mosquitto'].broker = True + if self.options.build_experimental: + self.options['libuv'].shared = True def requirements(self): if self.options.build_utils: @@ -370,6 +372,8 @@ def requirements(self): self.requires("zlib/1.3.1", override=True) if self.options.build_event_admin_remote_provider_mqtt: self.requires("mosquitto/[>=2.0.3 <3.0.0]") + if self.options.build_experimental: + self.requires("libuv/[>=1.49.2 <2.0.0]") self.validate() def generate(self): diff --git a/misc/experimental/CMakeLists.txt b/misc/experimental/CMakeLists.txt index f4de02bf2..51307cb0a 100644 --- a/misc/experimental/CMakeLists.txt +++ b/misc/experimental/CMakeLists.txt @@ -18,5 +18,6 @@ celix_subproject(EXPERIMENTAL "Options to enable building the experimental - non stable - bundles/libraries. " OFF) if (EXPERIMENTAL) add_subdirectory(bundles) + add_subdirectory(libuv) add_subdirectory(rust) endif () diff --git a/misc/experimental/libuv/CMakeLists.txt b/misc/experimental/libuv/CMakeLists.txt new file mode 100644 index 000000000..02b35ecf7 --- /dev/null +++ b/misc/experimental/libuv/CMakeLists.txt @@ -0,0 +1,31 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +find_package(libuv REQUIRED) + +if (NOT TARGET libuv::uv AND TARGET uv) + #Note: conan libuv package 1.49.2 defines uv target, but 1.51.0 defines lubuv::uv target + add_library(libuv::uv ALIAS uv) +endif () + +if (ENABLE_TESTING) + add_executable(libuv_smoke_test + src/libuv_smoke_test.cc + ) + target_link_libraries(libuv_smoke_test PRIVATE libuv::uv GTest::gtest GTest::gtest_main) + add_test(NAME libuv_smoke_test COMMAND libuv_smoke_test) +endif () diff --git a/misc/experimental/libuv/src/libuv_smoke_test.cc b/misc/experimental/libuv/src/libuv_smoke_test.cc new file mode 100644 index 000000000..820d7d0c1 --- /dev/null +++ b/misc/experimental/libuv/src/libuv_smoke_test.cc @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include + +TEST(LibuvSmokeTest, CanInitAndCloseLoopTest) { + uv_loop_t loop; + EXPECT_EQ(0, uv_loop_init(&loop)); + EXPECT_EQ(0, uv_loop_close(&loop)); +} + +namespace { +struct ThreadState { + uv_mutex_t mutex; + uv_cond_t cond; + bool ready; +}; + +void threadMain(void* data) { + auto* state = static_cast(data); + uv_mutex_lock(&state->mutex); + state->ready = true; + uv_cond_signal(&state->cond); + uv_mutex_unlock(&state->mutex); +} +} // namespace + +TEST(LibuvSmokeTest, CanUseThreadMutexAndConditionTest) { + ThreadState state{}; + state.ready = false; + + ASSERT_EQ(0, uv_mutex_init(&state.mutex)); + ASSERT_EQ(0, uv_cond_init(&state.cond)); + + uv_thread_t thread; + ASSERT_EQ(0, uv_thread_create(&thread, threadMain, &state)); + + uv_mutex_lock(&state.mutex); + while (!state.ready) { + uv_cond_wait(&state.cond, &state.mutex); + } + uv_mutex_unlock(&state.mutex); + + EXPECT_EQ(0, uv_thread_join(&thread)); + uv_cond_destroy(&state.cond); + uv_mutex_destroy(&state.mutex); +} From e2d3ceee194a4e62269bc79f0882fcb9828131a0 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 18 Jan 2026 20:20:35 +0100 Subject: [PATCH 2/8] gh-769: Add celix_uv_cleanup.h --- libs/utils/CMakeLists.txt | 10 +- libs/utils/gtest/CMakeLists.txt | 6 +- libs/utils/gtest/src/UvThreadsTestSuite.cc | 120 ++++++++++++ libs/utils/include/celix_uv_cleanup.h | 181 ++++++++++++++++++ misc/experimental/CMakeLists.txt | 1 - misc/experimental/libuv/CMakeLists.txt | 31 --- .../libuv/src/libuv_smoke_test.cc | 64 ------- 7 files changed, 314 insertions(+), 99 deletions(-) create mode 100644 libs/utils/gtest/src/UvThreadsTestSuite.cc create mode 100644 libs/utils/include/celix_uv_cleanup.h delete mode 100644 misc/experimental/libuv/CMakeLists.txt delete mode 100644 misc/experimental/libuv/src/libuv_smoke_test.cc diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt index e28317b49..bbb7474a1 100644 --- a/libs/utils/CMakeLists.txt +++ b/libs/utils/CMakeLists.txt @@ -18,7 +18,13 @@ celix_subproject(UTILS "Option to enable building the Utilities library" ON) if (UTILS) find_package(libzip REQUIRED) - find_package(jansson REQUIRED) #TODO add jansson dep info to build (conan) and documentation info + find_package(jansson REQUIRED) + find_package(libuv REQUIRED) + + if (NOT TARGET libuv::uv AND TARGET uv) + #Note: conan libuv package 1.49.2 defines uv target, but 1.51.0 defines libuv::uv target + add_library(libuv::uv ALIAS uv) + endif () set(MEMSTREAM_SOURCES ) set(MEMSTREAM_INCLUDES ) @@ -46,7 +52,7 @@ if (UTILS) ${MEMSTREAM_SOURCES} ) set(UTILS_PRIVATE_DEPS libzip::zip jansson::jansson) - set(UTILS_PUBLIC_DEPS) + set(UTILS_PUBLIC_DEPS libuv::uv) add_library(utils SHARED ${UTILS_SRC}) diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt index 4a25f7d41..c7cf68fcf 100644 --- a/libs/utils/gtest/CMakeLists.txt +++ b/libs/utils/gtest/CMakeLists.txt @@ -35,6 +35,7 @@ add_executable(test_utils src/VersionTestSuite.cc src/ErrTestSuite.cc src/ThreadsTestSuite.cc + src/UvThreadsTestSuite.cc src/CelixErrnoTestSuite.cc src/CelixUtilsAutoCleanupTestSuite.cc src/ArrayListTestSuite.cc @@ -42,7 +43,7 @@ add_executable(test_utils src/CxxExceptionsTestSuite.cc ) -target_link_libraries(test_utils PRIVATE utils_cut Celix::utils GTest::gtest GTest::gtest_main libzip::zip) +target_link_libraries(test_utils PRIVATE utils_cut Celix::utils GTest::gtest GTest::gtest_main libzip::zip libuv::uv) target_include_directories(test_utils PRIVATE ../src) #for version_private (needs refactoring of test) celix_deprecated_utils_headers(test_utils) @@ -153,7 +154,10 @@ if (EI_TESTS) Celix::fts_ei utils_cut Celix::utils_ei + libuv::uv + -Wl,--whole-archive Celix::ifaddrs_ei + -Wl,--no-whole-archive Celix::threads_ei Celix::malloc_ei Celix::asprintf_ei diff --git a/libs/utils/gtest/src/UvThreadsTestSuite.cc b/libs/utils/gtest/src/UvThreadsTestSuite.cc new file mode 100644 index 000000000..0ae40bfaf --- /dev/null +++ b/libs/utils/gtest/src/UvThreadsTestSuite.cc @@ -0,0 +1,120 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "celix_uv_cleanup.h" + +#include +#include + +class UvThreadsTestSuite : public ::testing::Test { +}; + +static void uvThreadIncrement(void* data) { + auto* counter = static_cast*>(data); + counter->fetch_add(1); +} + +TEST_F(UvThreadsTestSuite, ThreadAutoCleanupTest) { + std::atomic counter{0}; + { + celix_auto(uv_thread_t) thread; + ASSERT_EQ(0, uv_thread_create(&thread, uvThreadIncrement, &counter)); + } //thread out of scope -> join + EXPECT_EQ(1, counter.load()); +} + +TEST_F(UvThreadsTestSuite, MutexGuardTest) { + uv_mutex_t mutex; + ASSERT_EQ(0, uv_mutex_init(&mutex)); + celix_autoptr(uv_mutex_t) mutexCleanup = &mutex; + + { + celix_auto(celix_uv_mutex_lock_guard_t) guard = celixUvMutexLockGuard_init(&mutex); + EXPECT_NE(0, uv_mutex_trylock(&mutex)); + } //guard out of scope -> unlock + + EXPECT_EQ(0, uv_mutex_trylock(&mutex)); + uv_mutex_unlock(&mutex); +} + +TEST_F(UvThreadsTestSuite, MutexStealTest) { + uv_mutex_t mutex; + ASSERT_EQ(0, uv_mutex_init(&mutex)); + celix_autoptr(uv_mutex_t) mutexCleanup = &mutex; + celix_steal_ptr(mutexCleanup); + uv_mutex_destroy(&mutex); +} + +TEST_F(UvThreadsTestSuite, RwlockGuardTest) { + uv_rwlock_t lock; + ASSERT_EQ(0, uv_rwlock_init(&lock)); + celix_autoptr(uv_rwlock_t) lockCleanup = &lock; + + { + celix_auto(celix_uv_rwlock_wlock_guard_t) guard = celixUvRwlockWlockGuard_init(&lock); + EXPECT_NE(0, uv_rwlock_tryrdlock(&lock)); + EXPECT_NE(0, uv_rwlock_trywrlock(&lock)); + } //guard out of scope -> unlock + + { + celix_auto(celix_uv_rwlock_rlock_guard_t) guard = celixUvRwlockRlockGuard_init(&lock); + + EXPECT_EQ(0, uv_rwlock_tryrdlock(&lock)); + uv_rwlock_rdunlock(&lock); + + EXPECT_NE(0, uv_rwlock_trywrlock(&lock)); + } //guard out of scope -> unlock + + EXPECT_EQ(0, uv_rwlock_trywrlock(&lock)); + uv_rwlock_wrunlock(&lock); +} + +TEST_F(UvThreadsTestSuite, RwlockStealdTest) { + uv_rwlock_t lock; + ASSERT_EQ(0, uv_rwlock_init(&lock)); + celix_autoptr(uv_rwlock_t) lockCleanup = &lock; + celix_steal_ptr(lockCleanup); + uv_rwlock_destroy(&lock); +} + +TEST_F(UvThreadsTestSuite, ConditionAutoCleanupTest) { + uv_cond_t cond; + ASSERT_EQ(0, uv_cond_init(&cond)); + celix_autoptr(uv_cond_t) condCleanup = &cond; +} + +TEST_F(UvThreadsTestSuite, ConditionStealTest) { + uv_cond_t cond; + ASSERT_EQ(0, uv_cond_init(&cond)); + celix_autoptr(uv_cond_t) condCleanup = &cond; + celix_steal_ptr(condCleanup); + uv_cond_destroy(&cond); +} + +TEST_F(UvThreadsTestSuite, LocalThreadStorageKeyAutoCleanupTest) { + uv_key_t key; + ASSERT_EQ(0, uv_key_create(&key)); + celix_autoptr(uv_key_t) keyCleanup = &key; +} + +TEST_F(UvThreadsTestSuite, LocalThreadStorageKeyStealTest) { + uv_key_t key; + ASSERT_EQ(0, uv_key_create(&key)); + celix_autoptr(uv_key_t) keyCleanup = &key; + celix_steal_ptr(keyCleanup); + uv_key_delete(&key); +} diff --git a/libs/utils/include/celix_uv_cleanup.h b/libs/utils/include/celix_uv_cleanup.h new file mode 100644 index 000000000..a4ced5dc1 --- /dev/null +++ b/libs/utils/include/celix_uv_cleanup.h @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef CELIX_UV_CLEANUP_H +#define CELIX_UV_CLEANUP_H + +#include + +#include "celix_cleanup.h" + +#ifdef __cplusplus +extern "C" { +#endif + +CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(uv_thread_t, uv_thread_join) +CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(uv_mutex_t, uv_mutex_destroy) +CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(uv_rwlock_t, uv_rwlock_destroy) +CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(uv_cond_t, uv_cond_destroy) +CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(uv_key_t, uv_key_delete) + +/** + * @brief Lock guard for uv mutexes. + */ +typedef struct celix_uv_mutex_lock_guard { + uv_mutex_t* mutex; +} celix_uv_mutex_lock_guard_t; + +/** + * @brief Initialize a lock guard for @a mutex. + * + * Lock a mutex and return a celix_uv_mutex_lock_guard_t. + * Unlock with celixUvMutexLockGuard_deinit(). Using uv_mutex_lock() on a mutex + * while a celix_uv_mutex_lock_guard_t exists can lead to undefined behaviour. + * + * No allocation is performed, it is equivalent to a uv_mutex_lock() call. + * This is intended to be used with celix_auto(). + * + * @param mutex A mutex to lock. + * @return An initialized lock guard to be used with celix_auto(). + */ +static CELIX_UNUSED inline celix_uv_mutex_lock_guard_t celixUvMutexLockGuard_init(uv_mutex_t* mutex) { + celix_uv_mutex_lock_guard_t guard; + guard.mutex = mutex; + uv_mutex_lock(mutex); + return guard; +} + +/** + * @brief Deinitialize a lock guard for a mutex. + * + * Unlock the mutex of a guard. + * No memory is freed, it is equivalent to a uv_mutex_unlock() call. + * + * @param guard A celix_uv_mutex_lock_guard_t. + */ +static CELIX_UNUSED inline void celixUvMutexLockGuard_deinit(celix_uv_mutex_lock_guard_t* guard) { + if (guard->mutex) { + uv_mutex_unlock(guard->mutex); + guard->mutex = NULL; + } +} + +CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_mutex_lock_guard_t, celixUvMutexLockGuard_deinit) + +/** + * @brief A RAII style write lock guard for uv_rwlock_t. + * + * The lock is obtained in the constructor and released in the destructor. + * This is intended to be used with celix_auto(). + */ +typedef struct celix_uv_rwlock_wlock_guard { + uv_rwlock_t* lock; +} celix_uv_rwlock_wlock_guard_t; + +/** + * @brief Initialize a write lock guard for @a lock. + * + * Obtain a write lock on @a lock and return a celix_uv_rwlock_wlock_guard_t. + * Unlock with celixUvRwlockWlockGuard_deinit(). Using uv_rwlock_wrunlock() + * on @lock while a celix_uv_rwlock_wlock_guard_t exists can lead to undefined behaviour. + * + * No allocation is performed, it is equivalent to a uv_rwlock_wrlock() call. + * This is intended to be used with celix_auto(). + * + * @param lock A read-write lock to lock. + * @return An initialized write lock guard to be used with celix_auto(). + */ +static CELIX_UNUSED inline celix_uv_rwlock_wlock_guard_t celixUvRwlockWlockGuard_init(uv_rwlock_t* lock) { + celix_uv_rwlock_wlock_guard_t guard; + guard.lock = lock; + uv_rwlock_wrlock(lock); + return guard; +} + +/** + * @brief Deinitialize a write lock guard. + * + * Release a write lock on the read-write lock contained in @a guard. + * See celixUvRwlockWlockGuard_init() for details. + * No memory is freed, it is equivalent to a uv_rwlock_wrunlock() call. + * + * @param guard A celix_uv_rwlock_wlock_guard_t. + */ +static CELIX_UNUSED inline void celixUvRwlockWlockGuard_deinit(celix_uv_rwlock_wlock_guard_t* guard) { + if (guard->lock) { + uv_rwlock_wrunlock(guard->lock); + guard->lock = NULL; + } +} + +CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_rwlock_wlock_guard_t, celixUvRwlockWlockGuard_deinit) + +/** + * @brief A RAII style read lock guard for uv_rwlock_t. + * + * The lock is obtained in the constructor and released in the destructor. + * This is intended to be used with celix_auto(). + */ +typedef struct celix_uv_rwlock_rlock_guard { + uv_rwlock_t* lock; +} celix_uv_rwlock_rlock_guard_t; + +/** + * @brief Initialize a read lock guard for a lock. + * + * Obtain a read lock on a lock and return a celix_uv_rwlock_rlock_guard_t. + * Unlock with celixUvRwlockRlockGuard_deinit(). Using uv_rwlock_rdunlock() + * on @lock while a celix_uv_rwlock_rlock_guard_t exists can lead to undefined behaviour. + * + * No allocation is performed, it is equivalent to a uv_rwlock_rdlock() call. + * This is intended to be used with celix_auto(). + * + * @param lock A read-write lock to lock. + * @return A guard to be used with celix_auto(). + */ +static CELIX_UNUSED inline celix_uv_rwlock_rlock_guard_t celixUvRwlockRlockGuard_init(uv_rwlock_t* lock) { + celix_uv_rwlock_rlock_guard_t guard; + guard.lock = lock; + uv_rwlock_rdlock(lock); + return guard; +} + +/** + * @brief Deinitialize a read lock guard. + * + * Release a read lock on the read-write lock contained in a guard. + * See celixUvRwlockRlockGuard_init() for details. + * No memory is freed, it is equivalent to a uv_rwlock_rdunlock() call. + * + * @param guard A celix_uv_rwlock_rlock_guard_t. + */ +static CELIX_UNUSED inline void celixUvRwlockRlockGuard_deinit(celix_uv_rwlock_rlock_guard_t* guard) { + if (guard->lock) { + uv_rwlock_rdunlock(guard->lock); + guard->lock = NULL; + } +} + +CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_rwlock_rlock_guard_t, celixUvRwlockRlockGuard_deinit) + +#ifdef __cplusplus +} +#endif + +#endif /* CELIX_UV_CLEANUP_H */ diff --git a/misc/experimental/CMakeLists.txt b/misc/experimental/CMakeLists.txt index 51307cb0a..f4de02bf2 100644 --- a/misc/experimental/CMakeLists.txt +++ b/misc/experimental/CMakeLists.txt @@ -18,6 +18,5 @@ celix_subproject(EXPERIMENTAL "Options to enable building the experimental - non stable - bundles/libraries. " OFF) if (EXPERIMENTAL) add_subdirectory(bundles) - add_subdirectory(libuv) add_subdirectory(rust) endif () diff --git a/misc/experimental/libuv/CMakeLists.txt b/misc/experimental/libuv/CMakeLists.txt deleted file mode 100644 index 02b35ecf7..000000000 --- a/misc/experimental/libuv/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -find_package(libuv REQUIRED) - -if (NOT TARGET libuv::uv AND TARGET uv) - #Note: conan libuv package 1.49.2 defines uv target, but 1.51.0 defines lubuv::uv target - add_library(libuv::uv ALIAS uv) -endif () - -if (ENABLE_TESTING) - add_executable(libuv_smoke_test - src/libuv_smoke_test.cc - ) - target_link_libraries(libuv_smoke_test PRIVATE libuv::uv GTest::gtest GTest::gtest_main) - add_test(NAME libuv_smoke_test COMMAND libuv_smoke_test) -endif () diff --git a/misc/experimental/libuv/src/libuv_smoke_test.cc b/misc/experimental/libuv/src/libuv_smoke_test.cc deleted file mode 100644 index 820d7d0c1..000000000 --- a/misc/experimental/libuv/src/libuv_smoke_test.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include - -TEST(LibuvSmokeTest, CanInitAndCloseLoopTest) { - uv_loop_t loop; - EXPECT_EQ(0, uv_loop_init(&loop)); - EXPECT_EQ(0, uv_loop_close(&loop)); -} - -namespace { -struct ThreadState { - uv_mutex_t mutex; - uv_cond_t cond; - bool ready; -}; - -void threadMain(void* data) { - auto* state = static_cast(data); - uv_mutex_lock(&state->mutex); - state->ready = true; - uv_cond_signal(&state->cond); - uv_mutex_unlock(&state->mutex); -} -} // namespace - -TEST(LibuvSmokeTest, CanUseThreadMutexAndConditionTest) { - ThreadState state{}; - state.ready = false; - - ASSERT_EQ(0, uv_mutex_init(&state.mutex)); - ASSERT_EQ(0, uv_cond_init(&state.cond)); - - uv_thread_t thread; - ASSERT_EQ(0, uv_thread_create(&thread, threadMain, &state)); - - uv_mutex_lock(&state.mutex); - while (!state.ready) { - uv_cond_wait(&state.cond, &state.mutex); - } - uv_mutex_unlock(&state.mutex); - - EXPECT_EQ(0, uv_thread_join(&thread)); - uv_cond_destroy(&state.cond); - uv_mutex_destroy(&state.mutex); -} From 1b0b0934a4f562230f6b7ea4d586ee75b119db77 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 18 Jan 2026 20:24:05 +0100 Subject: [PATCH 3/8] gh-769: Update conan libuv dep to build_utils --- conanfile.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/conanfile.py b/conanfile.py index bf4925354..f5c5c6ecd 100644 --- a/conanfile.py +++ b/conanfile.py @@ -309,6 +309,7 @@ def configure(self): # https://github.com/conan-io/conan/issues/14528#issuecomment-1685344080 if self.options.build_utils: self.options['libzip'].shared = True + self.options['libuv'].shared = True if self.options.build_framework: self.options['util-linux-libuuid'].shared = True if ((self.options.build_framework and self.options.framework_curlinit) @@ -336,12 +337,11 @@ def configure(self): self.options['mosquitto'].shared = True if self.options.enable_testing: self.options['mosquitto'].broker = True - if self.options.build_experimental: - self.options['libuv'].shared = True def requirements(self): if self.options.build_utils: self.requires("libzip/[>=1.7.3 <2.0.0]") + self.requires("libuv/[>=1.49.2 <2.0.0]") if self.options.build_framework: self.requires("util-linux-libuuid/[>=2.39 <3.0.0]") if self.settings.os == "Macos": @@ -372,8 +372,6 @@ def requirements(self): self.requires("zlib/1.3.1", override=True) if self.options.build_event_admin_remote_provider_mqtt: self.requires("mosquitto/[>=2.0.3 <3.0.0]") - if self.options.build_experimental: - self.requires("libuv/[>=1.49.2 <2.0.0]") self.validate() def generate(self): From e0af03093c28a468765d685bb3e4333b99ca7170 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 18 Jan 2026 21:54:04 +0100 Subject: [PATCH 4/8] Exclude try locks on macos rwlock test --- libs/utils/gtest/src/UvThreadsTestSuite.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libs/utils/gtest/src/UvThreadsTestSuite.cc b/libs/utils/gtest/src/UvThreadsTestSuite.cc index 0ae40bfaf..bfc4cbd17 100644 --- a/libs/utils/gtest/src/UvThreadsTestSuite.cc +++ b/libs/utils/gtest/src/UvThreadsTestSuite.cc @@ -47,7 +47,7 @@ TEST_F(UvThreadsTestSuite, MutexGuardTest) { EXPECT_NE(0, uv_mutex_trylock(&mutex)); } //guard out of scope -> unlock - EXPECT_EQ(0, uv_mutex_trylock(&mutex)); + ASSERT_EQ(0, uv_mutex_trylock(&mutex)); uv_mutex_unlock(&mutex); } @@ -64,22 +64,24 @@ TEST_F(UvThreadsTestSuite, RwlockGuardTest) { ASSERT_EQ(0, uv_rwlock_init(&lock)); celix_autoptr(uv_rwlock_t) lockCleanup = &lock; +#ifndef __APPLE__ //On MacOs uv_rwlock_tryrdlock and uv_rwlock_trywrlock on write locked lock results in SIGABRT { - celix_auto(celix_uv_rwlock_wlock_guard_t) guard = celixUvRwlockWlockGuard_init(&lock); + celix_auto(celix_uv_rwlock_wlock_guard_t) writeGuard = celixUvRwlockWlockGuard_init(&lock); EXPECT_NE(0, uv_rwlock_tryrdlock(&lock)); EXPECT_NE(0, uv_rwlock_trywrlock(&lock)); - } //guard out of scope -> unlock + } //guard out of scope -> unlock write lock +#endif { - celix_auto(celix_uv_rwlock_rlock_guard_t) guard = celixUvRwlockRlockGuard_init(&lock); + celix_auto(celix_uv_rwlock_rlock_guard_t) readGuard = celixUvRwlockRlockGuard_init(&lock); EXPECT_EQ(0, uv_rwlock_tryrdlock(&lock)); uv_rwlock_rdunlock(&lock); EXPECT_NE(0, uv_rwlock_trywrlock(&lock)); - } //guard out of scope -> unlock + } //guard out of scope -> unlock read lock - EXPECT_EQ(0, uv_rwlock_trywrlock(&lock)); + ASSERT_EQ(0, uv_rwlock_trywrlock(&lock)); uv_rwlock_wrunlock(&lock); } From feb9d8ec82c0584df97799bf225604a5d07ce74f Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 18 Jan 2026 22:26:02 +0100 Subject: [PATCH 5/8] Remove libuv linkng from ei tests --- libs/utils/gtest/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt index c7cf68fcf..84fe3a4c2 100644 --- a/libs/utils/gtest/CMakeLists.txt +++ b/libs/utils/gtest/CMakeLists.txt @@ -154,10 +154,7 @@ if (EI_TESTS) Celix::fts_ei utils_cut Celix::utils_ei - libuv::uv - -Wl,--whole-archive Celix::ifaddrs_ei - -Wl,--no-whole-archive Celix::threads_ei Celix::malloc_ei Celix::asprintf_ei From 23a3408a6f9ebdd725e9a31834b2f0c6aeeb8c9a Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Mon, 19 Jan 2026 19:55:03 +0100 Subject: [PATCH 6/8] gh-769: Move trylock test for rwlock to in sep thread --- libs/utils/gtest/src/UvThreadsTestSuite.cc | 28 +++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/libs/utils/gtest/src/UvThreadsTestSuite.cc b/libs/utils/gtest/src/UvThreadsTestSuite.cc index bfc4cbd17..2e5d65015 100644 --- a/libs/utils/gtest/src/UvThreadsTestSuite.cc +++ b/libs/utils/gtest/src/UvThreadsTestSuite.cc @@ -59,26 +59,36 @@ TEST_F(UvThreadsTestSuite, MutexStealTest) { uv_mutex_destroy(&mutex); } +static void uvThreadTryLocksForWriteLock(void* data) { + auto* lock = static_cast(data); + EXPECT_NE(0, uv_rwlock_tryrdlock(lock)); + EXPECT_NE(0, uv_rwlock_trywrlock(lock)); +} + +static void uvThreadTryLocksForReadLock(void* data) { + auto* lock = static_cast(data); + EXPECT_NE(0, uv_rwlock_trywrlock(lock)); + EXPECT_EQ(0, uv_rwlock_tryrdlock(lock)); //additional read lock on read lock should succeed + uv_rwlock_rdunlock(lock); +} + TEST_F(UvThreadsTestSuite, RwlockGuardTest) { uv_rwlock_t lock; ASSERT_EQ(0, uv_rwlock_init(&lock)); celix_autoptr(uv_rwlock_t) lockCleanup = &lock; -#ifndef __APPLE__ //On MacOs uv_rwlock_tryrdlock and uv_rwlock_trywrlock on write locked lock results in SIGABRT { celix_auto(celix_uv_rwlock_wlock_guard_t) writeGuard = celixUvRwlockWlockGuard_init(&lock); - EXPECT_NE(0, uv_rwlock_tryrdlock(&lock)); - EXPECT_NE(0, uv_rwlock_trywrlock(&lock)); + uv_thread_t thread; + ASSERT_EQ(0, uv_thread_create(&thread, uvThreadTryLocksForWriteLock, &lock)); + EXPECT_EQ(0, uv_thread_join(&thread)); } //guard out of scope -> unlock write lock -#endif { celix_auto(celix_uv_rwlock_rlock_guard_t) readGuard = celixUvRwlockRlockGuard_init(&lock); - - EXPECT_EQ(0, uv_rwlock_tryrdlock(&lock)); - uv_rwlock_rdunlock(&lock); - - EXPECT_NE(0, uv_rwlock_trywrlock(&lock)); + uv_thread_t thread; + ASSERT_EQ(0, uv_thread_create(&thread, uvThreadTryLocksForReadLock, &lock)); + EXPECT_EQ(0, uv_thread_join(&thread)); } //guard out of scope -> unlock read lock ASSERT_EQ(0, uv_rwlock_trywrlock(&lock)); From 5ef11d9375d9a55d7e3117d3ac8d643691b420f6 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Mon, 19 Jan 2026 20:22:14 +0100 Subject: [PATCH 7/8] gh-769: Move trylock test for mutex to a sep thread --- libs/utils/gtest/src/UvThreadsTestSuite.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/utils/gtest/src/UvThreadsTestSuite.cc b/libs/utils/gtest/src/UvThreadsTestSuite.cc index 2e5d65015..25879c1ef 100644 --- a/libs/utils/gtest/src/UvThreadsTestSuite.cc +++ b/libs/utils/gtest/src/UvThreadsTestSuite.cc @@ -37,6 +37,11 @@ TEST_F(UvThreadsTestSuite, ThreadAutoCleanupTest) { EXPECT_EQ(1, counter.load()); } +static void uvThreadTryLockForMutex(void* data) { + auto* mutex = static_cast(data); + EXPECT_NE(0, uv_mutex_trylock(mutex)); +} + TEST_F(UvThreadsTestSuite, MutexGuardTest) { uv_mutex_t mutex; ASSERT_EQ(0, uv_mutex_init(&mutex)); @@ -44,7 +49,9 @@ TEST_F(UvThreadsTestSuite, MutexGuardTest) { { celix_auto(celix_uv_mutex_lock_guard_t) guard = celixUvMutexLockGuard_init(&mutex); - EXPECT_NE(0, uv_mutex_trylock(&mutex)); + uv_thread_t thread; + ASSERT_EQ(0, uv_thread_create(&thread, uvThreadTryLockForMutex, &mutex)); + EXPECT_EQ(0, uv_thread_join(&thread)); } //guard out of scope -> unlock ASSERT_EQ(0, uv_mutex_trylock(&mutex)); From 9f46175ba0164d12480c1e786a628f35d4e6f584 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Mon, 19 Jan 2026 20:37:22 +0100 Subject: [PATCH 8/8] gh-769: Refactor celix_uv_cleanup func and struct naming --- libs/utils/gtest/src/UvThreadsTestSuite.cc | 6 +-- libs/utils/include/celix_uv_cleanup.h | 56 +++++++++++----------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/libs/utils/gtest/src/UvThreadsTestSuite.cc b/libs/utils/gtest/src/UvThreadsTestSuite.cc index 25879c1ef..c7dd9bf2d 100644 --- a/libs/utils/gtest/src/UvThreadsTestSuite.cc +++ b/libs/utils/gtest/src/UvThreadsTestSuite.cc @@ -48,7 +48,7 @@ TEST_F(UvThreadsTestSuite, MutexGuardTest) { celix_autoptr(uv_mutex_t) mutexCleanup = &mutex; { - celix_auto(celix_uv_mutex_lock_guard_t) guard = celixUvMutexLockGuard_init(&mutex); + celix_auto(celix_uv_mutex_lock_guard_t) guard = celix_uvMutexLockGuard_init(&mutex); uv_thread_t thread; ASSERT_EQ(0, uv_thread_create(&thread, uvThreadTryLockForMutex, &mutex)); EXPECT_EQ(0, uv_thread_join(&thread)); @@ -85,14 +85,14 @@ TEST_F(UvThreadsTestSuite, RwlockGuardTest) { celix_autoptr(uv_rwlock_t) lockCleanup = &lock; { - celix_auto(celix_uv_rwlock_wlock_guard_t) writeGuard = celixUvRwlockWlockGuard_init(&lock); + celix_auto(celix_uv_write_lock_guard_t) writeGuard = celix_uvWriteLockGuard_init(&lock); uv_thread_t thread; ASSERT_EQ(0, uv_thread_create(&thread, uvThreadTryLocksForWriteLock, &lock)); EXPECT_EQ(0, uv_thread_join(&thread)); } //guard out of scope -> unlock write lock { - celix_auto(celix_uv_rwlock_rlock_guard_t) readGuard = celixUvRwlockRlockGuard_init(&lock); + celix_auto(celix_uv_read_lock_guard_t) readGuard = celix_uvReadLockGuard_init(&lock); uv_thread_t thread; ASSERT_EQ(0, uv_thread_create(&thread, uvThreadTryLocksForReadLock, &lock)); EXPECT_EQ(0, uv_thread_join(&thread)); diff --git a/libs/utils/include/celix_uv_cleanup.h b/libs/utils/include/celix_uv_cleanup.h index a4ced5dc1..d269666b7 100644 --- a/libs/utils/include/celix_uv_cleanup.h +++ b/libs/utils/include/celix_uv_cleanup.h @@ -42,7 +42,7 @@ typedef struct celix_uv_mutex_lock_guard { } celix_uv_mutex_lock_guard_t; /** - * @brief Initialize a lock guard for @a mutex. + * @brief Initialize a lock guard for a mutex. * * Lock a mutex and return a celix_uv_mutex_lock_guard_t. * Unlock with celixUvMutexLockGuard_deinit(). Using uv_mutex_lock() on a mutex @@ -54,7 +54,7 @@ typedef struct celix_uv_mutex_lock_guard { * @param mutex A mutex to lock. * @return An initialized lock guard to be used with celix_auto(). */ -static CELIX_UNUSED inline celix_uv_mutex_lock_guard_t celixUvMutexLockGuard_init(uv_mutex_t* mutex) { +static CELIX_UNUSED inline celix_uv_mutex_lock_guard_t celix_uvMutexLockGuard_init(uv_mutex_t* mutex) { celix_uv_mutex_lock_guard_t guard; guard.mutex = mutex; uv_mutex_lock(mutex); @@ -69,14 +69,14 @@ static CELIX_UNUSED inline celix_uv_mutex_lock_guard_t celixUvMutexLockGuard_ini * * @param guard A celix_uv_mutex_lock_guard_t. */ -static CELIX_UNUSED inline void celixUvMutexLockGuard_deinit(celix_uv_mutex_lock_guard_t* guard) { +static CELIX_UNUSED inline void celix_uvMutexLockGuard_deinit(celix_uv_mutex_lock_guard_t* guard) { if (guard->mutex) { uv_mutex_unlock(guard->mutex); guard->mutex = NULL; } } -CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_mutex_lock_guard_t, celixUvMutexLockGuard_deinit) +CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_mutex_lock_guard_t, celix_uvMutexLockGuard_deinit) /** * @brief A RAII style write lock guard for uv_rwlock_t. @@ -84,16 +84,16 @@ CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_mutex_lock_guard_t, celixUvMutexLo * The lock is obtained in the constructor and released in the destructor. * This is intended to be used with celix_auto(). */ -typedef struct celix_uv_rwlock_wlock_guard { +typedef struct celix_uv_write_lock_guard { uv_rwlock_t* lock; -} celix_uv_rwlock_wlock_guard_t; +} celix_uv_write_lock_guard_t; /** - * @brief Initialize a write lock guard for @a lock. + * @brief Initialize a write lock guard for a lock. * - * Obtain a write lock on @a lock and return a celix_uv_rwlock_wlock_guard_t. - * Unlock with celixUvRwlockWlockGuard_deinit(). Using uv_rwlock_wrunlock() - * on @lock while a celix_uv_rwlock_wlock_guard_t exists can lead to undefined behaviour. + * Obtain a write lock on a lock and return a celix_uv_write_lock_guard_t. + * Unlock with celixUvWriteLockGuard_deinit(). Using uv_rwlock_wrunlock() + * on lock while a celix_uv_write_lock_guard_t exists can lead to undefined behaviour. * * No allocation is performed, it is equivalent to a uv_rwlock_wrlock() call. * This is intended to be used with celix_auto(). @@ -101,8 +101,8 @@ typedef struct celix_uv_rwlock_wlock_guard { * @param lock A read-write lock to lock. * @return An initialized write lock guard to be used with celix_auto(). */ -static CELIX_UNUSED inline celix_uv_rwlock_wlock_guard_t celixUvRwlockWlockGuard_init(uv_rwlock_t* lock) { - celix_uv_rwlock_wlock_guard_t guard; +static CELIX_UNUSED inline celix_uv_write_lock_guard_t celix_uvWriteLockGuard_init(uv_rwlock_t* lock) { + celix_uv_write_lock_guard_t guard; guard.lock = lock; uv_rwlock_wrlock(lock); return guard; @@ -111,20 +111,20 @@ static CELIX_UNUSED inline celix_uv_rwlock_wlock_guard_t celixUvRwlockWlockGuard /** * @brief Deinitialize a write lock guard. * - * Release a write lock on the read-write lock contained in @a guard. - * See celixUvRwlockWlockGuard_init() for details. + * Release a write lock on the read-write lock contained in a guard. + * See celix_uvWriteLockGuard_init() for details. * No memory is freed, it is equivalent to a uv_rwlock_wrunlock() call. * - * @param guard A celix_uv_rwlock_wlock_guard_t. + * @param guard A celix_uv_write_lock_guard_t. */ -static CELIX_UNUSED inline void celixUvRwlockWlockGuard_deinit(celix_uv_rwlock_wlock_guard_t* guard) { +static CELIX_UNUSED inline void celix_uvWriteLockGuard_deinit(celix_uv_write_lock_guard_t* guard) { if (guard->lock) { uv_rwlock_wrunlock(guard->lock); guard->lock = NULL; } } -CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_rwlock_wlock_guard_t, celixUvRwlockWlockGuard_deinit) +CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_write_lock_guard_t, celix_uvWriteLockGuard_deinit) /** * @brief A RAII style read lock guard for uv_rwlock_t. @@ -132,16 +132,16 @@ CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_rwlock_wlock_guard_t, celixUvRwloc * The lock is obtained in the constructor and released in the destructor. * This is intended to be used with celix_auto(). */ -typedef struct celix_uv_rwlock_rlock_guard { +typedef struct celix_uv_read_lock_guard { uv_rwlock_t* lock; -} celix_uv_rwlock_rlock_guard_t; +} celix_uv_read_lock_guard_t; /** * @brief Initialize a read lock guard for a lock. * - * Obtain a read lock on a lock and return a celix_uv_rwlock_rlock_guard_t. - * Unlock with celixUvRwlockRlockGuard_deinit(). Using uv_rwlock_rdunlock() - * on @lock while a celix_uv_rwlock_rlock_guard_t exists can lead to undefined behaviour. + * Obtain a read lock on a lock and return a celix_uv_read_lock_guard_t. + * Unlock with celix_uvReadLockGuard_deinit(). Using uv_rwlock_rdunlock() + * on lock while a celix_uv_read_lock_guard_t exists can lead to undefined behaviour. * * No allocation is performed, it is equivalent to a uv_rwlock_rdlock() call. * This is intended to be used with celix_auto(). @@ -149,8 +149,8 @@ typedef struct celix_uv_rwlock_rlock_guard { * @param lock A read-write lock to lock. * @return A guard to be used with celix_auto(). */ -static CELIX_UNUSED inline celix_uv_rwlock_rlock_guard_t celixUvRwlockRlockGuard_init(uv_rwlock_t* lock) { - celix_uv_rwlock_rlock_guard_t guard; +static CELIX_UNUSED inline celix_uv_read_lock_guard_t celix_uvReadLockGuard_init(uv_rwlock_t* lock) { + celix_uv_read_lock_guard_t guard; guard.lock = lock; uv_rwlock_rdlock(lock); return guard; @@ -160,19 +160,19 @@ static CELIX_UNUSED inline celix_uv_rwlock_rlock_guard_t celixUvRwlockRlockGuard * @brief Deinitialize a read lock guard. * * Release a read lock on the read-write lock contained in a guard. - * See celixUvRwlockRlockGuard_init() for details. + * See celix_uvReadLockGuard_init() for details. * No memory is freed, it is equivalent to a uv_rwlock_rdunlock() call. * - * @param guard A celix_uv_rwlock_rlock_guard_t. + * @param guard A celix_uv_read_lock_guard_t. */ -static CELIX_UNUSED inline void celixUvRwlockRlockGuard_deinit(celix_uv_rwlock_rlock_guard_t* guard) { +static CELIX_UNUSED inline void celix_uvReadLockGuard_deinit(celix_uv_read_lock_guard_t* guard) { if (guard->lock) { uv_rwlock_rdunlock(guard->lock); guard->lock = NULL; } } -CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_rwlock_rlock_guard_t, celixUvRwlockRlockGuard_deinit) +CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_read_lock_guard_t, celix_uvReadLockGuard_deinit) #ifdef __cplusplus }