Skip to content

Commit e2d3cee

Browse files
committed
gh-769: Add celix_uv_cleanup.h
1 parent 2127aeb commit e2d3cee

File tree

7 files changed

+314
-99
lines changed

7 files changed

+314
-99
lines changed

libs/utils/CMakeLists.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@
1818
celix_subproject(UTILS "Option to enable building the Utilities library" ON)
1919
if (UTILS)
2020
find_package(libzip REQUIRED)
21-
find_package(jansson REQUIRED) #TODO add jansson dep info to build (conan) and documentation info
21+
find_package(jansson REQUIRED)
22+
find_package(libuv REQUIRED)
23+
24+
if (NOT TARGET libuv::uv AND TARGET uv)
25+
#Note: conan libuv package 1.49.2 defines uv target, but 1.51.0 defines libuv::uv target
26+
add_library(libuv::uv ALIAS uv)
27+
endif ()
2228

2329
set(MEMSTREAM_SOURCES )
2430
set(MEMSTREAM_INCLUDES )
@@ -46,7 +52,7 @@ if (UTILS)
4652
${MEMSTREAM_SOURCES}
4753
)
4854
set(UTILS_PRIVATE_DEPS libzip::zip jansson::jansson)
49-
set(UTILS_PUBLIC_DEPS)
55+
set(UTILS_PUBLIC_DEPS libuv::uv)
5056

5157
add_library(utils SHARED ${UTILS_SRC})
5258

libs/utils/gtest/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,15 @@ add_executable(test_utils
3535
src/VersionTestSuite.cc
3636
src/ErrTestSuite.cc
3737
src/ThreadsTestSuite.cc
38+
src/UvThreadsTestSuite.cc
3839
src/CelixErrnoTestSuite.cc
3940
src/CelixUtilsAutoCleanupTestSuite.cc
4041
src/ArrayListTestSuite.cc
4142
src/DeprecatedHashmapTestSuite.cc
4243
src/CxxExceptionsTestSuite.cc
4344
)
4445

45-
target_link_libraries(test_utils PRIVATE utils_cut Celix::utils GTest::gtest GTest::gtest_main libzip::zip)
46+
target_link_libraries(test_utils PRIVATE utils_cut Celix::utils GTest::gtest GTest::gtest_main libzip::zip libuv::uv)
4647
target_include_directories(test_utils PRIVATE ../src) #for version_private (needs refactoring of test)
4748
celix_deprecated_utils_headers(test_utils)
4849

