aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2013-09-27 23:15:53 -0400
committerNick Mathewson <nickm@torproject.org>2015-01-14 11:17:09 -0500
commit7a63005220938b30df41b51334942d7d79c14cf9 (patch)
treee1d3671a8d7a7cd195c7a4b307f2c7288b9211f3
parente47a90a976f883571bea6e58620aa13f058873e3 (diff)
downloadtor-7a63005220938b30df41b51334942d7d79c14cf9.tar.gz
tor-7a63005220938b30df41b51334942d7d79c14cf9.zip
Basic unit test for condition variables.
-rw-r--r--configure.ac2
-rw-r--r--src/test/test.c18
-rw-r--r--src/test/test.h2
-rw-r--r--src/test/test_crypto.c36
-rw-r--r--src/test/test_threads.c150
-rw-r--r--src/test/test_util.c21
6 files changed, 183 insertions, 46 deletions
diff --git a/configure.ac b/configure.ac
index 69a266a717..929b701594 100644
--- a/configure.ac
+++ b/configure.ac
@@ -437,7 +437,7 @@ AC_CHECK_FUNCS(
sysconf \
sysctl \
uname \
- usleep \
+ usleep \
vasprintf \
_vscprintf
)
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),