]>
Commit | Line | Data |
---|---|---|
748086b7 | 1 | // Copyright (C) 2006, 2007, 2009 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 | ||
40f5cc95 RO |
20 | // { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* mips-sgi-irix6* } } |
21 | // { dg-options "-pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* alpha*-*-osf* 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 | ||
66 | using std::tr1::_S_mutex; | |
67 | ||
68 | typedef std::tr1::__shared_ptr<A, _S_mutex> sp_A_t; | |
69 | typedef std::tr1::__weak_ptr<A, _S_mutex> wp_A_t; | |
70 | ||
71 | typedef std::vector<sp_A_t> sp_vector_t; | |
72 | typedef std::vector<wp_A_t> wp_vector_t; | |
73 | ||
74 | struct shared_and_weak_pools | |
75 | { | |
76 | sp_vector_t& shared_pool; | |
77 | wp_vector_t& weak_pool; | |
78 | ||
79 | shared_and_weak_pools(sp_vector_t& _shared_pool, wp_vector_t& _weak_pool) | |
80 | : shared_pool(_shared_pool), weak_pool(_weak_pool) | |
81 | { } | |
82 | }; | |
83 | ||
84 | void* thread_hammer_and_kill(void* opaque_pools) | |
85 | { | |
045fcc24 | 86 | shared_and_weak_pools& pools = *static_cast<shared_and_weak_pools*>(opaque_pools); |
a25ce4db PJ |
87 | // Using the same parameters as in the RNG test cases. |
88 | std::tr1::mersenne_twister< | |
89 | unsigned long, 32, 624, 397, 31, | |
90 | 0x9908b0dful, 11, 7, | |
91 | 0x9d2c5680ul, 15, | |
92 | 0xefc60000ul, 18> rng; | |
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::tr1::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 | { | |
045fcc24 | 121 | wp_vector_t& weak_pool = *static_cast<wp_vector_t*>(opaque_weak); |
a25ce4db PJ |
122 | // Using the same parameters as in the RNG test cases. |
123 | std::tr1::mersenne_twister< | |
124 | unsigned long, 32, 624, 397, 31, | |
125 | 0x9908b0dful, 11, 7, | |
126 | 0x9d2c5680ul, 15, | |
127 | 0xefc60000ul, 18> rng; | |
128 | wp_vector_t::iterator cur_weak = weak_pool.begin(); | |
129 | ||
130 | for (unsigned int i = 0; i < HAMMER_REPEAT; ++i) | |
131 | { | |
132 | try | |
133 | { | |
134 | sp_A_t strong(*cur_weak); | |
135 | } | |
136 | catch (std::tr1::bad_weak_ptr& exception) | |
137 | { | |
138 | ++cur_weak; | |
139 | if (cur_weak == weak_pool.end()) | |
140 | break; | |
141 | } | |
142 | } | |
143 | return 0; | |
144 | } | |
145 | ||
146 | int | |
147 | test01() | |
148 | { | |
149 | bool test __attribute__((unused)) = true; | |
150 | sp_vector_t obj_pool(POOL_SIZE); | |
151 | ||
152 | for(sp_vector_t::iterator cur = obj_pool.begin(); cur != obj_pool.end(); ++cur) | |
153 | { | |
154 | cur->reset(new A); | |
155 | } | |
156 | // Obtain weak references. | |
157 | std::vector<wp_vector_t> weak_pool(HAMMER_MAX_THREADS, wp_vector_t(obj_pool.begin(), obj_pool.end())); | |
158 | ||
159 | // Launch threads with pointer to weak reference. | |
160 | pthread_t threads[HAMMER_MAX_THREADS]; | |
161 | #if defined(__sun) && defined(__svr4__) && _XOPEN_VERSION >= 500 | |
162 | pthread_setconcurrency (HAMMER_MAX_THREADS); | |
163 | #endif | |
164 | ||
165 | pthread_attr_t tattr; | |
7919bb2f | 166 | pthread_attr_init(&tattr); |
a25ce4db PJ |
167 | |
168 | shared_and_weak_pools pools(obj_pool, weak_pool[0]); | |
045fcc24 | 169 | pthread_create(threads, &tattr, thread_hammer_and_kill, static_cast<void*>(&pools)); |
a25ce4db PJ |
170 | for (unsigned int worker = 1; worker < HAMMER_MAX_THREADS; worker++) |
171 | { | |
172 | if (pthread_create(&threads[worker], &tattr, | |
045fcc24 | 173 | thread_hammer, static_cast<void*>(&weak_pool[worker]))) |
debac9f4 | 174 | std::abort(); |
a25ce4db PJ |
175 | } |
176 | // Wait for threads to complete, then check integrity of reference. | |
177 | void* status; | |
178 | for (unsigned int worker = 0; worker < HAMMER_MAX_THREADS; worker++) | |
179 | { | |
180 | if (pthread_join(threads[worker], &status)) | |
debac9f4 | 181 | std::abort(); |
a25ce4db PJ |
182 | } |
183 | obj_pool.clear(); | |
184 | ||
185 | VERIFY( A::counter == 0 ); | |
186 | ||
187 | return 0; | |
188 | } | |
189 | ||
190 | int | |
191 | main() | |
192 | { | |
193 | test01(); | |
194 | return 0; | |
195 | } |