From a4dd0ad63c00f4dee3b86dfd3075d1d61b2b3180 Mon Sep 17 00:00:00 2001 From: sanine Date: Sat, 27 Aug 2022 23:52:56 -0500 Subject: add plibsys --- 3rdparty/plibsys/tests/puthread_test.cpp | 481 +++++++++++++++++++++++++++++++ 1 file changed, 481 insertions(+) create mode 100644 3rdparty/plibsys/tests/puthread_test.cpp (limited to '3rdparty/plibsys/tests/puthread_test.cpp') diff --git a/3rdparty/plibsys/tests/puthread_test.cpp b/3rdparty/plibsys/tests/puthread_test.cpp new file mode 100644 index 0000000..5c31cd1 --- /dev/null +++ b/3rdparty/plibsys/tests/puthread_test.cpp @@ -0,0 +1,481 @@ +/* + * The MIT License + * + * Copyright (C) 2013-2019 Alexander Saprykin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * 'Software'), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "plibsys.h" +#include "ptestmacros.h" + +P_TEST_MODULE_INIT (); + +static pint thread_wakes_1 = 0; +static pint thread_wakes_2 = 0; +static pint thread_to_wakes = 0; +static volatile pboolean is_threads_working = FALSE; + +static P_HANDLE thread1_id = (P_HANDLE) NULL; +static P_HANDLE thread2_id = (P_HANDLE) NULL; +static PUThread * thread1_obj = NULL; +static PUThread * thread2_obj = NULL; + +static PUThreadKey * tls_key = NULL; +static PUThreadKey * tls_key_2 = NULL; +static volatile pint free_counter = 0; + +extern "C" ppointer pmem_alloc (psize nbytes) +{ + P_UNUSED (nbytes); + return (ppointer) NULL; +} + +extern "C" ppointer pmem_realloc (ppointer block, psize nbytes) +{ + P_UNUSED (block); + P_UNUSED (nbytes); + return (ppointer) NULL; +} + +extern "C" void pmem_free (ppointer block) +{ + P_UNUSED (block); +} + +extern "C" void free_with_check (ppointer mem) +{ + p_free (mem); + p_atomic_int_inc (&free_counter); +} + +static void * test_thread_func (void *data) +{ + pint *counter = static_cast < pint * > (data); + + if ((*counter) == 1) { + thread1_id = p_uthread_current_id (); + thread1_obj = p_uthread_current (); + } else { + thread2_id = p_uthread_current_id (); + thread2_obj = p_uthread_current (); + } + + p_uthread_set_local (tls_key, (ppointer) p_uthread_current_id ()); + + *counter = 0; + + while (is_threads_working == TRUE) { + p_uthread_sleep (10); + ++(*counter); + p_uthread_yield (); + + if (p_uthread_get_local (tls_key) != (ppointer) p_uthread_current_id ()) + p_uthread_exit (-1); + } + + p_uthread_exit (*counter); + + return NULL; +} + +static void * test_thread_nonjoinable_func (void *data) +{ + pint *counter = static_cast < pint * > (data); + + is_threads_working = TRUE; + + for (int i = thread_to_wakes; i > 0; --i) { + p_uthread_sleep (10); + ++(*counter); + p_uthread_yield (); + } + + is_threads_working = FALSE; + + p_uthread_exit (0); + + return NULL; +} + +static void * test_thread_tls_func (void *data) +{ + pint self_thread_free = *((pint *) data); + + pint *tls_value = (pint *) p_malloc0 (sizeof (pint)); + *tls_value = 0; + p_uthread_set_local (tls_key, (ppointer) tls_value); + + pint prev_tls = 0; + pint counter = 0; + + while (is_threads_working == TRUE) { + p_uthread_sleep (10); + + pint *last_tls = (pint *) p_uthread_get_local (tls_key); + + if ((*last_tls) != prev_tls) + p_uthread_exit (-1); + + pint *tls_new_value = (pint *) p_malloc0 (sizeof (pint)); + + *tls_new_value = (*last_tls) + 1; + prev_tls = (*last_tls) + 1; + + p_uthread_replace_local (tls_key, (ppointer) tls_new_value); + + if (self_thread_free) + p_free (last_tls); + + ++counter; + + p_uthread_yield (); + } + + if (self_thread_free) { + pint *last_tls = (pint *) p_uthread_get_local (tls_key); + + if ((*last_tls) != prev_tls) + p_uthread_exit (-1); + + p_free (last_tls); + + p_uthread_replace_local (tls_key, (ppointer) NULL); + } + + p_uthread_exit (counter); + + return NULL; +} + +static void * test_thread_tls_create_func (void *data) +{ + P_UNUSED (data); + + pint *tls_value = (pint *) p_malloc0 (sizeof (pint)); + *tls_value = 0; + p_uthread_set_local (tls_key, (ppointer) tls_value); + + pint *tls_value_2 = (pint *) p_malloc0 (sizeof (pint)); + *tls_value_2 = 0; + p_uthread_set_local (tls_key_2, (ppointer) tls_value_2); + + return NULL; +} + +P_TEST_CASE_BEGIN (puthread_nomem_test) +{ + p_libsys_init (); + + PUThreadKey *thread_key = p_uthread_local_new (p_free); + P_TEST_CHECK (thread_key != NULL); + + PMemVTable vtable; + + vtable.free = pmem_free; + vtable.malloc = pmem_alloc; + vtable.realloc = pmem_realloc; + + P_TEST_CHECK (p_mem_set_vtable (&vtable) == TRUE); + + thread_wakes_1 = 0; + thread_wakes_2 = 0; + + P_TEST_CHECK (p_uthread_create ((PUThreadFunc) test_thread_func, + (ppointer) &thread_wakes_1, + TRUE, + NULL) == NULL); + + P_TEST_CHECK (p_uthread_create_full ((PUThreadFunc) test_thread_func, + (ppointer) &thread_wakes_2, + TRUE, + P_UTHREAD_PRIORITY_NORMAL, + 0, + NULL) == NULL); + + P_TEST_CHECK (p_uthread_current () == NULL); + P_TEST_CHECK (p_uthread_local_new (NULL) == NULL); + + p_uthread_exit (0); + + p_uthread_set_local (thread_key, PINT_TO_POINTER (10)); + + ppointer tls_value = p_uthread_get_local (thread_key); + + if (tls_value != NULL) { + P_TEST_CHECK (tls_value == PINT_TO_POINTER (10)); + p_uthread_set_local (thread_key, NULL); + } + + p_uthread_replace_local (thread_key, PINT_TO_POINTER (12)); + + tls_value = p_uthread_get_local (thread_key); + + if (tls_value != NULL) { + P_TEST_CHECK (tls_value == PINT_TO_POINTER (12)); + p_uthread_set_local (thread_key, NULL); + } + + p_mem_restore_vtable (); + + p_uthread_local_free (thread_key); + + p_libsys_shutdown (); +} +P_TEST_CASE_END () + +P_TEST_CASE_BEGIN (puthread_bad_input_test) +{ + p_libsys_init (); + + P_TEST_CHECK (p_uthread_create (NULL, NULL, FALSE, NULL) == NULL); + P_TEST_CHECK (p_uthread_create_full (NULL, NULL, FALSE, P_UTHREAD_PRIORITY_NORMAL, 0, NULL) == NULL); + P_TEST_CHECK (p_uthread_join (NULL) == -1); + P_TEST_CHECK (p_uthread_set_priority (NULL, P_UTHREAD_PRIORITY_NORMAL) == FALSE); + P_TEST_CHECK (p_uthread_get_local (NULL) == NULL); + p_uthread_set_local (NULL, NULL); + p_uthread_replace_local (NULL, NULL); + p_uthread_ref (NULL); + p_uthread_unref (NULL); + p_uthread_local_free (NULL); + p_uthread_exit (0); + + p_libsys_shutdown (); +} +P_TEST_CASE_END () + +P_TEST_CASE_BEGIN (puthread_general_test) +{ + p_libsys_init (); + + thread_wakes_1 = 1; + thread_wakes_2 = 2; + thread1_id = (P_HANDLE) NULL; + thread2_id = (P_HANDLE) NULL; + thread1_obj = NULL; + thread2_obj = NULL; + + tls_key = p_uthread_local_new (NULL); + P_TEST_CHECK (tls_key != NULL); + + /* Threre is no guarantee that we wouldn't get one of the IDs + * of the finished test threads */ + + P_HANDLE main_id = p_uthread_current_id (); + + is_threads_working = TRUE; + + PUThread *thr1 = p_uthread_create_full ((PUThreadFunc) test_thread_func, + (ppointer) &thread_wakes_1, + TRUE, + P_UTHREAD_PRIORITY_NORMAL, + 64 * 1024, + "thread_name"); + + PUThread *thr2 = p_uthread_create_full ((PUThreadFunc) test_thread_func, + (ppointer) &thread_wakes_2, + TRUE, + P_UTHREAD_PRIORITY_NORMAL, + 64 * 1024, + "very_long_name_for_thread_testing"); + + p_uthread_ref (thr1); + + p_uthread_set_priority (thr1, P_UTHREAD_PRIORITY_NORMAL); + + P_TEST_REQUIRE (thr1 != NULL); + P_TEST_REQUIRE (thr2 != NULL); + + p_uthread_sleep (5000); + + is_threads_working = FALSE; + + P_TEST_CHECK (p_uthread_join (thr1) == thread_wakes_1); + P_TEST_CHECK (p_uthread_join (thr2) == thread_wakes_2); + + P_TEST_REQUIRE (thread1_id != thread2_id); + P_TEST_CHECK (thread1_id != main_id && thread2_id != main_id); + + P_TEST_CHECK (thread1_obj == thr1); + P_TEST_CHECK (thread2_obj == thr2); + + p_uthread_local_free (tls_key); + p_uthread_unref (thr1); + p_uthread_unref (thr2); + + p_uthread_unref (thr1); + + PUThread *cur_thr = p_uthread_current (); + P_TEST_CHECK (cur_thr != NULL); + + P_TEST_CHECK (p_uthread_ideal_count () > 0); + + p_libsys_shutdown (); +} +P_TEST_CASE_END () + +P_TEST_CASE_BEGIN (puthread_nonjoinable_test) +{ + p_libsys_init (); + + thread_wakes_1 = 0; + thread_to_wakes = 100; + is_threads_working = TRUE; + + PUThread *thr1 = p_uthread_create ((PUThreadFunc) test_thread_nonjoinable_func, + (ppointer) &thread_wakes_1, + FALSE, + NULL); + + P_TEST_REQUIRE (thr1 != NULL); + + p_uthread_sleep (3000); + + P_TEST_CHECK (p_uthread_join (thr1) == -1); + + while (is_threads_working == TRUE) + p_uthread_sleep (10); + + P_TEST_CHECK (thread_wakes_1 == thread_to_wakes); + + p_uthread_unref (thr1); + + p_libsys_shutdown (); +} +P_TEST_CASE_END () + +P_TEST_CASE_BEGIN (puthread_tls_test) +{ + p_libsys_init (); + + /* With destroy notification */ + tls_key = p_uthread_local_new (free_with_check); + + is_threads_working = TRUE; + free_counter = 0; + + pint self_thread_free = 0; + + PUThread *thr1 = p_uthread_create ((PUThreadFunc) test_thread_tls_func, + (ppointer) &self_thread_free, + TRUE, + NULL); + + PUThread *thr2 = p_uthread_create ((PUThreadFunc) test_thread_tls_func, + (ppointer) &self_thread_free, + TRUE, + NULL); + + P_TEST_REQUIRE (thr1 != NULL); + P_TEST_REQUIRE (thr2 != NULL); + + p_uthread_sleep (5000); + + is_threads_working = FALSE; + + pint total_counter = 0; + + total_counter += (p_uthread_join (thr1) + 1); + total_counter += (p_uthread_join (thr2) + 1); + + P_TEST_CHECK (total_counter == free_counter); + + p_uthread_local_free (tls_key); + p_uthread_unref (thr1); + p_uthread_unref (thr2); + + /* Without destroy notification */ + tls_key = p_uthread_local_new (NULL); + + free_counter = 0; + is_threads_working = TRUE; + self_thread_free = 1; + + thr1 = p_uthread_create ((PUThreadFunc) test_thread_tls_func, + (ppointer) &self_thread_free, + TRUE, + NULL); + + thr2 = p_uthread_create ((PUThreadFunc) test_thread_tls_func, + (ppointer) &self_thread_free, + TRUE, + NULL); + + P_TEST_REQUIRE (thr1 != NULL); + P_TEST_REQUIRE (thr2 != NULL); + + p_uthread_sleep (5000); + + is_threads_working = FALSE; + + total_counter = 0; + + total_counter += (p_uthread_join (thr1) + 1); + total_counter += (p_uthread_join (thr2) + 1); + + P_TEST_CHECK (total_counter > 0); + P_TEST_CHECK (free_counter == 0); + + p_uthread_local_free (tls_key); + p_uthread_unref (thr1); + p_uthread_unref (thr2); + + /* With implicit thread exit */ + tls_key = p_uthread_local_new (free_with_check); + tls_key_2 = p_uthread_local_new (free_with_check); + + free_counter = 0; + + thr1 = p_uthread_create ((PUThreadFunc) test_thread_tls_create_func, + NULL, + TRUE, + NULL); + + thr2 = p_uthread_create ((PUThreadFunc) test_thread_tls_create_func, + NULL, + TRUE, + NULL); + + P_TEST_REQUIRE (thr1 != NULL); + P_TEST_REQUIRE (thr2 != NULL); + + p_uthread_join (thr1); + p_uthread_join (thr2); + + P_TEST_CHECK (free_counter == 4); + + p_uthread_local_free (tls_key); + p_uthread_local_free (tls_key_2); + p_uthread_unref (thr1); + p_uthread_unref (thr2); + + p_libsys_shutdown (); +} +P_TEST_CASE_END () + +P_TEST_SUITE_BEGIN() +{ + P_TEST_SUITE_RUN_CASE (puthread_nomem_test); + P_TEST_SUITE_RUN_CASE (puthread_bad_input_test); + P_TEST_SUITE_RUN_CASE (puthread_general_test); + P_TEST_SUITE_RUN_CASE (puthread_nonjoinable_test); + P_TEST_SUITE_RUN_CASE (puthread_tls_test); +} +P_TEST_SUITE_END() -- cgit v1.2.1