diff options
author | Nick Mathewson <nickm@torproject.org> | 2013-09-27 23:15:53 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2015-01-14 11:17:09 -0500 |
commit | 7a63005220938b30df41b51334942d7d79c14cf9 (patch) | |
tree | e1d3671a8d7a7cd195c7a4b307f2c7288b9211f3 /src/test | |
parent | e47a90a976f883571bea6e58620aa13f058873e3 (diff) | |
download | tor-7a63005220938b30df41b51334942d7d79c14cf9.tar.gz tor-7a63005220938b30df41b51334942d7d79c14cf9.zip |
Basic unit test for condition variables.
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/test.c | 18 | ||||
-rw-r--r-- | src/test/test.h | 2 | ||||
-rw-r--r-- | src/test/test_crypto.c | 36 | ||||
-rw-r--r-- | src/test/test_threads.c | 150 | ||||
-rw-r--r-- | src/test/test_util.c | 21 |
5 files changed, 182 insertions, 45 deletions
diff --git a/src/test/test.c b/src/test/test.c index edc28cd2d4..9171306d18 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1258,6 +1258,24 @@ test_stats(void *arg) tor_free(s); } + +static void * +passthrough_test_setup(const struct testcase_t *testcase) +{ + return testcase->setup_data; +} +static int +passthrough_test_cleanup(const struct testcase_t *testcase, void *ptr) +{ + (void)testcase; + (void)ptr; + return 1; +} + +const struct testcase_setup_t passthrough_setup = { + passthrough_test_setup, passthrough_test_cleanup +}; + #define ENT(name) \ { #name, test_ ## name , 0, NULL, NULL } #define FORK(name) \ diff --git a/src/test/test.h b/src/test/test.h index 48037a5ba3..b8057c59bf 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -158,5 +158,7 @@ crypto_pk_t *pk_generate(int idx); #define NS_MOCK(name) MOCK(name, NS(name)) #define NS_UNMOCK(name) UNMOCK(name) +extern const struct testcase_setup_t passthrough_setup; + #endif diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 4a5a12c50a..8426c715a4 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -1975,30 +1975,14 @@ test_crypto_siphash(void *arg) ; } -static void * -pass_data_setup_fn(const struct testcase_t *testcase) -{ - return testcase->setup_data; -} -static int -pass_data_cleanup_fn(const struct testcase_t *testcase, void *ptr) -{ - (void)ptr; - (void)testcase; - return 1; -} -static const struct testcase_setup_t pass_data = { - pass_data_setup_fn, pass_data_cleanup_fn -}; - #define CRYPTO_LEGACY(name) \ { #name, test_crypto_ ## name , 0, NULL, NULL } struct testcase_t crypto_tests[] = { CRYPTO_LEGACY(formats), CRYPTO_LEGACY(rng), - { "aes_AES", test_crypto_aes, TT_FORK, &pass_data, (void*)"aes" }, - { "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" }, + { "aes_AES", test_crypto_aes, TT_FORK, &passthrough_setup, (void*)"aes" }, + { "aes_EVP", test_crypto_aes, TT_FORK, &passthrough_setup, (void*)"evp" }, CRYPTO_LEGACY(sha), CRYPTO_LEGACY(pk), { "pk_fingerprints", test_crypto_pk_fingerprints, TT_FORK, NULL, NULL }, @@ -2006,23 +1990,25 @@ struct testcase_t crypto_tests[] = { CRYPTO_LEGACY(dh), CRYPTO_LEGACY(s2k_rfc2440), #ifdef HAVE_LIBSCRYPT_H - { "s2k_scrypt", test_crypto_s2k_general, 0, &pass_data, + { "s2k_scrypt", test_crypto_s2k_general, 0, &passthrough_setup, (void*)"scrypt" }, - { "s2k_scrypt_low", test_crypto_s2k_general, 0, &pass_data, + { "s2k_scrypt_low", test_crypto_s2k_general, 0, &passthrough_setup, (void*)"scrypt-low" }, #endif - { "s2k_pbkdf2", test_crypto_s2k_general, 0, &pass_data, + { "s2k_pbkdf2", test_crypto_s2k_general, 0, &passthrough_setup, (void*)"pbkdf2" }, - { "s2k_rfc2440_general", test_crypto_s2k_general, 0, &pass_data, + { "s2k_rfc2440_general", test_crypto_s2k_general, 0, &passthrough_setup, (void*)"rfc2440" }, - { "s2k_rfc2440_legacy", test_crypto_s2k_general, 0, &pass_data, + { "s2k_rfc2440_legacy", test_crypto_s2k_general, 0, &passthrough_setup, (void*)"rfc2440-legacy" }, { "s2k_errors", test_crypto_s2k_errors, 0, NULL, NULL }, { "scrypt_vectors", test_crypto_scrypt_vectors, 0, NULL, NULL }, { "pbkdf2_vectors", test_crypto_pbkdf2_vectors, 0, NULL, NULL }, { "pwbox", test_crypto_pwbox, 0, NULL, NULL }, - { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" }, - { "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"evp" }, + { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &passthrough_setup, + (void*)"aes" }, + { "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &passthrough_setup, + (void*)"evp" }, CRYPTO_LEGACY(base32_decode), { "kdf_TAP", test_crypto_kdf_TAP, 0, NULL, NULL }, { "hkdf_sha256", test_crypto_hkdf_sha256, 0, NULL, NULL }, diff --git a/src/test/test_threads.c b/src/test/test_threads.c index 2b4c93393f..d2a61a17d0 100644 --- a/src/test/test_threads.c +++ b/src/test/test_threads.c @@ -144,11 +144,159 @@ test_threads_basic(void *arg) tor_mutex_free(thread_test_start2_); } -#define THREAD_TEST(name) \ +typedef struct cv_testinfo_s { + tor_cond_t *cond; + tor_mutex_t *mutex; + int value; + int addend; + int shutdown; + int n_shutdown; + int n_wakeups; + int n_timeouts; + int n_threads; + const struct timeval *tv; +} cv_testinfo_t; + +static cv_testinfo_t * +cv_testinfo_new(void) +{ + cv_testinfo_t *i = tor_malloc_zero(sizeof(*i)); + i->cond = tor_cond_new(); + i->mutex = tor_mutex_new_nonrecursive(); + return i; +} + +static void +cv_testinfo_free(cv_testinfo_t *i) +{ + if (!i) + return; + tor_cond_free(i->cond); + tor_mutex_free(i->mutex); + tor_free(i); +} + +static void cv_test_thr_fn_(void *arg) ATTR_NORETURN; + +static void +cv_test_thr_fn_(void *arg) +{ + cv_testinfo_t *i = arg; + int tid, r; + + tor_mutex_acquire(i->mutex); + tid = i->n_threads++; + tor_mutex_release(i->mutex); + (void) tid; + + tor_mutex_acquire(i->mutex); + while (1) { + if (i->addend) { + i->value += i->addend; + i->addend = 0; + } + + if (i->shutdown) { + ++i->n_shutdown; + i->shutdown = 0; + tor_mutex_release(i->mutex); + spawn_exit(); + } + r = tor_cond_wait(i->cond, i->mutex, i->tv); + ++i->n_wakeups; + if (r == 1) { + ++i->n_timeouts; + tor_mutex_release(i->mutex); + spawn_exit(); + } + } +} + +static void +test_threads_conditionvar(void *arg) +{ + cv_testinfo_t *ti=NULL; + const struct timeval msec100 = { 0, 100*1000 }; + const int timeout = !strcmp(arg, "tv"); + + ti = cv_testinfo_new(); + if (timeout) { + ti->tv = &msec100; + } + spawn_func(cv_test_thr_fn_, ti); + spawn_func(cv_test_thr_fn_, ti); + spawn_func(cv_test_thr_fn_, ti); + spawn_func(cv_test_thr_fn_, ti); + + tor_mutex_acquire(ti->mutex); + ti->addend = 7; + ti->shutdown = 1; + tor_cond_signal_one(ti->cond); + tor_mutex_release(ti->mutex); + +#define SPIN() \ + while (1) { \ + tor_mutex_acquire(ti->mutex); \ + if (ti->addend == 0) { \ + break; \ + } \ + tor_mutex_release(ti->mutex); \ + } + + SPIN(); + + ti->addend = 30; + ti->shutdown = 1; + tor_cond_signal_all(ti->cond); + tor_mutex_release(ti->mutex); + SPIN(); + + ti->addend = 1000; + if (! timeout) ti->shutdown = 1; + tor_cond_signal_one(ti->cond); + tor_mutex_release(ti->mutex); + SPIN(); + ti->addend = 300; + if (! timeout) ti->shutdown = 1; + tor_cond_signal_all(ti->cond); + tor_mutex_release(ti->mutex); + + SPIN(); + tor_mutex_release(ti->mutex); + + tt_int_op(ti->value, ==, 1337); + if (!timeout) { + tt_int_op(ti->n_shutdown, ==, 4); + } else { +#ifdef _WIN32 + Sleep(500); /* msec */ +#elif defined(HAVE_USLEEP) + usleep(500*1000); /* usec */ +#else + { + struct tv = { 0, 500*1000 }; + select(0, NULL, NULL, NULL, &tv); + } +#endif + tor_mutex_acquire(ti->mutex); + tt_int_op(ti->n_shutdown, ==, 2); + tt_int_op(ti->n_timeouts, ==, 2); + tor_mutex_release(ti->mutex); + } + + done: + cv_testinfo_free(ti); +} + +#define THREAD_TEST(name) \ { #name, test_threads_##name, TT_FORK, NULL, NULL } struct testcase_t thread_tests[] = { THREAD_TEST(basic), + { "conditionvar", test_threads_conditionvar, TT_FORK, + &passthrough_setup, (void*)"no-tv" }, + { "conditionvar_timeout", test_threads_conditionvar, TT_FORK, + &passthrough_setup, (void*)"tv" }, END_OF_TESTCASES }; diff --git a/src/test/test_util.c b/src/test/test_util.c index b4ee934698..97cf3870f4 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -4646,23 +4646,6 @@ test_util_socket(void *arg) tor_close_socket(fd4); } -static void * -socketpair_test_setup(const struct testcase_t *testcase) -{ - return testcase->setup_data; -} -static int -socketpair_test_cleanup(const struct testcase_t *testcase, void *ptr) -{ - (void)testcase; - (void)ptr; - return 1; -} - -static const struct testcase_setup_t socketpair_setup = { - socketpair_test_setup, socketpair_test_cleanup -}; - /* Test for socketpair and ersatz_socketpair(). We test them both, since * the latter is a tolerably good way to exersize tor_accept_socket(). */ static void @@ -4837,10 +4820,10 @@ struct testcase_t util_tests[] = { UTIL_TEST(mathlog, 0), UTIL_TEST(weak_random, 0), UTIL_TEST(socket, TT_FORK), - { "socketpair", test_util_socketpair, TT_FORK, &socketpair_setup, + { "socketpair", test_util_socketpair, TT_FORK, &passthrough_setup, (void*)"0" }, { "socketpair_ersatz", test_util_socketpair, TT_FORK, - &socketpair_setup, (void*)"1" }, + &passthrough_setup, (void*)"1" }, UTIL_TEST(max_mem, 0), UTIL_TEST(hostname_validation, 0), UTIL_TEST(ipv4_validation, 0), |