Home | History | Annotate | Download | only in unittest
      1 /*
      2   This file is part of Valgrind, a dynamic binary instrumentation
      3   framework.
      4 
      5   Copyright (C) 2008-2008 Google Inc
      6      opensource (at) google.com
      7 
      8   This program is free software; you can redistribute it and/or
      9   modify it under the terms of the GNU General Public License as
     10   published by the Free Software Foundation; either version 2 of the
     11   License, or (at your option) any later version.
     12 
     13   This program is distributed in the hope that it will be useful, but
     14   WITHOUT ANY WARRANTY; without even the implied warranty of
     15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16   General Public License for more details.
     17 
     18   You should have received a copy of the GNU General Public License
     19   along with this program; if not, write to the Free Software
     20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     21   02111-1307, USA.
     22 
     23   The GNU General Public License is contained in the file COPYING.
     24 */
     25 
     26 /* Author: Konstantin Serebryany <opensource (at) google.com>
     27 
     28  This file contains a few macros useful for implementing
     29  unit-tests for data race detection tools.
     30 
     31 */
     32 
     33 #ifndef TEST_UTILS_H__
     34 #define TEST_UTILS_H__
     35 
     36 // This test must not include any other file specific to threading library,
     37 // everything should be inside THREAD_WRAPPERS.
     38 #ifndef THREAD_WRAPPERS
     39 # define THREAD_WRAPPERS "thread_wrappers.h"
     40 #endif
     41 #include THREAD_WRAPPERS
     42 
     43 #ifndef NEEDS_SEPERATE_RW_LOCK
     44 #define RWLock Mutex // Mutex does work as an rw-lock.
     45 #define WriterLockScoped MutexLock
     46 #define ReaderLockScoped ReaderMutexLock
     47 #endif // !NEEDS_SEPERATE_RW_LOCK
     48 
     49 static bool ArgIsOne(int *arg) { return *arg == 1; };
     50 static bool ArgIsZero(int *arg) { return *arg == 0; };
     51 static bool ArgIsTrue(bool *arg) { return *arg == true; };
     52 
     53 
     54 // If run under ThreadSanitizerQuery, this function is replaced by the tool
     55 // and a non-NULL string is returned. See the usage below.
     56 extern "C" const char *ThreadSanitizerQuery(const char *query);
     57 
     58 // Apply ANNOTATE_EXPECT_RACE only if running under ThreadSanitizer.
     59 #define ANNOTATE_EXPECT_RACE_FOR_TSAN(mem, descr) \
     60     do {\
     61       if (ThreadSanitizerQuery("") != NULL) {\
     62         ANNOTATE_EXPECT_RACE(mem, descr); \
     63       } \
     64     } while(0)\
     65 
     66 inline bool ThreadSanitizerQueryMatch(const char *query, const char *expected_answer) {
     67   const char *answer = ThreadSanitizerQuery(query);
     68   if (answer == NULL) {
     69     // Not running under ThreadSanitizer at all.
     70     return false;
     71   }
     72   return string(answer) == expected_answer;
     73 }
     74 
     75 inline bool Tsan_PureHappensBefore() {
     76   static bool ret = ThreadSanitizerQueryMatch("pure_happens_before", "1");
     77   return ret;
     78 }
     79 
     80 inline bool Tsan_RaceVerifier() {
     81   static bool ret = ThreadSanitizerQueryMatch("race_verifier", "1");
     82   return ret;
     83 }
     84 
     85 // An array of threads. Create/start/join all elements at once.
     86 class MyThreadArray {
     87  public:
     88   static const int kSize = 5;
     89   typedef void (*F) (void);
     90   MyThreadArray(F f1, F f2 = NULL, F f3 = NULL, F f4 = NULL, F f5 = NULL) {
     91     ar_[0] = new MyThread(f1);
     92     ar_[1] = f2 ? new MyThread(f2) : NULL;
     93     ar_[2] = f3 ? new MyThread(f3) : NULL;
     94     ar_[3] = f4 ? new MyThread(f4) : NULL;
     95     ar_[4] = f5 ? new MyThread(f5) : NULL;
     96   }
     97   void Start() {
     98     for(int i = 0; i < kSize; i++) {
     99       if(ar_[i]) {
    100         ar_[i]->Start();
    101         usleep(10);
    102       }
    103     }
    104   }
    105 
    106   void Join() {
    107     for(int i = 0; i < kSize; i++) {
    108       if(ar_[i]) {
    109         ar_[i]->Join();
    110       }
    111     }
    112   }
    113 
    114   ~MyThreadArray() {
    115     for(int i = 0; i < kSize; i++) {
    116       delete ar_[i];
    117     }
    118   }
    119  private:
    120   MyThread *ar_[kSize];
    121 };
    122 
    123 
    124 // This class does not implement a signal-wait synchronization
    125 // primitive, even if it looks like one. Its purpose is to enforce an
    126 // order of execution of threads in unit tests in a way that is
    127 // invisible to ThreadSanitizer and similar tools. It lacks memory
    128 // barriers, therefore it only works reliably if there is a real
    129 // synchronization primitive before signal() or after wait().
    130 class StealthNotification {
    131  public:
    132   StealthNotification() : flag_(0) {}
    133 
    134   void signal() {
    135     ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
    136     CHECK(!flag_);
    137     flag_ = 1;
    138     ANNOTATE_IGNORE_READS_AND_WRITES_END();
    139   }
    140 
    141   void wait() {
    142     while (!flag_) {
    143 #ifdef WIN32
    144       usleep(1000);
    145 #else
    146       sched_yield();
    147 #endif
    148     }
    149   }
    150 
    151  private:
    152   volatile int flag_;
    153 };
    154 
    155 #endif  // TEST_UTILS_H__
    156 // End {{{1
    157  // vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker
    158