]>
Commit | Line | Data |
---|---|---|
aa118a03 | 1 | // Copyright (C) 2006-2014 Free Software Foundation, Inc. |
aaf0ca6f JW |
2 | // |
3 | // This file is part of the GNU ISO C++ Library. This library is free | |
4 | // software; you can redistribute it and/or modify it under the | |
5 | // terms of the GNU General Public License as published by the | |
748086b7 | 6 | // Free Software Foundation; either version 3, or (at your option) |
aaf0ca6f JW |
7 | // any later version. |
8 | ||
9 | // This library is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | ||
14 | // You should have received a copy of the GNU General Public License along | |
748086b7 JJ |
15 | // with this library; see the file COPYING3. If not see |
16 | // <http://www.gnu.org/licenses/>. | |
aaf0ca6f JW |
17 | |
18 | // 20.6.6.2 Template class shared_ptr [util.smartptr.shared] | |
19 | ||
9275f73a TS |
20 | // { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-gnu* *-*-solaris* *-*-cygwin *-*-darwin* } } |
21 | // { dg-options "-pthread -std=gnu++0x" { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-gnu* } } | |
aaf0ca6f | 22 | // { dg-options "-pthreads -std=gnu++0x" { target *-*-solaris* } } |
dbf3a492 | 23 | // { dg-options " -std=gnu++0x " { target *-*-cygwin *-*-darwin* } } |
aaf0ca6f JW |
24 | |
25 | #include <memory> | |
26 | #include <random> | |
27 | #include <vector> | |
28 | #include <testsuite_hooks.h> | |
29 | #include <iostream> | |
30 | #include <cstdlib> | |
31 | ||
32 | #include <pthread.h> | |
33 | ||
34 | #ifdef _GLIBCXX_HAVE_UNISTD_H | |
35 | #include <unistd.h> // To test for _POSIX_THREAD_PRIORITY_SCHEDULING | |
36 | #endif | |
37 | ||
38 | /* This (brute-force) tests the atomicity and thus thread safety of the | |
39 | * shared_ptr <- weak_ptr | |
40 | * assignment operation by allocating a test object, retrieving a weak | |
41 | * reference to it, and letting a number of threads repeatedly create strong | |
42 | * references from the weak reference. | |
43 | * Specifically, this tests the function _Sp_counted_base<true>::add_ref_lock() | |
44 | */ | |
45 | ||
46 | ||
47 | const unsigned int HAMMER_MAX_THREADS = 10; | |
48 | const unsigned int POOL_SIZE = 1000; | |
49 | const unsigned long HAMMER_REPEAT = 100000; | |
50 | const unsigned long KILL_ONE_IN = 1000; | |
51 | ||
52 | struct A | |
53 | { | |
54 | static _Atomic_word counter; | |
55 | A() | |
56 | { | |
57 | __gnu_cxx::__atomic_add(&counter, 1); | |
58 | } | |
59 | ~A() | |
60 | { | |
61 | __gnu_cxx::__atomic_add(&counter, -1); | |
62 | } | |
63 | }; | |
64 | ||
65 | _Atomic_word A::counter = 0; | |
66 | ||
67 | typedef std::shared_ptr<A> sp_A_t; | |
68 | typedef std::weak_ptr<A> wp_A_t; | |
69 | ||
70 | typedef std::vector<sp_A_t> sp_vector_t; | |
71 | typedef std::vector<wp_A_t> wp_vector_t; | |
72 | ||
73 | struct shared_and_weak_pools | |
74 | { | |
75 | sp_vector_t& shared_pool; | |
76 | wp_vector_t& weak_pool; | |
77 | ||
78 | shared_and_weak_pools(sp_vector_t& _shared_pool, wp_vector_t& _weak_pool) | |
79 | : shared_pool(_shared_pool), weak_pool(_weak_pool) | |
80 | { } | |
81 | }; | |
82 | ||
83 | void* thread_hammer_and_kill(void* opaque_pools) | |
84 | { | |
85 | shared_and_weak_pools& pools = *static_cast<shared_and_weak_pools*>(opaque_pools); | |
86 | // Using the same parameters as in the RNG test cases. | |
8e79468d | 87 | std::mersenne_twister_engine< |
aaf0ca6f | 88 | unsigned long, 32, 624, 397, 31, |
8e79468d BK |
89 | 0x9908b0dful, 11, |
90 | 0xfffffffful, 7, | |
aaf0ca6f | 91 | 0x9d2c5680ul, 15, |
8e79468d | 92 | 0xefc60000ul, 18, 1812433253ul> rng; |
aaf0ca6f JW |
93 | |
94 | sp_vector_t::iterator cur_shared = pools.shared_pool.begin(); | |
95 | wp_vector_t::iterator cur_weak = pools.weak_pool.begin(); | |
96 | ||
97 | for (unsigned int i = 0; i < HAMMER_REPEAT; ++i) | |
98 | { | |
99 | try | |
100 | { | |
101 | sp_A_t strong(*cur_weak); | |
102 | } | |
103 | catch (std::bad_weak_ptr& exception) | |
104 | { | |
105 | ++cur_weak; | |
106 | if (cur_weak == pools.weak_pool.end()) | |
107 | break; | |
108 | } | |
109 | ||
110 | if (rng() % KILL_ONE_IN == 0) | |
111 | { | |
112 | cur_shared->reset(); | |
113 | ++cur_shared; | |
114 | } | |
115 | } | |
116 | return 0; | |
117 | } | |
118 | ||
119 | void* thread_hammer(void* opaque_weak) | |
120 | { | |
121 | wp_vector_t& weak_pool = *static_cast<wp_vector_t*>(opaque_weak); | |
122 | // Using the same parameters as in the RNG test cases. | |
8e79468d | 123 | std::mersenne_twister_engine< |
aaf0ca6f | 124 | unsigned long, 32, 624, 397, 31, |
8e79468d BK |
125 | 0x9908b0dful, 11, |
126 | 0xfffffffful, 7, | |
aaf0ca6f | 127 | 0x9d2c5680ul, 15, |
8e79468d BK |
128 | 0xefc60000ul, 18, 1812433253ul> rng; |
129 | ||
aaf0ca6f JW |
130 | wp_vector_t::iterator cur_weak = weak_pool.begin(); |
131 | ||
132 | for (unsigned int i = 0; i < HAMMER_REPEAT; ++i) | |
133 | { | |
134 | try | |
135 | { | |
136 | sp_A_t strong(*cur_weak); | |
137 | } | |
138 | catch (std::bad_weak_ptr& exception) | |
139 | { | |
140 | ++cur_weak; | |
141 | if (cur_weak == weak_pool.end()) | |
142 | break; | |
143 | } | |
144 | } | |
145 | return 0; | |
146 | } | |
147 | ||
148 | int | |
149 | test01() | |
150 | { | |
151 | bool test __attribute__((unused)) = true; | |
152 | sp_vector_t obj_pool(POOL_SIZE); | |
153 | ||
154 | for(sp_vector_t::iterator cur = obj_pool.begin(); cur != obj_pool.end(); ++cur) | |
155 | { | |
156 | cur->reset(new A); | |
157 | } | |
158 | // Obtain weak references. | |
159 | std::vector<wp_vector_t> weak_pool(HAMMER_MAX_THREADS, wp_vector_t(obj_pool.begin(), obj_pool.end())); | |
160 | ||
161 | // Launch threads with pointer to weak reference. | |
162 | pthread_t threads[HAMMER_MAX_THREADS]; | |
163 | #if defined(__sun) && defined(__svr4__) && _XOPEN_VERSION >= 500 | |
164 | pthread_setconcurrency (HAMMER_MAX_THREADS); | |
165 | #endif | |
166 | ||
167 | pthread_attr_t tattr; | |
395c9e79 | 168 | pthread_attr_init(&tattr); |
aaf0ca6f JW |
169 | |
170 | shared_and_weak_pools pools(obj_pool, weak_pool[0]); | |
171 | pthread_create(threads, &tattr, thread_hammer_and_kill, static_cast<void*>(&pools)); | |
172 | for (unsigned int worker = 1; worker < HAMMER_MAX_THREADS; worker++) | |
173 | { | |
174 | if (pthread_create(&threads[worker], &tattr, | |
175 | thread_hammer, static_cast<void*>(&weak_pool[worker]))) | |
176 | std::abort(); | |
177 | } | |
178 | // Wait for threads to complete, then check integrity of reference. | |
179 | void* status; | |
180 | for (unsigned int worker = 0; worker < HAMMER_MAX_THREADS; worker++) | |
181 | { | |
182 | if (pthread_join(threads[worker], &status)) | |
183 | std::abort(); | |
184 | } | |
185 | obj_pool.clear(); | |
186 | ||
187 | VERIFY( A::counter == 0 ); | |
188 | ||
189 | return 0; | |
190 | } | |
191 | ||
192 | int | |
193 | main() | |
194 | { | |
195 | test01(); | |
196 | return 0; | |
197 | } |