• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===----------------------------------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // UNSUPPORTED: libcpp-has-no-threads
11 
12 // <mutex>
13 
14 // struct once_flag;
15 
16 // template<class Callable, class ...Args>
17 //   void call_once(once_flag& flag, Callable func, Args&&... args);
18 
19 #include <mutex>
20 #include <thread>
21 #include <cassert>
22 
23 typedef std::chrono::milliseconds ms;
24 
25 std::once_flag flg0;
26 
27 int init0_called = 0;
28 
init0()29 void init0()
30 {
31     std::this_thread::sleep_for(ms(250));
32     ++init0_called;
33 }
34 
f0()35 void f0()
36 {
37     std::call_once(flg0, init0);
38 }
39 
40 std::once_flag flg3;
41 
42 int init3_called = 0;
43 int init3_completed = 0;
44 
init3()45 void init3()
46 {
47     ++init3_called;
48     std::this_thread::sleep_for(ms(250));
49     if (init3_called == 1)
50         throw 1;
51     ++init3_completed;
52 }
53 
f3()54 void f3()
55 {
56     try
57     {
58         std::call_once(flg3, init3);
59     }
60     catch (...)
61     {
62     }
63 }
64 
65 #ifndef _LIBCPP_HAS_NO_VARIADICS
66 
67 struct init1
68 {
69     static int called;
70 
operator ()init171     void operator()(int i) {called += i;}
72 };
73 
74 int init1::called = 0;
75 
76 std::once_flag flg1;
77 
f1()78 void f1()
79 {
80     std::call_once(flg1, init1(), 1);
81 }
82 
83 struct init2
84 {
85     static int called;
86 
operator ()init287     void operator()(int i, int j) const {called += i + j;}
88 };
89 
90 int init2::called = 0;
91 
92 std::once_flag flg2;
93 
f2()94 void f2()
95 {
96     std::call_once(flg2, init2(), 2, 3);
97     std::call_once(flg2, init2(), 4, 5);
98 }
99 
100 #endif  // _LIBCPP_HAS_NO_VARIADICS
101 
102 std::once_flag flg41;
103 std::once_flag flg42;
104 
105 int init41_called = 0;
106 int init42_called = 0;
107 
108 void init42();
109 
init41()110 void init41()
111 {
112     std::this_thread::sleep_for(ms(250));
113     ++init41_called;
114 }
115 
init42()116 void init42()
117 {
118     std::this_thread::sleep_for(ms(250));
119     ++init42_called;
120 }
121 
f41()122 void f41()
123 {
124     std::call_once(flg41, init41);
125     std::call_once(flg42, init42);
126 }
127 
f42()128 void f42()
129 {
130     std::call_once(flg42, init42);
131     std::call_once(flg41, init41);
132 }
133 
134 #ifndef _LIBCPP_HAS_NO_VARIADICS
135 
136 class MoveOnly
137 {
138 #if !defined(__clang__)
139    // GCC 4.8 complains about the following being private
140 public:
MoveOnly(const MoveOnly &)141     MoveOnly(const MoveOnly&)
142     {
143     }
144 #else
145     MoveOnly(const MoveOnly&);
146 #endif
147 public:
MoveOnly()148     MoveOnly() {}
MoveOnly(MoveOnly &&)149     MoveOnly(MoveOnly&&) {}
150 
operator ()(MoveOnly &&)151     void operator()(MoveOnly&&)
152     {
153     }
154 };
155 
156 #endif
157 
main()158 int main()
159 {
160     // check basic functionality
161     {
162         std::thread t0(f0);
163         std::thread t1(f0);
164         t0.join();
165         t1.join();
166         assert(init0_called == 1);
167     }
168     // check basic exception safety
169     {
170         std::thread t0(f3);
171         std::thread t1(f3);
172         t0.join();
173         t1.join();
174         assert(init3_called == 2);
175         assert(init3_completed == 1);
176     }
177     // check deadlock avoidance
178     {
179         std::thread t0(f41);
180         std::thread t1(f42);
181         t0.join();
182         t1.join();
183         assert(init41_called == 1);
184         assert(init42_called == 1);
185     }
186 #ifndef _LIBCPP_HAS_NO_VARIADICS
187     // check functors with 1 arg
188     {
189         std::thread t0(f1);
190         std::thread t1(f1);
191         t0.join();
192         t1.join();
193         assert(init1::called == 1);
194     }
195     // check functors with 2 args
196     {
197         std::thread t0(f2);
198         std::thread t1(f2);
199         t0.join();
200         t1.join();
201         assert(init2::called == 5);
202     }
203     {
204         std::once_flag f;
205         std::call_once(f, MoveOnly(), MoveOnly());
206     }
207 #endif  // _LIBCPP_HAS_NO_VARIADICS
208 }
209