1 // Copyright (C) 2020-2021 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 // { dg-options "-std=gnu++2a -pthread" }
19 // { dg-do run { target c++2a } }
20 // { dg-require-effective-target pthread }
21 // { dg-require-gthreads "" }
22 // { dg-add-options libatomic }
23 
24 #include <semaphore>
25 #ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
26 #include <chrono>
27 #include <thread>
28 #include <atomic>
29 #include <testsuite_hooks.h>
30 
test01()31 void test01()
32 {
33   using namespace std::chrono_literals;
34   std::__platform_semaphore s(2);
35   s._M_acquire();
36 
37   auto const dur = 250ms;
38   {
39     auto const t0 = std::chrono::steady_clock::now();
40     VERIFY( s._M_try_acquire_for(dur) );
41     auto const diff = std::chrono::steady_clock::now() - t0;
42     VERIFY( diff < dur );
43   }
44 
45   {
46     auto const t0 = std::chrono::steady_clock::now();
47     VERIFY( !s._M_try_acquire_for(dur) );
48     auto const diff = std::chrono::steady_clock::now() - t0;
49     VERIFY( diff >= dur );
50   }
51 }
52 
test02()53 void test02()
54 {
55   using namespace std::chrono_literals;
56   std::__platform_semaphore s(1);
57   std::atomic<int> a(0), b(0);
58   std::thread t([&] {
59     a.wait(0);
60     auto const dur = 250ms;
61     VERIFY( !s._M_try_acquire_for(dur) );
62     b++;
63     b.notify_one();
64 
65     a.wait(1);
66     VERIFY( s._M_try_acquire_for(dur) );
67     b++;
68     b.notify_one();
69   });
70   t.detach();
71 
72   s._M_acquire();
73   a++;
74   a.notify_one();
75   b.wait(0);
76   s._M_release(1);
77   a++;
78   a.notify_one();
79 
80   b.wait(1);
81 }
82 
test03()83 void test03()
84 {
85   using namespace std::chrono_literals;
86   std::__platform_semaphore s(2);
87   s._M_acquire();
88 
89   auto const dur = 250ms;
90   {
91     auto const at = std::chrono::system_clock::now() + dur;
92     auto const t0 = std::chrono::steady_clock::now();
93     VERIFY( s._M_try_acquire_until(at) );
94     auto const diff = std::chrono::steady_clock::now() - t0;
95     VERIFY( diff < dur );
96   }
97 
98   {
99     auto const at = std::chrono::system_clock::now() + dur;
100     auto const t0 = std::chrono::steady_clock::now();
101     VERIFY( !s._M_try_acquire_until(at) );
102     auto const diff = std::chrono::steady_clock::now() - t0;
103     VERIFY( diff >= dur );
104   }
105 }
106 
test04()107 void test04()
108 {
109   using namespace std::chrono_literals;
110   std::__platform_semaphore s(1);
111   std::atomic<int> a(0), b(0);
112   std::thread t([&] {
113     a.wait(0);
114     auto const dur = 250ms;
115     {
116       auto const at = std::chrono::system_clock::now() + dur;
117       VERIFY( !s._M_try_acquire_until(at) );
118 
119       b++;
120       b.notify_one();
121     }
122 
123     a.wait(1);
124     {
125       auto const at = std::chrono::system_clock::now() + dur;
126       VERIFY( s._M_try_acquire_until(at) );
127     }
128     b++;
129     b.notify_one();
130   });
131   t.detach();
132 
133   s._M_acquire();
134   a++;
135   a.notify_one();
136   b.wait(0);
137   s._M_release(1);
138   a++;
139   a.notify_one();
140 
141   b.wait(1);
142 }
143 #endif
144 
main()145 int main()
146 {
147 #ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
148   test01();
149   test02();
150   test03();
151   test04();
152 #endif
153   return 0;
154 }
155