1// Copyright (C) 2006-2015 Free Software Foundation, Inc. 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// 20.6.6.2 Template class shared_ptr [util.smartptr.shared] 19 20// { dg-do run { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* *-*-solaris* *-*-cygwin *-*-darwin* } } 21// { dg-options " -std=gnu++11 -pthread" { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* } } 22// { dg-options " -std=gnu++11 -pthreads" { target *-*-solaris* } } 23// { dg-options " -std=gnu++11 " { target *-*-cygwin *-*-darwin* } } 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 47const unsigned int HAMMER_MAX_THREADS = 10; 48const unsigned int POOL_SIZE = 1000; 49const unsigned long HAMMER_REPEAT = 100000; 50const unsigned long KILL_ONE_IN = 1000; 51 52struct 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 67using std::_S_mutex; 68 69typedef std::__shared_ptr<A, _S_mutex> sp_A_t; 70typedef std::__weak_ptr<A, _S_mutex> wp_A_t; 71 72typedef std::vector<sp_A_t> sp_vector_t; 73typedef std::vector<wp_A_t> wp_vector_t; 74 75struct shared_and_weak_pools 76{ 77 sp_vector_t& shared_pool; 78 wp_vector_t& weak_pool; 79 80 shared_and_weak_pools(sp_vector_t& _shared_pool, wp_vector_t& _weak_pool) 81 : shared_pool(_shared_pool), weak_pool(_weak_pool) 82 { } 83}; 84 85void* thread_hammer_and_kill(void* opaque_pools) 86{ 87 shared_and_weak_pools& pools = *static_cast<shared_and_weak_pools*>(opaque_pools); 88 // Using the same parameters as in the RNG test cases. 89 std::mersenne_twister_engine< 90 unsigned long, 32, 624, 397, 31, 91 0x9908b0dful, 11, 92 0xfffffffful, 7, 93 0x9d2c5680ul, 15, 94 0xefc60000ul, 18, 1812433253ul> rng; 95 96 sp_vector_t::iterator cur_shared = pools.shared_pool.begin(); 97 wp_vector_t::iterator cur_weak = pools.weak_pool.begin(); 98 99 for (unsigned int i = 0; i < HAMMER_REPEAT; ++i) 100 { 101 try 102 { 103 sp_A_t strong(*cur_weak); 104 } 105 catch (std::bad_weak_ptr& exception) 106 { 107 ++cur_weak; 108 if (cur_weak == pools.weak_pool.end()) 109 break; 110 } 111 112 if (rng() % KILL_ONE_IN == 0) 113 { 114 cur_shared->reset(); 115 ++cur_shared; 116 } 117 } 118 return 0; 119} 120 121void* thread_hammer(void* opaque_weak) 122{ 123 wp_vector_t& weak_pool = *static_cast<wp_vector_t*>(opaque_weak); 124 // Using the same parameters as in the RNG test cases. 125 std::mersenne_twister_engine< 126 unsigned long, 32, 624, 397, 31, 127 0x9908b0dful, 11, 128 0xfffffffful, 7, 129 0x9d2c5680ul, 15, 130 0xefc60000ul, 18, 1812433253ul> rng; 131 132 wp_vector_t::iterator cur_weak = weak_pool.begin(); 133 134 for (unsigned int i = 0; i < HAMMER_REPEAT; ++i) 135 { 136 try 137 { 138 sp_A_t strong(*cur_weak); 139 } 140 catch (std::bad_weak_ptr& exception) 141 { 142 ++cur_weak; 143 if (cur_weak == weak_pool.end()) 144 break; 145 } 146 } 147 return 0; 148} 149 150int 151test01() 152{ 153 bool test __attribute__((unused)) = true; 154 sp_vector_t obj_pool(POOL_SIZE); 155 156 for(sp_vector_t::iterator cur = obj_pool.begin(); cur != obj_pool.end(); ++cur) 157 { 158 cur->reset(new A); 159 } 160 // Obtain weak references. 161 std::vector<wp_vector_t> weak_pool(HAMMER_MAX_THREADS, wp_vector_t(obj_pool.begin(), obj_pool.end())); 162 163 // Launch threads with pointer to weak reference. 164 pthread_t threads[HAMMER_MAX_THREADS]; 165#if defined(__sun) && defined(__svr4__) && _XOPEN_VERSION >= 500 166 pthread_setconcurrency (HAMMER_MAX_THREADS); 167#endif 168 169 pthread_attr_t tattr; 170 pthread_attr_init(&tattr); 171 172 shared_and_weak_pools pools(obj_pool, weak_pool[0]); 173 pthread_create(threads, &tattr, thread_hammer_and_kill, static_cast<void*>(&pools)); 174 for (unsigned int worker = 1; worker < HAMMER_MAX_THREADS; worker++) 175 { 176 if (pthread_create(&threads[worker], &tattr, 177 thread_hammer, static_cast<void*>(&weak_pool[worker]))) 178 std::abort(); 179 } 180 // Wait for threads to complete, then check integrity of reference. 181 void* status; 182 for (unsigned int worker = 0; worker < HAMMER_MAX_THREADS; worker++) 183 { 184 if (pthread_join(threads[worker], &status)) 185 std::abort(); 186 } 187 obj_pool.clear(); 188 189 VERIFY( A::counter == 0 ); 190 191 return 0; 192} 193 194int 195main() 196{ 197 test01(); 198 return 0; 199} 200