@@ -153,7 +154,10 @@ if (EI_TESTS)
153154
Celix::fts_ei
154155
utils_cut
155156
Celix::utils_ei
157+
libuv::uv
158+
-Wl,--whole-archive
156159
Celix::ifaddrs_ei
160+
-Wl,--no-whole-archive
157161
Celix::threads_ei
158162
Celix::malloc_ei
159163
Celix::asprintf_ei
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
#include "celix_uv_cleanup.h"
19+
20+
#include <atomic>
21+
#include <gtest/gtest.h>
22+
23+
class UvThreadsTestSuite : public ::testing::Test {
24+
};
25+
26+
static void uvThreadIncrement(void* data) {
27+
auto* counter = static_cast<std::atomic<int>*>(data);
28+
counter->fetch_add(1);
29+
}
30+
31+
TEST_F(UvThreadsTestSuite, ThreadAutoCleanupTest) {
32+
std::atomic<int> counter{0};
33+
{
34+
celix_auto(uv_thread_t) thread;
35+
ASSERT_EQ(0, uv_thread_create(&thread, uvThreadIncrement, &counter));
36+
} //thread out of scope -> join
37+
EXPECT_EQ(1, counter.load());
38+
}
39+
40+
TEST_F(UvThreadsTestSuite, MutexGuardTest) {
41+
uv_mutex_t mutex;
42+
ASSERT_EQ(0, uv_mutex_init(&mutex));
43+
celix_autoptr(uv_mutex_t) mutexCleanup = &mutex;
44+
45+
{
46+
celix_auto(celix_uv_mutex_lock_guard_t) guard = celixUvMutexLockGuard_init(&mutex);
47+
EXPECT_NE(0, uv_mutex_trylock(&mutex));
48+
} //guard out of scope -> unlock
49+
50+
EXPECT_EQ(0, uv_mutex_trylock(&mutex));
51+
uv_mutex_unlock(&mutex);
52+
}
53+
54+
TEST_F(UvThreadsTestSuite, MutexStealTest) {
55+
uv_mutex_t mutex;
56+
ASSERT_EQ(0, uv_mutex_init(&mutex));
57+
celix_autoptr(uv_mutex_t) mutexCleanup = &mutex;
58+
celix_steal_ptr(mutexCleanup);
59+
uv_mutex_destroy(&mutex);
60+
}
61+
62+
TEST_F(UvThreadsTestSuite, RwlockGuardTest) {
63+
uv_rwlock_t lock;
64+
ASSERT_EQ(0, uv_rwlock_init(&lock));
65+
celix_autoptr(uv_rwlock_t) lockCleanup = &lock;
66+
67+
{
68+
celix_auto(celix_uv_rwlock_wlock_guard_t) guard = celixUvRwlockWlockGuard_init(&lock);
69+
EXPECT_NE(0, uv_rwlock_tryrdlock(&lock));
70+
EXPECT_NE(0, uv_rwlock_trywrlock(&lock));
71+
} //guard out of scope -> unlock
72+
73+
{
74+
celix_auto(celix_uv_rwlock_rlock_guard_t) guard = celixUvRwlockRlockGuard_init(&lock);
75+
76+
EXPECT_EQ(0, uv_rwlock_tryrdlock(&lock));
77+
uv_rwlock_rdunlock(&lock);
78+
79+
EXPECT_NE(0, uv_rwlock_trywrlock(&lock));
80+
} //guard out of scope -> unlock
81+
82+
EXPECT_EQ(0, uv_rwlock_trywrlock(&lock));
83+
uv_rwlock_wrunlock(&lock);
84+
}
85+
86+
TEST_F(UvThreadsTestSuite, RwlockStealdTest) {
87+
uv_rwlock_t lock;
88+
ASSERT_EQ(0, uv_rwlock_init(&lock));
89+
celix_autoptr(uv_rwlock_t) lockCleanup = &lock;
90+
celix_steal_ptr(lockCleanup);
91+
uv_rwlock_destroy(&lock);
92+
}
93+
94+
TEST_F(UvThreadsTestSuite, ConditionAutoCleanupTest) {
95+
uv_cond_t cond;
96+
ASSERT_EQ(0, uv_cond_init(&cond));
97+
celix_autoptr(uv_cond_t) condCleanup = &cond;
98+
}
99+
100+
TEST_F(UvThreadsTestSuite, ConditionStealTest) {
101+
uv_cond_t cond;
102+
ASSERT_EQ(0, uv_cond_init(&cond));
103+
celix_autoptr(uv_cond_t) condCleanup = &cond;
104+
celix_steal_ptr(condCleanup);
105+
uv_cond_destroy(&cond);
106+
}
107+
108+
TEST_F(UvThreadsTestSuite, LocalThreadStorageKeyAutoCleanupTest) {
109+
uv_key_t key;
110+
ASSERT_EQ(0, uv_key_create(&key));
111+
celix_autoptr(uv_key_t) keyCleanup = &key;
112+
}
113+
114+
TEST_F(UvThreadsTestSuite, LocalThreadStorageKeyStealTest) {
115+
uv_key_t key;
116+
ASSERT_EQ(0, uv_key_create(&key));
117+
celix_autoptr(uv_key_t) keyCleanup = &key;
118+
celix_steal_ptr(keyCleanup);
119+
uv_key_delete(&key);
120+
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#ifndef CELIX_UV_CLEANUP_H
21+
#define CELIX_UV_CLEANUP_H
22+
23+
#include <uv.h>
24+
25+
#include "celix_cleanup.h"
26+
27+
#ifdef __cplusplus
28+
extern "C" {
29+
#endif
30+
31+
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(uv_thread_t, uv_thread_join)
32+
CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(uv_mutex_t, uv_mutex_destroy)
33+
CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(uv_rwlock_t, uv_rwlock_destroy)
34+
CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(uv_cond_t, uv_cond_destroy)
35+
CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(uv_key_t, uv_key_delete)
36+
37+
/**
38+
* @brief Lock guard for uv mutexes.
39+
*/
40+
typedef struct celix_uv_mutex_lock_guard {
41+
uv_mutex_t* mutex;
42+
} celix_uv_mutex_lock_guard_t;
43+
44+
/**
45+
* @brief Initialize a lock guard for @a mutex.
46+
*
47+
* Lock a mutex and return a celix_uv_mutex_lock_guard_t.
48+
* Unlock with celixUvMutexLockGuard_deinit(). Using uv_mutex_lock() on a mutex
49+
* while a celix_uv_mutex_lock_guard_t exists can lead to undefined behaviour.
50+
*
51+
* No allocation is performed, it is equivalent to a uv_mutex_lock() call.
52+
* This is intended to be used with celix_auto().
53+
*
54+
* @param mutex A mutex to lock.
55+
* @return An initialized lock guard to be used with celix_auto().
56+
*/
57+
static CELIX_UNUSED inline celix_uv_mutex_lock_guard_t celixUvMutexLockGuard_init(uv_mutex_t* mutex) {
58+
celix_uv_mutex_lock_guard_t guard;
59+
guard.mutex = mutex;
60+
uv_mutex_lock(mutex);
61+
return guard;
62+
}
63+
64+
/**
65+
* @brief Deinitialize a lock guard for a mutex.
66+
*
67+
* Unlock the mutex of a guard.
68+
* No memory is freed, it is equivalent to a uv_mutex_unlock() call.
69+
*
70+
* @param guard A celix_uv_mutex_lock_guard_t.
71+
*/
72+
static CELIX_UNUSED inline void celixUvMutexLockGuard_deinit(celix_uv_mutex_lock_guard_t* guard) {
73+
if (guard->mutex) {
74+
uv_mutex_unlock(guard->mutex);
75+
guard->mutex = NULL;
76+
}
77+
}
78+
79+
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_mutex_lock_guard_t, celixUvMutexLockGuard_deinit)
80+
81+
/**
82+
* @brief A RAII style write lock guard for uv_rwlock_t.
83+
*
84+
* The lock is obtained in the constructor and released in the destructor.
85+
* This is intended to be used with celix_auto().
86+
*/
87+
typedef struct celix_uv_rwlock_wlock_guard {
88+
uv_rwlock_t* lock;
89+
} celix_uv_rwlock_wlock_guard_t;
90+
91+
/**
92+
* @brief Initialize a write lock guard for @a lock.
93+
*
94+
* Obtain a write lock on @a lock and return a celix_uv_rwlock_wlock_guard_t.
95+
* Unlock with celixUvRwlockWlockGuard_deinit(). Using uv_rwlock_wrunlock()
96+
* on @lock while a celix_uv_rwlock_wlock_guard_t exists can lead to undefined behaviour.
97+
*
98+
* No allocation is performed, it is equivalent to a uv_rwlock_wrlock() call.
99+
* This is intended to be used with celix_auto().
100+
*
101+
* @param lock A read-write lock to lock.
102+
* @return An initialized write lock guard to be used with celix_auto().
103+
*/
104+
static CELIX_UNUSED inline celix_uv_rwlock_wlock_guard_t celixUvRwlockWlockGuard_init(uv_rwlock_t* lock) {
105+
celix_uv_rwlock_wlock_guard_t guard;
106+
guard.lock = lock;
107+
uv_rwlock_wrlock(lock);
108+
return guard;
109+
}
110+
111+
/**
112+
* @brief Deinitialize a write lock guard.
113+
*
114+
* Release a write lock on the read-write lock contained in @a guard.
115+
* See celixUvRwlockWlockGuard_init() for details.
116+
* No memory is freed, it is equivalent to a uv_rwlock_wrunlock() call.
117+
*
118+
* @param guard A celix_uv_rwlock_wlock_guard_t.
119+
*/
120+
static CELIX_UNUSED inline void celixUvRwlockWlockGuard_deinit(celix_uv_rwlock_wlock_guard_t* guard) {
121+
if (guard->lock) {
122+
uv_rwlock_wrunlock(guard->lock);
123+
guard->lock = NULL;
124+
}
125+
}
126+
127+
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_rwlock_wlock_guard_t, celixUvRwlockWlockGuard_deinit)
128+
129+
/**
130+
* @brief A RAII style read lock guard for uv_rwlock_t.
131+
*
132+
* The lock is obtained in the constructor and released in the destructor.
133+
* This is intended to be used with celix_auto().
134+
*/
135+
typedef struct celix_uv_rwlock_rlock_guard {
136+
uv_rwlock_t* lock;
137+
} celix_uv_rwlock_rlock_guard_t;
138+
139+
/**
140+
* @brief Initialize a read lock guard for a lock.
141+
*
142+
* Obtain a read lock on a lock and return a celix_uv_rwlock_rlock_guard_t.
143+
* Unlock with celixUvRwlockRlockGuard_deinit(). Using uv_rwlock_rdunlock()
144+
* on @lock while a celix_uv_rwlock_rlock_guard_t exists can lead to undefined behaviour.
145+
*
146+
* No allocation is performed, it is equivalent to a uv_rwlock_rdlock() call.
147+
* This is intended to be used with celix_auto().
148+
*
149+
* @param lock A read-write lock to lock.
150+
* @return A guard to be used with celix_auto().
151+
*/
152+
static CELIX_UNUSED inline celix_uv_rwlock_rlock_guard_t celixUvRwlockRlockGuard_init(uv_rwlock_t* lock) {
153+
celix_uv_rwlock_rlock_guard_t guard;
154+
guard.lock = lock;
155+
uv_rwlock_rdlock(lock);
156+
return guard;
157+
}
158+
159+
/**
160+
* @brief Deinitialize a read lock guard.
161+
*
162+
* Release a read lock on the read-write lock contained in a guard.
163+
* See celixUvRwlockRlockGuard_init() for details.
164+
* No memory is freed, it is equivalent to a uv_rwlock_rdunlock() call.
165+
*
166+
* @param guard A celix_uv_rwlock_rlock_guard_t.
167+
*/
168+
static CELIX_UNUSED inline void celixUvRwlockRlockGuard_deinit(celix_uv_rwlock_rlock_guard_t* guard) {
169+
if (guard->lock) {
170+
uv_rwlock_rdunlock(guard->lock);
171+
guard->lock = NULL;
172+
}
173+
}
174+
175+
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_uv_rwlock_rlock_guard_t, celixUvRwlockRlockGuard_deinit)
176+
177+
#ifdef __cplusplus
178+
}
179+
#endif
180+
181+
#endif /* CELIX_UV_CLEANUP_H */

misc/experimental/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,5 @@
1818
celix_subproject(EXPERIMENTAL "Options to enable building the experimental - non stable - bundles/libraries. " OFF)
1919
if (EXPERIMENTAL)
2020
add_subdirectory(bundles)
21-
add_subdirectory(libuv)
2221
add_subdirectory(rust)
2322
endif ()

misc/experimental/libuv/CMakeLists.txt

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)