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 set of unit tests for a deadlock detection tool.
     29 //
     30 //
     31 //
     32 // This test can be compiled with pthreads (default) or
     33 // with any other library that supports threads, locks, cond vars, etc.
     34 //
     35 // To compile with pthreads:
     36 //   g++  deadlock_unittest.cc -lpthread -g
     37 //
     38 // To compile with different library:
     39 //   1. cp thread_wrappers_pthread.h thread_wrappers_yourlib.h
     40 //   2. edit thread_wrappers_yourlib.h
     41 //   3. add '-DTHREAD_WRAPPERS="thread_wrappers_yourlib.h"' to your compilation.
     42 //
     43 //
     44 
     45 #include <fcntl.h>
     46 #include <queue>
     47 #include <signal.h>
     48 #include <stdlib.h>
     49 #include <string>
     50 #include <vector>
     51 
     52 #include "old_test_suite.h"
     53 #include "test_utils.h"
     54 
     55 #include <gtest/gtest.h>
     56 
     57 /*ProducerConsumerQueue *Q[4] = {
     58   new ProducerConsumerQueue(INT_MAX),
     59   new ProducerConsumerQueue(INT_MAX),
     60   new ProducerConsumerQueue(INT_MAX),
     61   new ProducerConsumerQueue(INT_MAX)
     62 };
     63 Mutex mu[4];*/
     64 
     65 /*
     66 void PutAndWait(int *work_item, int idx) {
     67   // Put work_item1.
     68   Q[idx]->Put(work_item);
     69 
     70   // Wait for work_item completion.
     71   mu[idx].LockWhen(Condition(&ArgIsOne, work_item));
     72   mu[idx].Unlock();
     73 }
     74 
     75 void GetAndServe(int idx) {
     76   // Get an item.
     77   int *item = reinterpret_cast<int*>(Q[idx]->Get());
     78 
     79   // Handle work item and signal completion.
     80   mu[idx].Lock();
     81   *item = 1;
     82   mu[idx].Unlock();
     83 }
     84 
     85 
     86 bool TryGetAndServe(int idx) {
     87   // Get an item.
     88   int *item;
     89   if (Q[idx]->TryGet(reinterpret_cast<void**>(&item))) {
     90     // Handle work item and signal completion.
     91     mu[idx].Lock();
     92     *item = 1;
     93     mu[idx].Unlock();
     94     return true;
     95   } else {
     96     return false;
     97   }
     98 }*/
     99 
    100 // Set of threads that execute the same function.
    101 class MyThreadSet {
    102  public:
    103   typedef void (*F) (void);
    104   MyThreadSet(F f, int count)
    105     : count_(count) {
    106     CHECK(count_ >= 1 && count_ <= 1000);
    107     ar_ = new MyThread* [count_];
    108     for (int i = 0; i < count_; i++) {
    109       ar_[i] = new MyThread(f);
    110     }
    111   }
    112   void Start() {
    113     for (int i = 0; i < count_; i++) {
    114       ar_[i]->Start();
    115     }
    116   }
    117   void Join() {
    118     for (int i = 0; i < count_; i++) {
    119       ar_[i]->Join();
    120     }
    121   }
    122   ~MyThreadSet() {
    123     for (int i = 0; i < count_; i++) {
    124       delete ar_[i];
    125     }
    126     delete ar_;
    127   }
    128 
    129  private:
    130   MyThread **ar_;
    131   int count_;
    132 };
    133 
    134 int ThreadId() {
    135   static Mutex mu;
    136   static map<pthread_t, int> m;
    137 
    138   int id;
    139   pthread_t self = pthread_self();
    140 
    141   mu.Lock();
    142   map<pthread_t, int>::iterator it = m.find(self);
    143   if (it != m.end()) {
    144     id = it->second;
    145   } else {
    146     id = m.size();
    147     m[self] = id;
    148   }
    149   mu.Unlock();
    150   return id;
    151 }
    152 
    153 // test00: {{{1
    154 namespace test00 {
    155 void Run() {
    156   printf("test00: negative\n");
    157 }
    158 REGISTER_TEST(Run, 00)
    159 }  // namespace test00
    160 
    161 // test01: Simple deadlock, 2 threads. {{{1
    162 namespace test01 {
    163 Mutex mu1, mu2;
    164 void Worker1()  {
    165   mu1.Lock();
    166   mu2.Lock();
    167   mu2.Unlock();
    168   mu1.Unlock();
    169 }
    170 void Worker2()  {
    171   usleep(1000);
    172   mu2.Lock();
    173   mu1.Lock();
    174   mu1.Unlock();
    175   mu2.Unlock();
    176 }
    177 void Run() {
    178   MyThreadArray t(Worker1, Worker2);
    179   t.Start();
    180   t.Join();
    181   printf("test01: positive, simple deadlock\n");
    182 }
    183 REGISTER_TEST(Run, 01)
    184 }  // namespace test01
    185 
    186 // test02: Simple deadlock, 4 threads. {{{1
    187 namespace test02 {
    188 Mutex mu1, mu2, mu3, mu4;
    189 void Worker1()  {
    190   mu1.Lock();   mu2.Lock();
    191   mu2.Unlock(); mu1.Unlock();
    192 }
    193 void Worker2()  {
    194   usleep(1000);
    195   mu2.Lock();   mu3.Lock();
    196   mu3.Unlock(); mu2.Unlock();
    197 }
    198 void Worker3()  {
    199   usleep(2000);
    200   mu3.Lock();   mu4.Lock();
    201   mu4.Unlock(); mu3.Unlock();
    202 }
    203 void Worker4()  {
    204   usleep(3000);
    205   mu4.Lock();   mu1.Lock();
    206   mu1.Unlock(); mu4.Unlock();
    207 }
    208 void Run() {
    209   MyThreadArray t(Worker1, Worker2, Worker3, Worker4);
    210   t.Start();
    211   t.Join();
    212   printf("test02: positive, simple deadlock\n");
    213 }
    214 REGISTER_TEST(Run, 02)
    215 }  // namespace test02
    216 /*
    217 // test03: Queue deadlock test, 2 workers. {{{1
    218 // This test will deadlock for sure.
    219 namespace  test03 {
    220 
    221 void Worker1() {
    222   int *item = new int (0);
    223   PutAndWait(item, 0);
    224   GetAndServe(1);
    225 }
    226 void Worker2() {
    227   int *item = new int (0);
    228   PutAndWait(item, 1);
    229   GetAndServe(0);
    230 }
    231 void Run() {
    232   printf("test03: queue deadlock\n");
    233   MyThreadArray t(Worker1, Worker2);
    234   t.Start();
    235   t.Join();
    236 }
    237 REGISTER_TEST(Run, 03)
    238 }  // namespace test03
    239 
    240 // test04: Queue deadlock test, 3 workers. {{{1
    241 // This test will deadlock for sure.
    242 namespace  test04 {
    243 
    244 void Worker1() {
    245   int *item = new int (0);
    246   PutAndWait(item, 0);
    247   GetAndServe(1);
    248 }
    249 void Worker2() {
    250   int *item = new int (0);
    251   PutAndWait(item, 1);
    252   GetAndServe(2);
    253 }
    254 
    255 void Worker3() {
    256   int *item = new int (0);
    257   PutAndWait(item, 2);
    258   GetAndServe(0);
    259 }
    260 
    261 void Run() {
    262   printf("test04: queue deadlock\n");
    263   MyThreadArray t(Worker1, Worker2, Worker3);
    264   t.Start();
    265   t.Join();
    266 }
    267 REGISTER_TEST(Run, 04)
    268 }  // namespace test04
    269 
    270 // test05: Queue deadlock test, 1 worker set. {{{1
    271 // This test will deadlock after some number of served requests.
    272 namespace  test05 {
    273 
    274 int item_number = 0;  // Just for debug prints.
    275 
    276 
    277 // This function randomly enqueues work and waits on it or serves a piece of work.
    278 void Worker() {
    279   while(true) {
    280     int action = rand() % 100;
    281     if (action <= 1) {        // PutAndWait.
    282       int n = __sync_add_and_fetch(&item_number, 1);
    283       int *item = new int(0);
    284       PutAndWait(item, 0);
    285       if ((n % 10000) == 0) {
    286         printf("Done %d\n", n);
    287       }
    288       delete item;
    289     } else {                 // GetAndServe.
    290       TryGetAndServe(0);
    291     }
    292   }
    293 }
    294 
    295 
    296 void Run() {
    297   printf("test05: queue deadlock\n");
    298   MyThreadSet t(Worker, 5);
    299   t.Start();
    300   t.Join();
    301 }
    302 REGISTER_TEST(Run, 05)
    303 }  // namespace test05
    304 
    305 // test06: Queue deadlock test, 3 worker sets. {{{1
    306 // This test will deadlock after some number of served requests.
    307 namespace  test06 {
    308 
    309 int item_number[3] = {0, 0, 0};  // Just for debug prints.
    310 
    311 // This function randomly enqueues work to queue 'put_queue' and waits on it
    312 // or serves a piece of work from queue 'get_queue'.
    313 void Worker(int put_queue, int get_queue) {
    314   while(true) {
    315     int action = rand() % 1000;
    316     if (action <= 100) {        // PutAndWait.
    317       int n = __sync_add_and_fetch(&item_number[put_queue], 1);
    318       int *item = new int(0);
    319       PutAndWait(item, put_queue);
    320       if ((n % 1000) == 0) {
    321         printf("Q[%d]: done %d\n", put_queue, n);
    322       }
    323       delete item;
    324     } else {                 // TryGetAndServe.
    325       TryGetAndServe(get_queue);
    326     }
    327   }
    328 }
    329 
    330 void Worker1() { Worker(0, 1); }
    331 void Worker2() { Worker(1, 2); }
    332 void Worker3() { Worker(2, 0); }
    333 
    334 void Run() {
    335   printf("test06: queue deadlock\n");
    336   MyThreadSet t1(Worker1, 4);
    337   MyThreadSet t2(Worker2, 4);
    338   MyThreadSet t3(Worker3, 4);
    339   t1.Start();
    340   t2.Start();
    341   t3.Start();
    342   t1.Join();
    343   t2.Join();
    344   t3.Join();
    345 }
    346 REGISTER_TEST(Run, 06)
    347 }  // namespace test06
    348 // test07: Simple deadlock which actually deadlocks, 2 threads. {{{1
    349 namespace test07 {
    350 Mutex mu1, mu2;
    351 void Worker1()  {
    352   mu1.Lock();
    353   usleep(100000);
    354   mu2.Lock();
    355   mu2.Unlock();
    356   mu1.Unlock();
    357 }
    358 void Worker2()  {
    359   mu2.Lock();
    360   usleep(100000);
    361   mu1.Lock();
    362   mu1.Unlock();
    363   mu2.Unlock();
    364 }
    365 void Run() {
    366   mu1.EnableDebugLog("mu1");
    367   mu2.EnableDebugLog("mu2");
    368   printf("test07: positive, simple deadlock\n");
    369   MyThreadArray t(Worker1, Worker2);
    370   t.Start();
    371   t.Join();
    372 }
    373 REGISTER_TEST(Run, 07)
    374 }  // namespace test07
    375 
    376 */
    377