Skip to content

Commit

Permalink
Cleaned up thread_base and added unit tests for lifecycle and global …
Browse files Browse the repository at this point in the history
…lock.
  • Loading branch information
rakshasa committed Dec 19, 2011
1 parent b713053 commit 5606af6
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 27 deletions.
7 changes: 2 additions & 5 deletions src/torrent/utils/thread_base.cc
Expand Up @@ -66,8 +66,7 @@ thread_base::start_thread() {

void*
thread_base::event_loop(thread_base* thread) {
thread->m_state = STATE_ACTIVE;
__sync_synchronize();
__sync_lock_test_and_set(&thread->m_state, STATE_ACTIVE);

try {

Expand All @@ -82,9 +81,7 @@ thread_base::event_loop(thread_base* thread) {
release_global_lock();
}

thread->m_state = STATE_INACTIVE;
__sync_synchronize();

__sync_lock_test_and_set(&thread->m_state, STATE_INACTIVE);
return NULL;
}

Expand Down
7 changes: 6 additions & 1 deletion src/torrent/utils/thread_base.h
Expand Up @@ -67,11 +67,11 @@ class LIBTORRENT_EXPORT thread_base {
virtual void init_thread() = 0;

virtual void start_thread();
// virtual void stop_thread();

static inline int global_queue_size() { return m_global.waiting; }

static inline void acquire_global_lock();
static inline bool trylock_global_lock();
static inline void release_global_lock();
static inline void waive_global_lock();

Expand Down Expand Up @@ -106,6 +106,11 @@ thread_base::acquire_global_lock() {
__sync_sub_and_fetch(&thread_base::m_global.waiting, 1);
}

inline bool
thread_base::trylock_global_lock() {
return pthread_mutex_trylock(&thread_base::m_global.lock) == 0;
}

inline void
thread_base::release_global_lock() {
pthread_mutex_unlock(&thread_base::m_global.lock);
Expand Down
79 changes: 58 additions & 21 deletions test/torrent/utils/thread_base_test.cc
Expand Up @@ -23,34 +23,38 @@ class thread_test : public torrent::thread_base {
TEST_STOP
};

static const int test_flag_pre_stop = 0x1;
static const int test_flag_do_shutdown = 0x2;
static const int test_flag_has_shutdown = 0x4;

static const int test_flag_acquire_global = 0x10;
static const int test_flag_has_global = 0x20;

thread_test();

int test_state() const { return m_test_state; }
bool is_state(int state) const { return m_state == state; }
bool is_test_state(int state) const { return m_test_state == state; }
bool is_test_flags(int flags) const { return m_test_flags == flags; }

void init_thread();

// static void stop_thread(thread_test* thread) { } // Queue throw_shutdown_exception...
void set_pre_stop() { __sync_or_and_fetch(&m_test_flags, test_flag_pre_stop); }
void set_shutdown() { __sync_or_and_fetch(&m_test_flags, test_flag_do_shutdown); }

void set_pre_stop() { m_set_pre_stop = true; __sync_synchronize(); }
void set_shutdown() { m_set_shutdown = true; __sync_synchronize(); }
void set_acquire_global() { __sync_or_and_fetch(&m_test_flags, test_flag_acquire_global); }

private:
void call_events();
int64_t next_timeout_usec() { return 100 * 1000; }

int m_test_state;
bool m_set_pre_stop;
bool m_set_shutdown;
bool m_has_shutdown;
int m_test_state lt_cacheline_aligned;
int m_test_flags lt_cacheline_aligned;
};

thread_test::thread_test() :
m_test_state(TEST_NONE),
m_set_pre_stop(false),
m_set_shutdown(false),
m_has_shutdown(false) {
m_test_flags(0) {
}

void
Expand All @@ -62,14 +66,20 @@ thread_test::init_thread() {

void
thread_test::call_events() {
if (m_set_pre_stop && m_test_state == TEST_PRE_START)
m_test_state = TEST_PRE_STOP;
if ((m_test_flags & test_flag_pre_stop) && m_test_state == TEST_PRE_START && m_state == STATE_ACTIVE)
__sync_lock_test_and_set(&m_test_state, TEST_PRE_STOP);

if (m_set_shutdown) {
if (m_has_shutdown)
throw torrent::internal_error("Already trigged shutdown.");

m_has_shutdown = true;
if ((m_test_flags & test_flag_acquire_global)) {
acquire_global_lock();
__sync_and_and_fetch(&m_test_flags, ~test_flag_acquire_global);
__sync_or_and_fetch(&m_test_flags, test_flag_has_global);
}

if ((m_test_flags & test_flag_has_shutdown))
throw torrent::internal_error("Already trigged shutdown.");

if ((m_test_flags & test_flag_do_shutdown)) {
__sync_or_and_fetch(&m_test_flags, test_flag_has_shutdown);
throw torrent::shutdown_exception();
}
}
Expand Down Expand Up @@ -127,12 +137,39 @@ utils_thread_base_test::test_lifecycle() {
CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_test_state, thread, thread_test::TEST_PRE_STOP)));

thread->set_shutdown();

CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_state, thread, thread_test::STATE_INACTIVE)));

delete thread;
}

// void
// utils_thread_base_test::test_global_lock...() {
// }
void
utils_thread_base_test::test_global_lock_basic() {
thread_test* thread = new thread_test;

thread->init_thread();
thread->start_thread();

// Acquire main thread...
CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());

torrent::thread_base::release_global_lock();
CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());

torrent::thread_base::release_global_lock();
torrent::thread_base::acquire_global_lock();
CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());

thread->set_acquire_global();
CPPUNIT_ASSERT(!wait_for_true(std::bind(&thread_test::is_test_flags, thread, thread_test::test_flag_has_global)));

torrent::thread_base::release_global_lock();
CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_test_flags, thread, thread_test::test_flag_has_global)));

CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
torrent::thread_base::release_global_lock();
CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());

// Test waive (loop).
}
4 changes: 4 additions & 0 deletions test/torrent/utils/thread_base_test.h
Expand Up @@ -6,6 +6,8 @@ class utils_thread_base_test : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(utils_thread_base_test);
CPPUNIT_TEST(test_basic);
CPPUNIT_TEST(test_lifecycle);

CPPUNIT_TEST(test_global_lock_basic);
CPPUNIT_TEST_SUITE_END();

public:
Expand All @@ -14,4 +16,6 @@ class utils_thread_base_test : public CppUnit::TestFixture {

void test_basic();
void test_lifecycle();

void test_global_lock_basic();
};

0 comments on commit 5606af6

Please sign in to comment.