From: Martin Willi Date: Tue, 14 Apr 2015 06:59:01 +0000 (+0200) Subject: thread: Add a function to pop and call all registered cleanup handlers X-Git-Tag: 5.3.1dr1~16^2~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d36b30803e2ca313339b44e181efa46c925b51b8;p=thirdparty%2Fstrongswan.git thread: Add a function to pop and call all registered cleanup handlers --- diff --git a/src/libstrongswan/tests/suites/test_threading.c b/src/libstrongswan/tests/suites/test_threading.c index 55a4cd797a..9a9fdd8e9e 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 91a2d345d4..7a243e8262 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 38275541e3..c247728395 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 e76758f8c3..610524722d 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. */