Added copyright and license
[libcds.git] / tests / cppunit / thread.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8     
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
29 */
30
31 #ifndef CDS_CPPUNIT_THREAD_H
32 #define CDS_CPPUNIT_THREAD_H
33
34 #include <cds/details/defs.h>
35 #include "cppunit/cppunit_mini.h"
36 #include <boost/thread.hpp>
37 #include <cds/os/timer.h>
38 #include <cds/threading/model.h>    // for attach/detach thread
39 #include <cds/algo/atomic.h>
40
41 // Visual leak detector (see http://vld.codeplex.com/)
42 #if defined(CDS_USE_VLD) && CDS_COMPILER == CDS_COMPILER_MSVC
43 #   ifdef _DEBUG
44 #       include <vld.h>
45 #   endif
46 #endif
47
48 namespace CppUnitMini {
49     static inline unsigned int Rand( unsigned int nMax )
50     {
51         double rnd = double( rand() ) / double( RAND_MAX );
52         unsigned int n = (unsigned int) (rnd * nMax);
53         return n < nMax ? n : (n-1);
54     }
55
56     class ThreadPool;
57     class TestThread
58     {
59     protected:
60         typedef TestThread  Base;
61         friend class ThreadPool;
62
63         ThreadPool&         m_Pool;
64         boost::thread *     m_pThread;
65         cds::OS::Timer      m_Timer;
66         atomics::atomic<bool>    m_bTimeElapsed;
67
68     public:
69         double              m_nDuration;
70         size_t              m_nThreadNo;
71
72     protected:
73         static void threadEntryPoint( TestThread * pThread );
74
75         TestThread( TestThread& src )
76             : m_Pool( src.m_Pool )
77             , m_pThread( nullptr )
78             , m_bTimeElapsed( false )
79             , m_nDuration( 0 )
80             , m_nThreadNo( 0 )
81         {}
82
83         virtual ~TestThread()
84         {
85             if ( m_pThread )
86                 delete m_pThread;
87         }
88
89         virtual TestThread *    clone() = 0;
90
91         void create();
92         void run();
93
94         virtual void init() {}
95         virtual void test() = 0;
96         virtual void fini() {}
97         void stop()
98         {
99             m_bTimeElapsed.store( true, atomics::memory_order_release );
100         }
101         bool time_elapsed() const
102         {
103             return m_bTimeElapsed.load( atomics::memory_order_acquire );
104         }
105
106         bool check_timeout( size_t nMaxDuration )
107         {
108             return m_Timer.duration() > nMaxDuration;
109         }
110
111         void error(const char *in_macroName, const char *in_macro, const char *in_file, int in_line);
112
113     public:
114         TestThread( ThreadPool& pool )
115             : m_Pool( pool )
116             , m_pThread( nullptr )
117             , m_nDuration( 0 )
118             , m_nThreadNo( 0 )
119         {}
120     };
121
122     class ThreadPool
123     {
124     public:
125         TestCase&                       m_Test;
126
127     private:
128         typedef std::vector< TestThread * >     thread_vector;
129
130         boost::thread_group             m_Pool;
131         thread_vector                   m_arrThreads;
132
133         boost::barrier * volatile       m_pBarrierStart;
134         boost::barrier * volatile       m_pBarrierDone;
135
136     public:
137         typedef thread_vector::iterator    iterator;
138
139     public:
140         ThreadPool( TestCase& tc )
141             : m_Test( tc )
142             , m_pBarrierStart( nullptr )
143             , m_pBarrierDone( nullptr )
144         {}
145         ~ThreadPool();
146
147         void    add( TestThread * pThread, size_t nCount );
148
149         void    run();
150         void    run( unsigned int nDuration );
151
152         void    onThreadInitDone( TestThread * pThread );
153         void    onThreadTestDone( TestThread * pThread );
154         void    onThreadFiniDone( TestThread * pThread );
155
156         iterator begin() { return m_arrThreads.begin(); }
157         iterator end()   { return m_arrThreads.end() ;   }
158
159         double  avgDuration() const
160         {
161             double nDur = 0;
162             for ( size_t i = 0; i < m_arrThreads.size(); ++i )
163                 nDur += m_arrThreads[i]->m_nDuration;
164             return nDur / m_arrThreads.size();
165         }
166     };
167 }
168
169 #endif    // #ifndef CDS_CPPUNIT_THREAD_H