1// { dg-do run { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* *-*-solaris* *-*-cygwin *-*-darwin* } }
2// { dg-options " -std=gnu++11 -pthread" { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* } }
3// { dg-options " -std=gnu++11 -pthreads" { target *-*-solaris* } }
4// { dg-options " -std=gnu++11 " { target *-*-cygwin *-*-darwin* } }
5// { dg-require-cstdint "" }
6// { dg-require-gthreads "" }
7// { dg-require-debug-mode "" }
8// Copyright (C) 2010-2015 Free Software Foundation, Inc.
9//
10// This file is part of the GNU ISO C++ Library.  This library is free
11// software; you can redistribute it and/or modify it under the
12// terms of the GNU General Public License as published by the
13// Free Software Foundation; either version 3, or (at your option)
14// any later version.
15//
16// This library is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License along
22// with this library; see the file COPYING3.  If not see
23// <http://www.gnu.org/licenses/>.
24//
25
26// This test check for potential deadlock when swaping sequences in debug
27// mode as it requires acquiring 2 locks at the same time.
28
29#include <vector>
30#include <thread>
31#include <functional>
32#include <testsuite_hooks.h>
33
34// The following function mimic the one in src/debug.cc to associate a mutex
35// to a given safe sequence instance.
36size_t
37get_index(std::vector<int>& v)
38{
39  const size_t mask = 0xf;
40  // We have to check the address of the internal safe sequence that starts
41  // after the normal vector memory footprint that is to say a 3 pointers
42  // offset:
43  void* __address = reinterpret_cast<char*>(&v) + 3 * sizeof(void*);
44  return std::_Hash_impl::hash(__address) & mask;
45}
46
47void test01()
48{
49  using namespace std;
50  bool test __attribute__((unused)) = true;
51  vector<int> v1, v2;
52  vector<shared_ptr<vector<int> > > vs;
53  vector<int> *pv3 = 0, *pv4 = 0;
54  const int nb_attempts = 100;
55  for (int i = 0; i != nb_attempts; ++i)
56    {
57      vs.push_back(shared_ptr<vector<int> >(new vector<int>()));
58      if (!pv3)
59	{
60	  if (get_index(*vs.back()) == get_index(v1))
61	    pv3 = vs.back().get();
62	}
63      else if (!pv4)
64	{
65	  if (get_index(*vs.back()) == get_index(v2))
66	    {
67	      pv4 = vs.back().get();
68	      break;
69	    }
70	}
71    }
72
73  if (!pv3 || !pv4)
74    // Maybe an other time...
75    return;
76
77  vector<int> &v3 = *pv3, &v4 = *pv4;
78
79  // v1 and v3 shares the same mutex instance, like v2 and v4
80  // thread t1 lock v1 and v2
81  thread t1([&v1, &v2]()
82    {
83      for (int i = 0; i != 1000; ++i)
84	v1.swap(v2);
85    });
86  // thread t2 lock v4 and v3
87  thread t2([&v3, &v4]()
88    {
89      for (int i = 0; i != 1000; ++i)
90	v4.swap(v3);
91    });
92  t2.join();
93  t1.join();
94}
95
96int main()
97{
98  test01();
99  return 0;
100}
101