]>
Commit | Line | Data |
---|---|---|
5c30094f | 1 | // Copyright (C) 2006, 2007, 2009, 2012 Free Software Foundation |
a25ce4db PJ |
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) |
a25ce4db PJ |
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/>. | |
a25ce4db PJ |
17 | |
18 | // TR1 2.2.2 Template class shared_ptr [tr.util.smartptr.shared] | |
19 | ||
5c30094f RO |
20 | // { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* mips-sgi-irix6* } } |
21 | // { dg-options "-pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* mips-sgi-irix6* } } | |
a25ce4db PJ |
22 | // { dg-options "-pthreads" { target *-*-solaris* } } |
23 | ||
a25ce4db PJ |
24 | #include <tr1/memory> |
25 | #include <tr1/random> | |
26 | #include <vector> | |
27 | #include <testsuite_hooks.h> | |
28 | #include <iostream> | |
debac9f4 | 29 | #include <cstdlib> |
a25ce4db PJ |
30 | |
31 | #include <pthread.h> | |
32 | ||
33 | #ifdef _GLIBCXX_HAVE_UNISTD_H | |
34 | #include <unistd.h> // To test for _POSIX_THREAD_PRIORITY_SCHEDULING | |
35 | #endif | |
36 | ||
37 | /* This (brute-force) tests the atomicity and thus thread safety of the | |
38 | * shared_ptr <- weak_ptr | |
39 | * assignment operation by allocating a test object, retrieving a weak | |
40 | * reference to it, and letting a number of threads repeatedly create strong | |
41 | * references from the weak reference. | |
42 | * Specifically, this tests the function _Sp_counted_base<true>::add_ref_lock() | |
43 | */ | |
44 | ||
45 | ||
46 | const unsigned int HAMMER_MAX_THREADS = 10; | |
47 | const unsigned int POOL_SIZE = 1000; | |
48 | const unsigned long HAMMER_REPEAT = 100000; | |
49 | const unsigned long KILL_ONE_IN = 1000; | |
50 | ||
51 | struct A | |
52 | { | |
53 | static _Atomic_word counter; | |
54 | A() | |
55 | { | |
56 | __gnu_cxx::__atomic_add(&counter, 1); | |
57 | } | |
58 | ~A() | |
59 | { | |
60 | __gnu_cxx::__atomic_add(&counter, -1); | |
61 | } | |
62 | }; | |
63 | ||
64 | _Atomic_word A::counter = 0; | |
65 | ||
0370f61a PC |
66 | typedef std::tr1::shared_ptr<A> sp_A_t; |
67 | typedef std::tr1::weak_ptr<A> wp_A_t; | |
a25ce4db PJ |
68 | |
69 | typedef std::vector<sp_A_t> sp_vector_t; | |
70 | typedef std::vector<wp_A_t> wp_vector_t; | |
71 | ||
72 | struct shared_and_weak_pools | |
73 | { | |
74 | sp_vector_t& shared_pool; | |
75 | wp_vector_t& weak_pool; | |
76 | ||
77 | shared_and_weak_pools(sp_vector_t& _shared_pool, wp_vector_t& _weak_pool) | |
78 | : shared_pool(_shared_pool), weak_pool(_weak_pool) | |
79 | { } | |
80 | }; | |
81 | ||
82 | void* thread_hammer_and_kill(void* opaque_pools) | |
83 | { | |
045fcc24 | 84 | shared_and_weak_pools& pools = *static_cast<shared_and_weak_pools*>(opaque_pools); |
a25ce4db PJ |
85 | // Using the same parameters as in the RNG test cases. |
86 | std::tr1::mersenne_twister< | |
87 | unsigned long, 32, 624, 397, 31, | |
88 | 0x9908b0dful, 11, 7, | |
89 | 0x9d2c5680ul, 15, | |
90 | 0xefc60000ul, 18> rng; | |
91 | ||
92 | sp_vector_t::iterator cur_shared = pools.shared_pool.begin(); | |
93 | wp_vector_t::iterator cur_weak = pools.weak_pool.begin(); | |
94 | ||
95 | for (unsigned int i = 0; i < HAMMER_REPEAT; ++i) | |
96 | { | |
97 | try | |
98 | { | |
99 | sp_A_t strong(*cur_weak); | |
100 | } | |
101 | catch (std::tr1::bad_weak_ptr& exception) | |
102 | { | |
103 | ++cur_weak; | |
104 | if (cur_weak == pools.weak_pool.end()) | |
105 | break; | |
106 | } | |
107 | ||
108 | if (rng() % KILL_ONE_IN == 0) | |
109 | { | |
110 | cur_shared->reset(); | |
111 | ++cur_shared; | |
112 | } | |
113 | } | |
114 | return 0; | |
115 | } | |
116 | ||
117 | void* thread_hammer(void* opaque_weak) | |
118 | { | |
045fcc24 | 119 | wp_vector_t& weak_pool = *static_cast<wp_vector_t*>(opaque_weak); |
a25ce4db PJ |
120 | // Using the same parameters as in the RNG test cases. |
121 | std::tr1::mersenne_twister< | |
122 | unsigned long, 32, 624, 397, 31, | |
123 | 0x9908b0dful, 11, 7, | |
124 | 0x9d2c5680ul, 15, | |
125 | 0xefc60000ul, 18> rng; | |
126 | wp_vector_t::iterator cur_weak = weak_pool.begin(); | |
127 | ||
128 | for (unsigned int i = 0; i < HAMMER_REPEAT; ++i) | |
129 | { | |
130 | try | |
131 | { | |
132 | sp_A_t strong(*cur_weak); | |
133 | } | |
134 | catch (std::tr1::bad_weak_ptr& exception) | |
135 | { | |
136 | ++cur_weak; | |
137 | if (cur_weak == weak_pool.end()) | |
138 | break; | |
139 | } | |
140 | } | |
141 | return 0; | |
142 | } | |
143 | ||
144 | int | |
145 | test01() | |
146 | { | |
147 | bool test __attribute__((unused)) = true; | |
148 | sp_vector_t obj_pool(POOL_SIZE); | |
149 | ||
150 | for(sp_vector_t::iterator cur = obj_pool.begin(); cur != obj_pool.end(); ++cur) | |
151 | { | |
152 | cur->reset(new A); | |
153 | } | |
154 | // Obtain weak references. | |
155 | std::vector<wp_vector_t> weak_pool(HAMMER_MAX_THREADS, wp_vector_t(obj_pool.begin(), obj_pool.end())); | |
156 | ||
157 | // Launch threads with pointer to weak reference. | |
158 | pthread_t threads[HAMMER_MAX_THREADS]; | |
159 | #if defined(__sun) && defined(__svr4__) && _XOPEN_VERSION >= 500 | |
160 | pthread_setconcurrency (HAMMER_MAX_THREADS); | |
161 | #endif | |
162 | ||
163 | pthread_attr_t tattr; | |
7919bb2f | 164 | pthread_attr_init(&tattr); |
a25ce4db PJ |
165 | |
166 | shared_and_weak_pools pools(obj_pool, weak_pool[0]); | |
045fcc24 | 167 | pthread_create(threads, &tattr, thread_hammer_and_kill, static_cast<void*>(&pools)); |
a25ce4db PJ |
168 | for (unsigned int worker = 1; worker < HAMMER_MAX_THREADS; worker++) |
169 | { | |
170 | if (pthread_create(&threads[worker], &tattr, | |
045fcc24 | 171 | thread_hammer, static_cast<void*>(&weak_pool[worker]))) |
debac9f4 | 172 | std::abort(); |
a25ce4db PJ |
173 | } |
174 | // Wait for threads to complete, then check integrity of reference. | |
175 | void* status; | |
176 | for (unsigned int worker = 0; worker < HAMMER_MAX_THREADS; worker++) | |
177 | { | |
178 | if (pthread_join(threads[worker], &status)) | |
debac9f4 | 179 | std::abort(); |
a25ce4db PJ |
180 | } |
181 | obj_pool.clear(); | |
182 | ||
183 | VERIFY( A::counter == 0 ); | |
184 | ||
185 | return 0; | |
186 | } | |
187 | ||
188 | int | |
189 | main() | |
190 | { | |
191 | test01(); | |
192 | return 0; | |
193 | } |