mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
Move thread tests into their own module
This commit is contained in:
parent
c51f7c23e3
commit
74b782645a
@ -46,6 +46,7 @@ src_test_test_SOURCES = \
|
||||
src/test/test_routerkeys.c \
|
||||
src/test/test_scheduler.c \
|
||||
src/test/test_socks.c \
|
||||
src/test/test_threads.c \
|
||||
src/test/test_util.c \
|
||||
src/test/test_config.c \
|
||||
src/test/test_hs.c \
|
||||
|
@ -1297,6 +1297,7 @@ extern struct testcase_t cell_queue_tests[];
|
||||
extern struct testcase_t options_tests[];
|
||||
extern struct testcase_t socks_tests[];
|
||||
extern struct testcase_t entrynodes_tests[];
|
||||
extern struct testcase_t thread_tests[];
|
||||
extern struct testcase_t extorport_tests[];
|
||||
extern struct testcase_t controller_event_tests[];
|
||||
extern struct testcase_t logging_tests[];
|
||||
@ -1323,6 +1324,7 @@ static struct testgroup_t testgroups[] = {
|
||||
{ "container/", container_tests },
|
||||
{ "util/", util_tests },
|
||||
{ "util/logging/", logging_tests },
|
||||
{ "util/thread/", thread_tests },
|
||||
{ "cellfmt/", cell_format_tests },
|
||||
{ "cellqueue/", cell_queue_tests },
|
||||
{ "dir/", dir_tests },
|
||||
|
154
src/test/test_threads.c
Normal file
154
src/test/test_threads.c
Normal file
@ -0,0 +1,154 @@
|
||||
/* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "or.h"
|
||||
#include "compat_threads.h"
|
||||
#include "test.h"
|
||||
|
||||
/** mutex for thread test to stop the threads hitting data at the same time. */
|
||||
static tor_mutex_t *thread_test_mutex_ = NULL;
|
||||
/** mutexes for the thread test to make sure that the threads have to
|
||||
* interleave somewhat. */
|
||||
static tor_mutex_t *thread_test_start1_ = NULL,
|
||||
*thread_test_start2_ = NULL;
|
||||
/** Shared strmap for the thread test. */
|
||||
static strmap_t *thread_test_strmap_ = NULL;
|
||||
/** The name of thread1 for the thread test */
|
||||
static char *thread1_name_ = NULL;
|
||||
/** The name of thread2 for the thread test */
|
||||
static char *thread2_name_ = NULL;
|
||||
|
||||
static void thread_test_func_(void* _s) ATTR_NORETURN;
|
||||
|
||||
/** How many iterations have the threads in the unit test run? */
|
||||
static int t1_count = 0, t2_count = 0;
|
||||
|
||||
/** Helper function for threading unit tests: This function runs in a
|
||||
* subthread. It grabs its own mutex (start1 or start2) to make sure that it
|
||||
* should start, then it repeatedly alters _test_thread_strmap protected by
|
||||
* thread_test_mutex_. */
|
||||
static void
|
||||
thread_test_func_(void* _s)
|
||||
{
|
||||
char *s = _s;
|
||||
int i, *count;
|
||||
tor_mutex_t *m;
|
||||
char buf[64];
|
||||
char **cp;
|
||||
if (!strcmp(s, "thread 1")) {
|
||||
m = thread_test_start1_;
|
||||
cp = &thread1_name_;
|
||||
count = &t1_count;
|
||||
} else {
|
||||
m = thread_test_start2_;
|
||||
cp = &thread2_name_;
|
||||
count = &t2_count;
|
||||
}
|
||||
|
||||
tor_snprintf(buf, sizeof(buf), "%lu", tor_get_thread_id());
|
||||
*cp = tor_strdup(buf);
|
||||
|
||||
tor_mutex_acquire(m);
|
||||
|
||||
for (i=0; i<10000; ++i) {
|
||||
tor_mutex_acquire(thread_test_mutex_);
|
||||
strmap_set(thread_test_strmap_, "last to run", *cp);
|
||||
++*count;
|
||||
tor_mutex_release(thread_test_mutex_);
|
||||
}
|
||||
tor_mutex_acquire(thread_test_mutex_);
|
||||
strmap_set(thread_test_strmap_, s, *cp);
|
||||
tor_mutex_release(thread_test_mutex_);
|
||||
|
||||
tor_mutex_release(m);
|
||||
|
||||
spawn_exit();
|
||||
}
|
||||
|
||||
/** Run unit tests for threading logic. */
|
||||
static void
|
||||
test_threads_basic(void *arg)
|
||||
{
|
||||
char *s1 = NULL, *s2 = NULL;
|
||||
int done = 0, timedout = 0;
|
||||
time_t started;
|
||||
#ifndef _WIN32
|
||||
struct timeval tv;
|
||||
tv.tv_sec=0;
|
||||
tv.tv_usec=100*1000;
|
||||
#endif
|
||||
(void)arg;
|
||||
thread_test_mutex_ = tor_mutex_new();
|
||||
thread_test_start1_ = tor_mutex_new();
|
||||
thread_test_start2_ = tor_mutex_new();
|
||||
thread_test_strmap_ = strmap_new();
|
||||
s1 = tor_strdup("thread 1");
|
||||
s2 = tor_strdup("thread 2");
|
||||
tor_mutex_acquire(thread_test_start1_);
|
||||
tor_mutex_acquire(thread_test_start2_);
|
||||
spawn_func(thread_test_func_, s1);
|
||||
spawn_func(thread_test_func_, s2);
|
||||
tor_mutex_release(thread_test_start2_);
|
||||
tor_mutex_release(thread_test_start1_);
|
||||
started = time(NULL);
|
||||
while (!done) {
|
||||
tor_mutex_acquire(thread_test_mutex_);
|
||||
strmap_assert_ok(thread_test_strmap_);
|
||||
if (strmap_get(thread_test_strmap_, "thread 1") &&
|
||||
strmap_get(thread_test_strmap_, "thread 2")) {
|
||||
done = 1;
|
||||
} else if (time(NULL) > started + 150) {
|
||||
timedout = done = 1;
|
||||
}
|
||||
tor_mutex_release(thread_test_mutex_);
|
||||
#ifndef _WIN32
|
||||
/* Prevent the main thread from starving the worker threads. */
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
#endif
|
||||
}
|
||||
tor_mutex_acquire(thread_test_start1_);
|
||||
tor_mutex_release(thread_test_start1_);
|
||||
tor_mutex_acquire(thread_test_start2_);
|
||||
tor_mutex_release(thread_test_start2_);
|
||||
|
||||
tor_mutex_free(thread_test_mutex_);
|
||||
|
||||
if (timedout) {
|
||||
printf("\nTimed out: %d %d", t1_count, t2_count);
|
||||
tt_assert(strmap_get(thread_test_strmap_, "thread 1"));
|
||||
tt_assert(strmap_get(thread_test_strmap_, "thread 2"));
|
||||
tt_assert(!timedout);
|
||||
}
|
||||
|
||||
/* different thread IDs. */
|
||||
tt_assert(strcmp(strmap_get(thread_test_strmap_, "thread 1"),
|
||||
strmap_get(thread_test_strmap_, "thread 2")));
|
||||
tt_assert(!strcmp(strmap_get(thread_test_strmap_, "thread 1"),
|
||||
strmap_get(thread_test_strmap_, "last to run")) ||
|
||||
!strcmp(strmap_get(thread_test_strmap_, "thread 2"),
|
||||
strmap_get(thread_test_strmap_, "last to run")));
|
||||
|
||||
done:
|
||||
tor_free(s1);
|
||||
tor_free(s2);
|
||||
tor_free(thread1_name_);
|
||||
tor_free(thread2_name_);
|
||||
if (thread_test_strmap_)
|
||||
strmap_free(thread_test_strmap_, NULL);
|
||||
if (thread_test_start1_)
|
||||
tor_mutex_free(thread_test_start1_);
|
||||
if (thread_test_start2_)
|
||||
tor_mutex_free(thread_test_start2_);
|
||||
}
|
||||
|
||||
#define THREAD_TEST(name) \
|
||||
{ #name, test_threads_##name, TT_FORK, NULL, NULL }
|
||||
|
||||
struct testcase_t thread_tests[] = {
|
||||
THREAD_TEST(basic),
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
@ -1607,142 +1607,6 @@ test_util_pow2(void *arg)
|
||||
;
|
||||
}
|
||||
|
||||
/** mutex for thread test to stop the threads hitting data at the same time. */
|
||||
static tor_mutex_t *thread_test_mutex_ = NULL;
|
||||
/** mutexes for the thread test to make sure that the threads have to
|
||||
* interleave somewhat. */
|
||||
static tor_mutex_t *thread_test_start1_ = NULL,
|
||||
*thread_test_start2_ = NULL;
|
||||
/** Shared strmap for the thread test. */
|
||||
static strmap_t *thread_test_strmap_ = NULL;
|
||||
/** The name of thread1 for the thread test */
|
||||
static char *thread1_name_ = NULL;
|
||||
/** The name of thread2 for the thread test */
|
||||
static char *thread2_name_ = NULL;
|
||||
|
||||
static void thread_test_func_(void* _s) ATTR_NORETURN;
|
||||
|
||||
/** How many iterations have the threads in the unit test run? */
|
||||
static int t1_count = 0, t2_count = 0;
|
||||
|
||||
/** Helper function for threading unit tests: This function runs in a
|
||||
* subthread. It grabs its own mutex (start1 or start2) to make sure that it
|
||||
* should start, then it repeatedly alters _test_thread_strmap protected by
|
||||
* thread_test_mutex_. */
|
||||
static void
|
||||
thread_test_func_(void* _s)
|
||||
{
|
||||
char *s = _s;
|
||||
int i, *count;
|
||||
tor_mutex_t *m;
|
||||
char buf[64];
|
||||
char **cp;
|
||||
if (!strcmp(s, "thread 1")) {
|
||||
m = thread_test_start1_;
|
||||
cp = &thread1_name_;
|
||||
count = &t1_count;
|
||||
} else {
|
||||
m = thread_test_start2_;
|
||||
cp = &thread2_name_;
|
||||
count = &t2_count;
|
||||
}
|
||||
|
||||
tor_snprintf(buf, sizeof(buf), "%lu", tor_get_thread_id());
|
||||
*cp = tor_strdup(buf);
|
||||
|
||||
tor_mutex_acquire(m);
|
||||
|
||||
for (i=0; i<10000; ++i) {
|
||||
tor_mutex_acquire(thread_test_mutex_);
|
||||
strmap_set(thread_test_strmap_, "last to run", *cp);
|
||||
++*count;
|
||||
tor_mutex_release(thread_test_mutex_);
|
||||
}
|
||||
tor_mutex_acquire(thread_test_mutex_);
|
||||
strmap_set(thread_test_strmap_, s, *cp);
|
||||
tor_mutex_release(thread_test_mutex_);
|
||||
|
||||
tor_mutex_release(m);
|
||||
|
||||
spawn_exit();
|
||||
}
|
||||
|
||||
/** Run unit tests for threading logic. */
|
||||
static void
|
||||
test_util_threads(void *arg)
|
||||
{
|
||||
char *s1 = NULL, *s2 = NULL;
|
||||
int done = 0, timedout = 0;
|
||||
time_t started;
|
||||
#ifndef _WIN32
|
||||
struct timeval tv;
|
||||
tv.tv_sec=0;
|
||||
tv.tv_usec=100*1000;
|
||||
#endif
|
||||
(void)arg;
|
||||
thread_test_mutex_ = tor_mutex_new();
|
||||
thread_test_start1_ = tor_mutex_new();
|
||||
thread_test_start2_ = tor_mutex_new();
|
||||
thread_test_strmap_ = strmap_new();
|
||||
s1 = tor_strdup("thread 1");
|
||||
s2 = tor_strdup("thread 2");
|
||||
tor_mutex_acquire(thread_test_start1_);
|
||||
tor_mutex_acquire(thread_test_start2_);
|
||||
spawn_func(thread_test_func_, s1);
|
||||
spawn_func(thread_test_func_, s2);
|
||||
tor_mutex_release(thread_test_start2_);
|
||||
tor_mutex_release(thread_test_start1_);
|
||||
started = time(NULL);
|
||||
while (!done) {
|
||||
tor_mutex_acquire(thread_test_mutex_);
|
||||
strmap_assert_ok(thread_test_strmap_);
|
||||
if (strmap_get(thread_test_strmap_, "thread 1") &&
|
||||
strmap_get(thread_test_strmap_, "thread 2")) {
|
||||
done = 1;
|
||||
} else if (time(NULL) > started + 150) {
|
||||
timedout = done = 1;
|
||||
}
|
||||
tor_mutex_release(thread_test_mutex_);
|
||||
#ifndef _WIN32
|
||||
/* Prevent the main thread from starving the worker threads. */
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
#endif
|
||||
}
|
||||
tor_mutex_acquire(thread_test_start1_);
|
||||
tor_mutex_release(thread_test_start1_);
|
||||
tor_mutex_acquire(thread_test_start2_);
|
||||
tor_mutex_release(thread_test_start2_);
|
||||
|
||||
tor_mutex_free(thread_test_mutex_);
|
||||
|
||||
if (timedout) {
|
||||
printf("\nTimed out: %d %d", t1_count, t2_count);
|
||||
tt_assert(strmap_get(thread_test_strmap_, "thread 1"));
|
||||
tt_assert(strmap_get(thread_test_strmap_, "thread 2"));
|
||||
tt_assert(!timedout);
|
||||
}
|
||||
|
||||
/* different thread IDs. */
|
||||
tt_assert(strcmp(strmap_get(thread_test_strmap_, "thread 1"),
|
||||
strmap_get(thread_test_strmap_, "thread 2")));
|
||||
tt_assert(!strcmp(strmap_get(thread_test_strmap_, "thread 1"),
|
||||
strmap_get(thread_test_strmap_, "last to run")) ||
|
||||
!strcmp(strmap_get(thread_test_strmap_, "thread 2"),
|
||||
strmap_get(thread_test_strmap_, "last to run")));
|
||||
|
||||
done:
|
||||
tor_free(s1);
|
||||
tor_free(s2);
|
||||
tor_free(thread1_name_);
|
||||
tor_free(thread2_name_);
|
||||
if (thread_test_strmap_)
|
||||
strmap_free(thread_test_strmap_, NULL);
|
||||
if (thread_test_start1_)
|
||||
tor_mutex_free(thread_test_start1_);
|
||||
if (thread_test_start2_)
|
||||
tor_mutex_free(thread_test_start2_);
|
||||
}
|
||||
|
||||
/** Run unit tests for compression functions */
|
||||
static void
|
||||
test_util_gzip(void *arg)
|
||||
@ -4927,7 +4791,6 @@ struct testcase_t util_tests[] = {
|
||||
UTIL_LEGACY(memarea),
|
||||
UTIL_LEGACY(control_formats),
|
||||
UTIL_LEGACY(mmap),
|
||||
UTIL_LEGACY(threads),
|
||||
UTIL_LEGACY(sscanf),
|
||||
UTIL_LEGACY(format_time_interval),
|
||||
UTIL_LEGACY(path_is_relative),
|
||||
|
Loading…
Reference in New Issue
Block a user