1 /*
2  *
3  * Copyright (c) 2004
4  * John Maddock
5  *
6  * Use, modification and distribution are subject to the
7  * Boost Software License, Version 1.0. (See accompanying file
8  * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9  *
10  */
11 
12  /*
13   *   LOCATION:    see http://www.boost.org for most recent version.
14   *   FILE         static_mutex_test.cpp
15   *   VERSION      see <boost/version.hpp>
16   *   DESCRIPTION: test program for boost::static_mutex.
17   */
18 
19 #include <boost/regex/pending/static_mutex.hpp>
20 #include <boost/thread/thread.hpp>
21 #include <boost/timer.hpp>
22 #include <iostream>
23 #include <iomanip>
24 
25 #ifdef BOOST_REGEX_CXX03
26 //
27 // we cannot use the regular Boost.Test in here: it is not thread safe
28 // and calls to BOOST_CHECK will eventually crash on some compilers
29 // (Borland certainly) due to race conditions inside the Boost.Test lib.
30 //
31 #define BOOST_CHECK(pred) if(!(pred)) failed_test(__FILE__, __LINE__, BOOST_STRINGIZE(pred));
32 
33 int total_failures = 0;
failed_test(const char * file,int line,const char * pred)34 void failed_test(const char* file, int line, const char* pred)
35 {
36    static boost::static_mutex mut = BOOST_STATIC_MUTEX_INIT ;
37    boost::static_mutex::scoped_lock guard(mut);
38    ++total_failures;
39    std::cout << "Failed test in \"" << file << "\" at line " << line << ": " << pred << std::endl;
40 }
41 
print_cycles(int c)42 void print_cycles(int c)
43 {
44    static boost::static_mutex mut = BOOST_STATIC_MUTEX_INIT ;
45    boost::static_mutex::scoped_lock guard(mut);
46    std::cout << "Thread exited after " << c << " cycles." << std::endl;
47 }
48 
sufficient_time()49 bool sufficient_time()
50 {
51    // return true if enough time has passed since the tests began:
52    static boost::static_mutex mut = BOOST_STATIC_MUTEX_INIT ;
53    boost::static_mutex::scoped_lock guard(mut);
54    static boost::timer t;
55    // is 10 seconds enough?
56    return t.elapsed() >= 10.0;
57 }
58 
59 // define three trivial test proceedures:
t1()60 bool t1()
61 {
62    static boost::static_mutex mut = BOOST_STATIC_MUTEX_INIT ;
63    static int has_lock = 0;
64    static int data = 10000;
65 
66    boost::static_mutex::scoped_lock guard(mut);
67    BOOST_CHECK(++has_lock == 1);
68    BOOST_CHECK(guard.locked());
69    BOOST_CHECK(guard);
70    bool result = (--data > 0) ? true : false;
71    BOOST_CHECK(--has_lock == 0);
72    return result;
73 }
74 
t2()75 bool t2()
76 {
77    static boost::static_mutex mut = BOOST_STATIC_MUTEX_INIT ;
78    static int has_lock = 0;
79    static int data = 10000;
80 
81    boost::static_mutex::scoped_lock guard(mut, false);
82    BOOST_CHECK(0 == guard.locked());
83    BOOST_CHECK(!guard);
84    guard.lock();
85    BOOST_CHECK(++has_lock == 1);
86    BOOST_CHECK(guard.locked());
87    BOOST_CHECK(guard);
88    bool result = (--data > 0) ? true : false;
89    BOOST_CHECK(--has_lock == 0);
90    guard.unlock();
91    BOOST_CHECK(0 == guard.locked());
92    BOOST_CHECK(!guard);
93    return result;
94 }
95 
t3()96 bool t3()
97 {
98    static boost::static_mutex mut = BOOST_STATIC_MUTEX_INIT ;
99    static int has_lock = 0;
100    static int data = 10000;
101 
102    boost::static_mutex::scoped_lock guard(mut);
103    BOOST_CHECK(++has_lock == 1);
104    BOOST_CHECK(guard.locked());
105    BOOST_CHECK(guard);
106    bool result = (--data > 0) ? true : false;
107    BOOST_CHECK(--has_lock == 0);
108    return result;
109 }
110 
111 // define their thread procs:
thread1_proc()112 void thread1_proc()
113 {
114    int cycles = 0;
115    while(!sufficient_time())
116    {
117       t1();
118       t2();
119       ++cycles;
120    }
121    print_cycles(cycles);
122 }
123 
thread2_proc()124 void thread2_proc()
125 {
126    int cycles = 0;
127    while(!sufficient_time())
128    {
129       t2();
130       t3();
131       ++cycles;
132    }
133    print_cycles(cycles);
134 }
135 
thread3_proc()136 void thread3_proc()
137 {
138    int cycles = 0;
139    while(!sufficient_time())
140    {
141       t1();
142       t3();
143       ++cycles;
144    }
145    print_cycles(cycles);
146 }
147 
148 // make sure that at least one of our test proceedures
149 // is called during program startup:
150 struct startup1
151 {
startup1startup1152    startup1()
153    {
154       t1();
155    }
~startup1startup1156    ~startup1()
157    {
158       t1();
159    }
160 };
161 
162 startup1 up1;
163 
main()164 int main()
165 {
166    (void)up1;
167 
168    std::list<boost::shared_ptr<boost::thread> > threads;
169    for(int i = 0; i < 2; ++i)
170    {
171       try{
172          threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(&thread1_proc)));
173       }
174       catch(const std::exception& e)
175       {
176          std::cerr << "<note>Thread creation failed with message: " << e.what() << "</note>" << std::endl;
177       }
178    }
179    for(int i = 0; i < 2; ++i)
180    {
181       try{
182          threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(&thread2_proc)));
183       }
184       catch(const std::exception& e)
185       {
186          std::cerr << "<note>Thread creation failed with message: " << e.what() << "</note>" << std::endl;
187       }
188    }
189    for(int i = 0; i < 2; ++i)
190    {
191       try{
192          threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(&thread3_proc)));
193       }
194       catch(const std::exception& e)
195       {
196          std::cerr << "<note>Thread creation failed with message: " << e.what() << "</note>" << std::endl;
197       }
198    }
199 
200    std::list<boost::shared_ptr<boost::thread> >::const_iterator a(threads.begin()), b(threads.end());
201    while(a != b)
202    {
203       (*a)->join();
204       ++a;
205    }
206 
207    return total_failures;
208 }
209 #else
main()210 int main() {}
211 #endif
212