1// Copyright (C) 2006, 2007, 2009 Free Software Foundation 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 6// Free Software Foundation; either version 3, or (at your option) 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 15// with this library; see the file COPYING3. If not see 16// <http://www.gnu.org/licenses/>. 17 18// TR1 2.2.2 Template class shared_ptr [tr.util.smartptr.shared] 19 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* } } 22// { dg-options "-pthreads" { target *-*-solaris* } } 23 24#include <tr1/memory> 25#include <tr1/random> 26#include <vector> 27#include <testsuite_hooks.h> 28#include <iostream> 29#include <cstdlib> 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 46const unsigned int HAMMER_MAX_THREADS = 10; 47const unsigned int POOL_SIZE = 1000; 48const unsigned long HAMMER_REPEAT = 100000; 49const unsigned long KILL_ONE_IN = 1000; 50 51struct 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 66typedef std::tr1::shared_ptr<A> sp_A_t; 67typedef std::tr1::weak_ptr<A> wp_A_t; 68 69typedef std::vector<sp_A_t> sp_vector_t; 70typedef std::vector<wp_A_t> wp_vector_t; 71 72struct 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 82void* thread_hammer_and_kill(void* opaque_pools) 83{ 84 shared_and_weak_pools& pools = *static_cast<shared_and_weak_pools*>(opaque_pools); 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 117void* thread_hammer(void* opaque_weak) 118{ 119 wp_vector_t& weak_pool = *static_cast<wp_vector_t*>(opaque_weak); 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 144int 145test01() 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; 164 pthread_attr_init(&tattr); 165 166 shared_and_weak_pools pools(obj_pool, weak_pool[0]); 167 pthread_create(threads, &tattr, thread_hammer_and_kill, static_cast<void*>(&pools)); 168 for (unsigned int worker = 1; worker < HAMMER_MAX_THREADS; worker++) 169 { 170 if (pthread_create(&threads[worker], &tattr, 171 thread_hammer, static_cast<void*>(&weak_pool[worker]))) 172 std::abort(); 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)) 179 std::abort(); 180 } 181 obj_pool.clear(); 182 183 VERIFY( A::counter == 0 ); 184 185 return 0; 186} 187 188int 189main() 190{ 191 test01(); 192 return 0; 193} 194