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