• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2008-2010, Google Inc.
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Neither the name of Google Inc. nor the names of its
11  * contributors may be used to endorse or promote products derived from
12  * this software without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 // This file is a part of a test suite for ThreadSanitizer, a race detector.
28 // Author: Konstantin Serebryany.
29 //
30 // C++ tests for atomicity violations (aka high-level races).
31 // See also: http://code.google.com/p/data-race-test/wiki/HighLevelDataRaces
32 #include "test_utils.h"
33 
34 #include <gtest/gtest.h>
35 
36 #include <map>
37 
38 namespace AtomicityTests_LockedVector {  // {{{1
39 // The most popular form of atomicity violation.
40 // Every method of a class is locked, but not every method is atomic.
41 // So,
42 //   if(v.size() > 0)
43 //     v.pop_back()
44 // may fail, if another thread called v.pop_back() in between.
45 class LockedVector {
46  public:
size()47   size_t size() {
48     MutexLock l(&mu_);
49     return v_.size();
50   }
51 
push_back(int a)52   void push_back(int a) {
53     MutexLock l(&mu_);
54     v_.push_back(a);
55   }
56 
pop_back()57   void pop_back() {
58     MutexLock l(&mu_);
59     v_.pop_back();
60   }
61 
62  private:
63   vector<int> v_;
64   Mutex       mu_;
65 };
66 
67 const int N = 100;
68 LockedVector v;
69 
Worker()70 void Worker() {
71   for (int i = 0; i < N; i++) {
72     if (v.size() > 0)
73       v.pop_back();
74     v.push_back(i);
75     usleep(1);
76   }
77 }
78 
79 // The test is disabled because it actually fails sometimes.
80 // Run it with --gtest_also_run_disabled_tests
TEST(AtomicityTests,DISABLED_LockedVector)81 TEST(AtomicityTests, DISABLED_LockedVector) {
82   MyThreadArray t(Worker, Worker);
83   t.Start();
84   t.Join();
85 }
86 
87 }  // namespace
88 
89 
90 namespace AtomicityTests_ReaderThenWriterLockTest {  // {{{1
91 #ifndef _MSC_VER
92 // Atomicity violation with a map and a reader lock.
93 // The function CheckMapAndInsertIfNeeded first checks if an element
94 // with a given key exists. If not, it inserts such element.
95 // The problem here is that during the first part we hold a reader lock,
96 // then we release it and grap writer lock, but the code has (incorrect)
97 // assumption that the map has not been changed between ReaderUnlock and
98 // WriterLock.
99 
100 typedef std::map<int, int> Map;
101 Map *m;
102 RWLock mu;
103 bool reported = false;
104 
CheckMapAndInsertIfNeeded(int key,int val)105 void CheckMapAndInsertIfNeeded(int key, int val) {
106   Map::iterator it;
107 
108   {
109     ReaderLockScoped reader(&mu);
110     it = m->find(key);
111     if (it != m->end())
112       return;
113   }
114   // <<<<< Another thread may change the map here.
115   {
116     WriterLockScoped writer(&mu);
117     // CHECK(m->find(key) == m->end());
118     if (m->find(key) != m->end()) {
119       if (!reported) {
120         printf("Here comes the result of atomicity violation!\n");
121         reported = true;
122       }
123       return;
124     }
125     (*m)[key] = val;
126   }
127 }
128 
Worker()129 void Worker() {
130   for (int i = 0; i < 1000; i++) {
131     CheckMapAndInsertIfNeeded(i, i);
132     usleep(0);
133   }
134 }
135 
TEST(AtomicityTests,ReaderThenWriterLockTest)136 TEST(AtomicityTests, ReaderThenWriterLockTest) {
137   m = new Map();
138   MyThreadArray t(Worker, Worker, Worker);
139   t.Start();
140   t.Join();
141   delete m;
142 }
143 #endif  // _MSC_VER
144 }  // namespace
145 
146 // End {{{1
147 // vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker
148