1 #include <cppunit/extensions/HelperMacros.h>
2 
3 #include "torrent/utils/thread_base.h"
4 
5 class utils_thread_base_test : public CppUnit::TestFixture {
6   CPPUNIT_TEST_SUITE(utils_thread_base_test);
7   CPPUNIT_TEST(test_basic);
8   CPPUNIT_TEST(test_lifecycle);
9 
10   CPPUNIT_TEST(test_global_lock_basic);
11   CPPUNIT_TEST(test_interrupt);
12   CPPUNIT_TEST(test_stop);
13   CPPUNIT_TEST_SUITE_END();
14 
15 public:
16   void setUp();
17   void tearDown();
18 
19   void test_basic();
20   void test_lifecycle();
21 
22   void test_global_lock_basic();
23   void test_interrupt();
24   void test_interrupt_legacy();
25   void test_stop();
26 };
27 
28 struct thread_management_type {
thread_management_typethread_management_type29   thread_management_type() { CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock()); }
~thread_management_typethread_management_type30   ~thread_management_type() { torrent::thread_base::release_global_lock(); }
31 };
32 
33 #define SETUP_THREAD()                                                  \
34   thread_management_type thread_management;                             \
35   torrent::thread_disk* thread_disk = new torrent::thread_disk();       \
36   thread_disk->init_thread();
37 
38 #define CLEANUP_THREAD()                                                \
39   CPPUNIT_ASSERT(wait_for_true(std::bind(&torrent::thread_base::is_inactive, thread_disk))); \
40   delete thread_disk;
41 
42 bool wait_for_true(std::function<bool ()> test_function);
43 
44 class thread_test : public torrent::thread_base {
45 public:
46   enum test_state {
47     TEST_NONE,
48     TEST_PRE_START,
49     TEST_PRE_STOP,
50     TEST_STOP
51   };
52 
53   static const int test_flag_pre_stop       = 0x1;
54   static const int test_flag_long_timeout   = 0x2;
55 
56   static const int test_flag_acquire_global = 0x10;
57   static const int test_flag_has_global     = 0x20;
58 
59   static const int test_flag_do_work   = 0x100;
60   static const int test_flag_pre_poke  = 0x200;
61   static const int test_flag_post_poke = 0x400;
62 
63   thread_test();
64 
test_state()65   int                 test_state() const { return m_test_state; }
is_state(int state)66   bool                is_state(int state) const { return m_state == state; }
is_test_state(int state)67   bool                is_test_state(int state) const { return m_test_state == state; }
is_test_flags(int flags)68   bool                is_test_flags(int flags) const { return (m_test_flags & flags) == flags; }
is_not_test_flags(int flags)69   bool                is_not_test_flags(int flags) const { return !(m_test_flags & flags); }
70 
name()71   const char*         name() const { return "test_thread"; }
72 
73   void                init_thread();
74 
set_pre_stop()75   void                set_pre_stop() { __sync_or_and_fetch(&m_test_flags, test_flag_pre_stop); }
set_acquire_global()76   void                set_acquire_global() { __sync_or_and_fetch(&m_test_flags, test_flag_acquire_global); }
77 
set_test_flag(int flags)78   void                set_test_flag(int flags) { __sync_or_and_fetch(&m_test_flags, flags); }
79 
80 private:
81   void                call_events();
next_timeout_usec()82   int64_t             next_timeout_usec() { return (m_test_flags & test_flag_long_timeout) ? (10000 * 1000) : (100 * 1000); }
83 
84   int                 m_test_state lt_cacheline_aligned;
85   int                 m_test_flags lt_cacheline_aligned;
86 };
87