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: 47 size_t size() { 48 MutexLock l(&mu_); 49 return v_.size(); 50 } 51 52 void push_back(int a) { 53 MutexLock l(&mu_); 54 v_.push_back(a); 55 } 56 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 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 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 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 129 void Worker() { 130 for (int i = 0; i < 1000; i++) { 131 CheckMapAndInsertIfNeeded(i, i); 132 usleep(0); 133 } 134 } 135 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