libmoost
|
00001 /* vim:set ts=3 sw=3 sts=3 et: */ 00028 #include <csignal> 00029 #include <vector> 00030 #include <string> 00031 00032 #include <boost/test/unit_test.hpp> 00033 #include <boost/thread.hpp> 00034 #include <boost/bind.hpp> 00035 00036 #include "../../include/moost/pdl/dynamic_library.h" 00037 #include "../../include/moost/safe_shared_ptr.hpp" 00038 00039 #include "test_interface.h" 00040 00041 BOOST_AUTO_TEST_SUITE(moost_pdl_multithread) 00042 00043 namespace 00044 { 00045 00046 // mmmmh, maybe we can turn this into a stand-alone template? 00047 template <typename T> 00048 class atomic 00049 { 00050 public: 00051 atomic() 00052 : m_value(0) 00053 { 00054 } 00055 00056 atomic& operator++ () 00057 { 00058 atomic_add_and_fetch(1); 00059 return *this; 00060 } 00061 00062 T read() 00063 { 00064 return atomic_add_and_fetch(0); 00065 } 00066 00067 private: 00068 volatile T m_value; 00069 00070 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) 00071 T atomic_add_and_fetch(T x) 00072 { 00073 return __sync_add_and_fetch(&m_value, x); 00074 } 00075 #else 00076 boost::mutex m_mutex; 00077 00078 T atomic_add_and_fetch(T x) 00079 { 00080 boost::mutex::scoped_lock lock(m_mutex); 00081 m_value += x; 00082 return m_value; 00083 } 00084 #endif 00085 }; 00086 00087 atomic<unsigned> c3_load; 00088 atomic<unsigned> c3_unload; 00089 atomic<unsigned> c3_ctor; 00090 atomic<unsigned> c3_dtor; 00091 00092 atomic<unsigned> c4_load; 00093 atomic<unsigned> c4_unload; 00094 atomic<unsigned> c4_ctor; 00095 atomic<unsigned> c4_dtor; 00096 00097 class multithread_pdl_test 00098 { 00099 public: 00100 multithread_pdl_test(const std::vector<std::string>& libs) 00101 : m_finish(0) 00102 , m_lib_counter(0) 00103 , m_libs(libs) 00104 { 00105 reload(true); 00106 } 00107 00108 void reload(bool force) 00109 { 00110 if (force) 00111 { 00112 m_dl.open(m_libs[m_lib_counter++ % m_libs.size()]); 00113 } 00114 00115 m_inst = m_dl.create<my_test_interface>("my_test_class"); 00116 } 00117 00118 void process() 00119 { 00120 boost::shared_ptr<my_test_interface> inst = m_inst.get_shared(); 00121 00122 for (size_t i = 0; i < 10; ++i) 00123 { 00124 inst->do_it(); 00125 } 00126 } 00127 00128 void processor_thread() 00129 { 00130 while (!m_finish) 00131 { 00132 process(); 00133 } 00134 } 00135 00136 void run(size_t num_threads = 37) 00137 { 00138 boost::thread_group tg; 00139 00140 for (size_t i = 0; i < num_threads; ++i) 00141 { 00142 tg.create_thread(boost::bind(&multithread_pdl_test::processor_thread, this)); 00143 } 00144 00145 for (size_t i = 0; i < 2000; ++i) 00146 { 00147 boost::this_thread::sleep(boost::posix_time::microseconds(500)); 00148 reload(i % 5 == 0); 00149 } 00150 00151 m_finish = 1; 00152 00153 tg.join_all(); 00154 } 00155 00156 private: 00157 volatile sig_atomic_t m_finish; 00158 size_t m_lib_counter; 00159 std::vector<std::string> m_libs; 00160 moost::pdl::dynamic_library m_dl; 00161 moost::safe_shared_ptr<my_test_interface> m_inst; 00162 }; 00163 00164 } 00165 00166 extern "C" void pdl_test_c3_load() { ++c3_load; } 00167 extern "C" void pdl_test_c3_unload() { ++c3_unload; } 00168 extern "C" void pdl_test_c3_ctor() { ++c3_ctor; } 00169 extern "C" void pdl_test_c3_dtor() { ++c3_dtor; } 00170 00171 extern "C" void pdl_test_c4_load() { ++c4_load; } 00172 extern "C" void pdl_test_c4_unload() { ++c4_unload; } 00173 extern "C" void pdl_test_c4_ctor() { ++c4_ctor; } 00174 extern "C" void pdl_test_c4_dtor() { ++c4_dtor; } 00175 00176 BOOST_AUTO_TEST_CASE(pdl_thread) 00177 { 00178 // Check behaviour in a multi-threaded environment 00179 00180 std::vector<std::string> libs; 00181 00182 libs.push_back("../lib/test_module3"); 00183 libs.push_back("../lib/test_module4"); 00184 00185 multithread_pdl_test(libs).run(); 00186 00187 BOOST_CHECK(c3_load.read() > 0); 00188 BOOST_CHECK(c3_ctor.read() > 0); 00189 00190 BOOST_CHECK(c4_load.read() > 0); 00191 BOOST_CHECK(c4_ctor.read() > 0); 00192 00193 BOOST_CHECK_EQUAL(c3_load.read(), c3_unload.read()); 00194 BOOST_CHECK_EQUAL(c3_ctor.read(), c3_dtor.read()); 00195 00196 BOOST_CHECK_EQUAL(c4_load.read(), c4_unload.read()); 00197 BOOST_CHECK_EQUAL(c4_ctor.read(), c4_dtor.read()); 00198 } 00199 00200 BOOST_AUTO_TEST_SUITE_END()