From d36b30803e2ca313339b44e181efa46c925b51b8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 14 Apr 2015 08:59:01 +0200 Subject: [PATCH] thread: Add a function to pop and call all registered cleanup handlers --- .../tests/suites/test_threading.c | 31 +++++++++++++++++++ src/libstrongswan/threading/thread.c | 17 ++++++++++ src/libstrongswan/threading/thread.h | 10 ++++++ src/libstrongswan/threading/windows/thread.c | 20 ++++++++++++ 4 files changed, 78 insertions(+) diff --git a/src/libstrongswan/tests/suites/test_threading.c b/src/libstrongswan/tests/suites/test_threading.c index 55a4cd797..9a9fdd8e9 100644 --- a/src/libstrongswan/tests/suites/test_threading.c +++ b/src/libstrongswan/tests/suites/test_threading.c @@ -1517,6 +1517,36 @@ START_TEST(test_cleanup_pop) } END_TEST +static void *cleanup_popall_run(void *data) +{ + thread_cleanup_push(cleanup3, data); + thread_cleanup_push(cleanup2, data); + thread_cleanup_push(cleanup1, data); + + thread_cleanup_popall(); + return NULL; +} + +START_TEST(test_cleanup_popall) +{ + thread_t *threads[THREADS]; + uintptr_t values[THREADS]; + int i; + + for (i = 0; i < THREADS; i++) + { + values[i] = 1; + threads[i] = thread_create(cleanup_popall_run, &values[i]); + } + for (i = 0; i < THREADS; i++) + { + threads[i]->join(threads[i]); + ck_assert_int_eq(values[i], 4); + } +} +END_TEST + + static thread_value_t *tls[10]; static void *tls_run(void *data) @@ -1697,6 +1727,7 @@ Suite *threading_suite_create() tcase_add_test(tc, test_cleanup_exit); tcase_add_test(tc, test_cleanup_cancel); tcase_add_test(tc, test_cleanup_pop); + tcase_add_test(tc, test_cleanup_popall); suite_add_tcase(s, tc); tc = tcase_create("thread local storage"); diff --git a/src/libstrongswan/threading/thread.c b/src/libstrongswan/threading/thread.c index 91a2d345d..7a243e826 100644 --- a/src/libstrongswan/threading/thread.c +++ b/src/libstrongswan/threading/thread.c @@ -399,6 +399,23 @@ void thread_cleanup_pop(bool execute) free(handler); } +/** + * Described in header. + */ +void thread_cleanup_popall() +{ + private_thread_t *this = (private_thread_t*)thread_current(); + cleanup_handler_t *handler; + + while (this->cleanup_handlers->get_count(this->cleanup_handlers)) + { + this->cleanup_handlers->remove_last(this->cleanup_handlers, + (void**)&handler); + handler->cleanup(handler->arg); + free(handler); + } +} + /** * Described in header. */ diff --git a/src/libstrongswan/threading/thread.h b/src/libstrongswan/threading/thread.h index 38275541e..c24772839 100644 --- a/src/libstrongswan/threading/thread.h +++ b/src/libstrongswan/threading/thread.h @@ -123,6 +123,16 @@ void thread_cleanup_push(thread_cleanup_t cleanup, void *arg); */ void thread_cleanup_pop(bool execute); +/** + * Pop and execute all cleanup handlers in reverse order of registration. + * + * This function is for very special purposes only, where the caller exactly + * knows which cleanup handlers have been pushed. For regular use, a caller + * should thread_cleanup_pop() exactly the number of handlers it pushed + * using thread_cleanup_push(). + */ +void thread_cleanup_popall(); + /** * Enable or disable the cancelability of the current thread. The current * value is returned. diff --git a/src/libstrongswan/threading/windows/thread.c b/src/libstrongswan/threading/windows/thread.c index e76758f8c..610524722 100644 --- a/src/libstrongswan/threading/windows/thread.c +++ b/src/libstrongswan/threading/windows/thread.c @@ -559,6 +559,26 @@ void thread_cleanup_pop(bool execute) } } +/** + * Described in header. + */ +void thread_cleanup_popall() +{ + private_thread_t *this; + cleanup_t cleanup = {}; + bool old; + + this = get_current_thread(); + while (array_count(this->cleanup)) + { + old = set_leak_detective(FALSE); + array_remove(this->cleanup, -1, &cleanup); + set_leak_detective(old); + + cleanup.cb(cleanup.arg); + } +} + /** * Described in header. */ -- 2.39.2