1 // { dg-options "-std=gnu++2a" }
2 // { dg-do run { target c++2a } }
3 // { dg-require-gthreads "" }
4 // { dg-additional-options "-pthread" { target pthread } }
5 // { dg-add-options libatomic }
6 
7 // Copyright (C) 2021 Free Software Foundation, Inc.
8 //
9 // This file is part of the GNU ISO C++ Library.  This library is free
10 // software; you can redistribute it and/or modify it under the
11 // terms of the GNU General Public License as published by the
12 // Free Software Foundation; either version 3, or (at your option)
13 // any later version.
14 
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 
20 // You should have received a copy of the GNU General Public License along
21 // with this library; see the file COPYING3.  If not see
22 // <http://www.gnu.org/licenses/>.
23 
24 #include <atomic>
25 #include <future>
26 
27 #include <testsuite_hooks.h>
28 
29 template <typename T>
30 struct atomics_sharing_same_waiter
31 {
32    std::atomic<T> tmp[49 * 4] = {};
33    std::atomic<T>* a[4] = {
34       { &tmp[0] },
35       { &tmp[16 * 4] },
36       { &tmp[32 * 4] },
37       { &tmp[48 * 4] }
38    };
39 };
40 
key(void * a)41 constexpr unsigned key(void * a)
42 {
43   constexpr uintptr_t ct = 16;
44   return (uintptr_t(a) >> 2) % ct;
45 }
46 
47 int
main()48 main()
49 {
50   // all atomic share the same waiter
51 //  atomics_sharing_same_waiter<char> atomics;
52   atomics_sharing_same_waiter<char> atomics;
53   for (auto& atom : atomics.a)
54   {
55     atom->store(0);
56   }
57 
58   auto a = &std::__detail::__waiter_pool_base::_S_for(reinterpret_cast<char *>(atomics.a[0]));
59   auto b = &std::__detail::__waiter_pool_base::_S_for(reinterpret_cast<char *>(atomics.a[1]));
60   VERIFY( a == b );
61 
62   auto fut0 = std::async(std::launch::async, [&] { atomics.a[0]->wait(0); });
63   auto fut1 = std::async(std::launch::async, [&] { atomics.a[1]->wait(0); });
64   auto fut2 = std::async(std::launch::async, [&] { atomics.a[2]->wait(0); });
65   auto fut3 = std::async(std::launch::async, [&] { atomics.a[3]->wait(0); });
66 
67   // make sure the all threads already await
68   std::this_thread::sleep_for(std::chrono::milliseconds{100});
69 
70   atomics.a[2]->store(1);
71   atomics.a[2]->notify_one();
72 
73   VERIFY(std::future_status::timeout == fut0.wait_for(std::chrono::milliseconds{100}));
74   VERIFY(atomics.a[0]->load() == 0);
75 
76   VERIFY(std::future_status::timeout == fut1.wait_for(std::chrono::milliseconds{100}));
77   VERIFY(atomics.a[1]->load() == 0);
78 
79   VERIFY(std::future_status::ready == fut2.wait_for(std::chrono::milliseconds{100}));
80   VERIFY(atomics.a[2]->load() == 1);
81 
82   VERIFY(std::future_status::timeout == fut3.wait_for(std::chrono::milliseconds{100}));
83   VERIFY(atomics.a[3]->load() == 0);
84 
85   atomics.a[0]->store(1);
86   atomics.a[0]->notify_one();
87   atomics.a[1]->store(1);
88   atomics.a[1]->notify_one();
89   atomics.a[3]->store(1);
90   atomics.a[3]->notify_one();
91 
92   return 0;
93 }
94