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/coverage.yml b/.github/workflows/coverage.yml index b6c997ef9..4ad7a2339 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -19,15 +19,21 @@ jobs: - name: Install conan and lcov run: | sudo apt-get install -yq --no-install-recommends lcov - sudo pip install conan==1.62.0 coverage + sudo pip install -U conan coverage - name: Setup Conan Profile run: | - conan profile new default --detect - conan profile update settings.build_type=Debug default - #Note no backwards compatiblity for gcc5 needed, setting libcxx to c++11. - conan profile update settings.compiler.libcxx=libstdc++11 default - echo "[tool_requires]" >> `conan config home`/profiles/default - echo "cmake/3.26.4" >> `conan config home`/profiles/default + # build profile + conan profile detect -f --name release + sed -i 's/compiler.cppstd=gnu14/compiler.cppstd=gnu17/g' `conan profile path release` + echo "[tool_requires]" >> `conan profile path release` + echo "cmake/3.26.4" >> `conan profile path release` + + # host profile + conan profile detect -f + sed -i 's/build_type=Release/build_type=Debug/g' `conan profile path default` + sed -i 's/compiler.cppstd=gnu14/compiler.cppstd=gnu17/g' `conan profile path default` + echo "[tool_requires]" >> `conan profile path default` + echo "cmake/3.26.4" >> `conan profile path default` - name: Conan Cache id: cache-conan uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf #v4.2.2 @@ -48,19 +54,16 @@ jobs: key: ${{ runner.os }}-gcov-ccache-${{ steps.ccache_cache_timestamp.outputs.timestamp }} restore-keys: | ${{ runner.os }}-gcov-ccache- - - name: Install Dependencies + - name: Install Dependencies and Build env: CONAN_BUILD_OPTIONS: | - -o celix:enable_testing=True - -o celix:build_all=True - -o celix:enable_code_coverage=True - -o celix:enable_testing_on_ci=True - -o celix:enable_ccache=True + -o celix/*:enable_testing=True + -o celix/*:build_all=True + -o celix/*:enable_code_coverage=True + -o celix/*:enable_testing_on_ci=True + -o celix/*:enable_ccache=True run: | - conan install . celix/ci -pr:b default -pr:h default -if build ${CONAN_BUILD_OPTIONS} -b missing --require-override=openssl/1.1.1s - - name: Build - run: | - conan build . -bf build + conan build . -pr:b release -pr:h default -of build ${CONAN_BUILD_OPTIONS} -b missing - name: Test with coverage run: | cd build 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..0e60cf73c 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -28,7 +28,7 @@ jobs: uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c #v3.3.0 - name: Install build dependencies run: | - sudo pip install -U conan==1.62.0 + sudo pip install -U conan sudo apt-get install -yq --no-install-recommends ninja-build - name: Setup Conan Profile env: @@ -36,21 +36,17 @@ jobs: CXX: ${{ matrix.compiler[1] }} run: | # build profile - conan profile new release --detect - conan profile update settings.build_type=Release release - #Note no backwards compatibility for gcc5 needed, setting libcxx to c++11. - conan profile update settings.compiler.libcxx=libstdc++11 release - conan profile show release - echo "[tool_requires]" >> `conan config home`/profiles/release - echo "cmake/3.26.4" >> `conan config home`/profiles/release + conan profile detect -f --name release + sed -i 's/compiler.cppstd=gnu14/compiler.cppstd=gnu17/g' `conan profile path release` + echo "[tool_requires]" >> `conan profile path release` + echo "cmake/3.26.4" >> `conan profile path release` + # host profile - conan profile new default --detect - conan profile update settings.build_type=${{ matrix.type }} default - #Note no backwards compatibility for gcc5 needed, setting libcxx to c++11. - conan profile update settings.compiler.libcxx=libstdc++11 default - conan profile show default - echo "[tool_requires]" >> `conan config home`/profiles/default - echo "cmake/3.26.4" >> `conan config home`/profiles/default + conan profile detect -f + sed -i 's/build_type=Release/build_type=${{ matrix.type }}/g' `conan profile path default` + sed -i 's/compiler.cppstd=gnu14/compiler.cppstd=gnu17/g' `conan profile path default` + echo "[tool_requires]" >> `conan profile path default` + echo "cmake/3.26.4" >> `conan profile path default` - name: Conan Cache id: cache-conan uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf #v4.2.2 @@ -71,29 +67,22 @@ jobs: key: ${{ runner.os }}-test-ccache-${{ matrix.compiler[0] }}-${{ matrix.type }}-${{ steps.ccache_cache_timestamp.outputs.timestamp }} restore-keys: | ${{ runner.os }}-test-ccache-${{ matrix.compiler[0] }}-${{ matrix.type }}- - - name: Configure and install dependencies + - name: Install Dependencies and Build env: CC: ${{ matrix.compiler[0] }} CXX: ${{ matrix.compiler[1] }} CONAN_BUILD_OPTIONS: | - -o celix:enable_testing=True - -o celix:enable_benchmarking=True - -o celix:enable_address_sanitizer=True - -o celix:enable_undefined_sanitizer=True - -o celix:build_all=True - -o celix:enable_cmake_warning_tests=True - -o celix:enable_testing_on_ci=True - -o celix:framework_curlinit=False - -o celix:enable_ccache=True + -o celix/*:enable_testing=True + -o celix/*:enable_benchmarking=True + -o celix/*:enable_address_sanitizer=True + -o celix/*:enable_undefined_sanitizer=True + -o celix/*:build_all=True + -o celix/*:enable_cmake_warning_tests=True + -o celix/*:enable_testing_on_ci=True + -o celix/*:framework_curlinit=False + -o celix/*:enable_ccache=True run: | - conan install . celix/ci -c tools.cmake.cmaketoolchain:generator=Ninja -pr:b release -pr:h default -if build ${CONAN_BUILD_OPTIONS} -b missing - - name: Build - env: - CC: ${{ matrix.compiler[0] }} - CXX: ${{ matrix.compiler[1] }} - CONAN_CMAKE_GENERATOR: Ninja - run: | - conan build . -bf build + conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -pr:b release -pr:h default -of build ${CONAN_BUILD_OPTIONS} -b missing - name: Test run: | cd build @@ -123,6 +112,7 @@ jobs: libjansson-dev \ libcurl4-openssl-dev \ libbenchmark-dev \ + libuv1-dev \ default-jdk \ cmake \ libffi-dev \ diff --git a/cmake/CelixConfig.cmake b/cmake/CelixConfig.cmake index a97ccc8a2..20c07935d 100644 --- a/cmake/CelixConfig.cmake +++ b/cmake/CelixConfig.cmake @@ -35,6 +35,9 @@ include(CMakeFindDependencyMacro) set(THREADS_PREFER_PTHREAD_FLAG ON) find_dependency(Threads) +# The rest is added to ensure backwards compatibility with project using the cmake lib/include var instead of targets. +set(CELIX_CMAKE_MODULES_DIR ${CELIX_REL_INSTALL_DIR}/share/celix/cmake/Modules) + #adds celix optional dependencies include("${CELIX_REL_INSTALL_DIR}/share/celix/cmake/CelixDeps.cmake") @@ -42,9 +45,6 @@ include("${CELIX_REL_INSTALL_DIR}/share/celix/cmake/CelixDeps.cmake") include("${CELIX_REL_INSTALL_DIR}/share/celix/cmake/Targets.cmake") include("${CELIX_REL_INSTALL_DIR}/share/celix/cmake/CelixTargets.cmake") -# The rest is added to ensure backwards compatiblity with project using the cmake lib/include var instead of targets. -set(CELIX_CMAKE_MODULES_DIR ${CELIX_REL_INSTALL_DIR}/share/celix/cmake/Modules) - set(CELIX_FRAMEWORK_INCLUDE_DIR "${CELIX_REL_INSTALL_DIR}/include/celix") set(CELIX_UTILS_INCLUDE_DIR "${CELIX_REL_INSTALL_DIR}/include/utils") set(CELIX_DFI_INCLUDE_DIR "${CELIX_REL_INSTALL_DIR}/include/dfi") @@ -69,16 +69,6 @@ if (TARGET Celix::etcdlib) set(CELIX_ETCD_LIB Celix::etcdlib) endif () -if (TARGET Celix::dependency_manager_so) - set(CELIX_DM_LIB Celix::dependency_manager_so) - set(CELIX_DM_INCLUDE_DIR $) - set(CELIX_DM_STATIC_LIB Celix::dependency_manager_static) -endif () -if (TARGET Celix::dependency_manager_cxx) - set(CELIX_DM_STATIC_CXX_LIB Celix::dependency_manager_cxx) - set(CELIX_DM_CXX_STATIC_LIB $) -endif () - set(CELIX_BUNDLES_DIR ${CELIX_REL_INSTALL_DIR}/share/celix/bundles) set(CELIX_SHELL_BUNDLE ${CELIX_BUNDLES_DIR}/shell.zip) set(CELIX_SHELL_TUI_BUNDLE ${CELIX_BUNDLES_DIR}/shell_tui.zip) \ No newline at end of file diff --git a/cmake/CelixDeps.cmake.in b/cmake/CelixDeps.cmake.in index bea259e79..4e64bb977 100644 --- a/cmake/CelixDeps.cmake.in +++ b/cmake/CelixDeps.cmake.in @@ -2,6 +2,8 @@ $<$>:find_dependency(libuuid)> $<$>:find_dependency(libuuid)> $<$>:find_dependency(libuuid)> $<$>:find_dependency(libzip)> +$<$>:find_dependency(jansson)> +$<$>:find_dependency(libuv)> $<$>:find_dependency(ZLIB)> $<$>:find_dependency(libffi)> $<$>:find_dependency(jansson)> 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..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) @@ -340,6 +341,7 @@ def configure(self): 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": diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt index e28317b49..513314b2b 100644 --- a/libs/utils/CMakeLists.txt +++ b/libs/utils/CMakeLists.txt @@ -18,7 +18,8 @@ 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) set(MEMSTREAM_SOURCES ) set(MEMSTREAM_INCLUDES ) @@ -46,7 +47,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..84fe3a4c2 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) diff --git a/libs/utils/gtest/src/UvThreadsTestSuite.cc b/libs/utils/gtest/src/UvThreadsTestSuite.cc new file mode 100644 index 000000000..6f062a7d2 --- /dev/null +++ b/libs/utils/gtest/src/UvThreadsTestSuite.cc @@ -0,0 +1,125 @@ +// 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 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)); + celix_autoptr(uv_mutex_t) mutexCleanup = &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)); + } //guard out of scope -> unlock + + ASSERT_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); +} + +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; + + { + 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_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)); + } //guard out of scope -> unlock read lock + + ASSERT_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..aab25460a --- /dev/null +++ b/libs/utils/include/celix_uv_cleanup.h @@ -0,0 +1,180 @@ +/* + * 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_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 celix_uvMutexLockGuard_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 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, celix_uvMutexLockGuard_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_write_lock_guard { + uv_rwlock_t* lock; +} celix_uv_write_lock_guard_t; + +/** + * @brief Initialize a write lock guard for a lock. + * + * 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(). + * + * @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_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; +} + +/** + * @brief Deinitialize a write lock guard. + * + * 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_write_lock_guard_t. + */ +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_write_lock_guard_t, celix_uvWriteLockGuard_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_read_lock_guard { + uv_rwlock_t* lock; +} 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_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(). + * + * @param lock A read-write lock to lock. + * @return A guard to be used with celix_auto(). + */ +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; +} + +/** + * @brief Deinitialize a read lock guard. + * + * Release a read lock on the read-write lock contained in a guard. + * See celix_uvReadLockGuard_init() for details. + * No memory is freed, it is equivalent to a uv_rwlock_rdunlock() call. + * + * @param guard A celix_uv_read_lock_guard_t. + */ +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_read_lock_guard_t, celix_uvReadLockGuard_deinit) + +#ifdef __cplusplus +} +#endif + +#endif /* CELIX_UV_CLEANUP_H */ diff --git a/misc/Dockerfile.Android b/misc/Dockerfile.Android index 8e27f09f6..1a8a3f4d0 100644 --- a/misc/Dockerfile.Android +++ b/misc/Dockerfile.Android @@ -132,6 +132,6 @@ RUN curl -L -O ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz && \ RUN git clone -b master --single-branch https://github.com/apache/celix.git celix -CMD mkdir -p celix/build-android && cd celix/build-android && cmake -DANDROID=TRUE -DENABLE_TESTING=OFF -DBUILD_EXAMPLES=OFF -DBUILD_DEPENDENCY_MANAGER_CXX=OFF -DBUILD_REMOTE_SERVICE_ADMIN=ON -DBUILD_REMOTE_SHELL=ON -DBUILD_RSA_DISCOVERY_CONFIGURED=ON -DBUILD_RSA_DISCOVERY_ETCD=ON -DBUILD_RSA_EXAMPLES=ON -DBUILD_RSA_REMOTE_SERVICE_ADMIN_HTTP=ON -DBUILD_RSA_REMOTE_SERVICE_ADMIN_DFI=OFF -DBUILD_RSA_TOPOLOGY_MANAGER=ON -DFFI_LIBRARY=/build/output/libffi/lib/libffi.a -DFFI_INCLUDE_DIR=/build/output/libffi/lib/libffi-3.2.1/include -DJANSSON_LIBRARY=/build/output/jansson/lib/libjansson.a -DJANSSON_INCLUDE_DIR=/build/output/jansson/include -DCURL_LIBRARY=/build/output/curl/lib/libcurl.a -DCURL_INCLUDE_DIR=/build/output/curl/include -DLIBXML2_LIBRARIES=/build/output/libxml2/lib/libxml2.a -DLIBXML2_INCLUDE_DIR=/build/output/libxml2/include/libxml2 -DZLIB_LIBRARY=/build/output/zlib/lib/libz.a -DZLIB_INCLUDE_DIR=/build/output/zlib/include -DUUID_LIBRARY=/build/output/uuid/lib/libuuid.a -DUUID_INCLUDE_DIR=/build/output/uuid/include -DCMAKE_INSTALL_PREFIX:PATH=/build/output/celix .. && make && make install +CMD mkdir -p celix/build-android && cd celix/build-android && cmake -DANDROID=TRUE -DENABLE_TESTING=OFF -DBUILD_EXAMPLES=OFF -DBUILD_REMOTE_SERVICE_ADMIN=ON -DBUILD_REMOTE_SHELL=ON -DBUILD_RSA_DISCOVERY_CONFIGURED=ON -DBUILD_RSA_DISCOVERY_ETCD=ON -DBUILD_RSA_EXAMPLES=ON -DBUILD_RSA_REMOTE_SERVICE_ADMIN_HTTP=ON -DBUILD_RSA_REMOTE_SERVICE_ADMIN_DFI=OFF -DBUILD_RSA_TOPOLOGY_MANAGER=ON -DFFI_LIBRARY=/build/output/libffi/lib/libffi.a -DFFI_INCLUDE_DIR=/build/output/libffi/lib/libffi-3.2.1/include -DJANSSON_LIBRARY=/build/output/jansson/lib/libjansson.a -DJANSSON_INCLUDE_DIR=/build/output/jansson/include -DCURL_LIBRARY=/build/output/curl/lib/libcurl.a -DCURL_INCLUDE_DIR=/build/output/curl/include -DLIBXML2_LIBRARIES=/build/output/libxml2/lib/libxml2.a -DLIBXML2_INCLUDE_DIR=/build/output/libxml2/include/libxml2 -DZLIB_LIBRARY=/build/output/zlib/lib/libz.a -DZLIB_INCLUDE_DIR=/build/output/zlib/include -DUUID_LIBRARY=/build/output/uuid/lib/libuuid.a -DUUID_INCLUDE_DIR=/build/output/uuid/include -DCMAKE_INSTALL_PREFIX:PATH=/build/output/celix .. && make && make install # done