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 38namespace 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. 45class 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 67const int N = 100; 68LockedVector v; 69 70void 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 81TEST(AtomicityTests, DISABLED_LockedVector) { 82 MyThreadArray t(Worker, Worker); 83 t.Start(); 84 t.Join(); 85} 86 87} // namespace 88 89 90namespace 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 100typedef std::map<int, int> Map; 101Map *m; 102RWLock mu; 103bool reported = false; 104 105void 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 129void Worker() { 130 for (int i = 0; i < 1000; i++) { 131 CheckMapAndInsertIfNeeded(i, i); 132 usleep(0); 133 } 134} 135 136TEST(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