1#	$NetBSD: t_call_once2.sh,v 1.8 2022/09/29 07:22:49 skrll Exp $
2#
3# Copyright (c) 2018 The NetBSD Foundation, Inc.
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25# POSSIBILITY OF SUCH DAMAGE.
26#
27
28atf_test_case call_once2
29call_once2_head() {
30	atf_set "descr" "compile and run std::call_once"
31	atf_set "require.progs" "c++"
32	atf_set "timeout" "600"
33}
34
35atf_test_case call_once2_profile
36call_once2_profile_head() {
37	atf_set "descr" "compile and run std::call_once with profiling option"
38	atf_set "require.progs" "c++"
39	atf_set "timeout" "600"
40}
41
42atf_test_case call_once2_pic
43call_once2_pic_head() {
44	atf_set "descr" "compile and run PIC std::call_once"
45	atf_set "require.progs" "c++"
46	atf_set "timeout" "600"
47}
48
49atf_test_case call_once2_pic_32
50call_once2_pic_32_head() {
51	atf_set "descr" "compile and run 32-bit PIC std::call_once"
52	atf_set "require.progs" "c++"
53	atf_set "timeout" "600"
54}
55
56atf_test_case call_once2_pic_profile
57call_once2_pic_profile_head() {
58	atf_set "descr" "compile and run PIC std::call_once with profiling flag"
59	atf_set "require.progs" "c++"
60	atf_set "timeout" "600"
61}
62
63atf_test_case call_once2_pic_profile_32
64call_once2_pic_profile_32_head() {
65	atf_set "descr" "compile and run 32-bit PIC std::call_once with profiling flag"
66	atf_set "require.progs" "c++"
67	atf_set "timeout" "600"
68}
69
70atf_test_case call_once2_profile_32
71call_once2_profile_32_head() {
72	atf_set "descr" "compile and run 32-bit std::call_once with profiling flag"
73	atf_set "require.progs" "c++"
74	atf_set "timeout" "600"
75}
76
77atf_test_case call_once2_pie
78call_once2_pie_head() {
79	atf_set "descr" "compile and run position independent (PIE) std::call_once"
80	atf_set "require.progs" "c++"
81	atf_set "timeout" "600"
82}
83
84atf_test_case call_once2_32
85call_once2_32_head() {
86	atf_set "descr" "compile and run std::call_once for/in netbsd32 emulation"
87	atf_set "require.progs" "c++ file diff cat"
88	atf_set "timeout" "600"
89}
90
91atf_test_case call_once2_static
92call_once2_static_head() {
93	atf_set "descr" "compile and run std::call_once with static flag"
94	atf_set "require.progs" "c++"
95	atf_set "timeout" "600"
96}
97
98call_once2_body() {
99	cat > test.cpp << EOF
100#include <mutex>
101#include <thread>
102#include <iostream>
103std::once_flag flag, flag_throw;
104void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
105void throw_once(void) { throw std::exception(); }
106int main(void) {
107        static const int nr_threads(4);
108        std::thread threads[nr_threads];
109
110        for (int i = 0; i < nr_threads; ++i) {
111                threads[i] = std::thread(print_once);
112        }
113        for (int i = 0; i < nr_threads; ++i) {
114                threads[i].join();
115        }
116
117        try {
118                std::call_once(flag_throw, throw_once);
119        } catch (...) {
120                std::cout << "world!" << std::endl;
121        }
122        return 0;
123}
124EOF
125	atf_check -s exit:0 -o ignore -e ignore c++ -o call_once2 test.cpp -pthread
126	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2
127}
128
129call_once2_profile_body() {
130	atf_expect_fail "profiling option doesn't work with shared libraries"
131	cat > test.cpp << EOF
132#include <mutex>
133#include <thread>
134#include <iostream>
135std::once_flag flag, flag_throw;
136void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
137void throw_once(void) { throw std::exception(); }
138int main(void) {
139        static const int nr_threads(4);
140        std::thread threads[nr_threads];
141
142        for (int i = 0; i < nr_threads; ++i) {
143                threads[i] = std::thread(print_once);
144        }
145        for (int i = 0; i < nr_threads; ++i) {
146                threads[i].join();
147        }
148
149        try {
150                std::call_once(flag_throw, throw_once);
151        } catch (...) {
152                std::cout << "world!" << std::endl;
153        }
154        return 0;
155}
156EOF
157	atf_check -s exit:0 -o ignore -e ignore c++ -pg -o call_once2 test.cpp -pthread
158	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2
159}
160
161call_once2_profile_32_body() {
162	atf_expect_fail "profiling option doesn't work now"
163	# check whether this arch is 64bit
164	if ! c++ -dM -E - < /dev/null | fgrep -q _LP64; then
165		atf_skip "this is not a 64 bit architecture"
166	fi
167	if ! c++ -m32 -dM -E - < /dev/null 2>/dev/null > ./def32; then
168		atf_skip "c++ -m32 not supported on this architecture"
169	else
170		if fgrep -q _LP64 ./def32; then
171			atf_fail "c++ -m32 does not generate netbsd32 binaries"
172		fi
173	fi
174
175	cat > test.cpp << EOF
176#include <mutex>
177#include <thread>
178#include <iostream>
179std::once_flag flag, flag_throw;
180void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
181void throw_once(void) { throw std::exception(); }
182int main(void) {
183        static const int nr_threads(4);
184        std::thread threads[nr_threads];
185
186        for (int i = 0; i < nr_threads; ++i) {
187                threads[i] = std::thread(print_once);
188        }
189        for (int i = 0; i < nr_threads; ++i) {
190                threads[i].join();
191        }
192
193        try {
194                std::call_once(flag_throw, throw_once);
195        } catch (...) {
196                std::cout << "world!" << std::endl;
197        }
198        return 0;
199}
200EOF
201	atf_check -s exit:0 -o ignore -e ignore c++ -m32 -pg -o call_once2 test.cpp -pthread
202	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2
203	atf_expect_fail "The combination of 32-bit and profiling should be fail"
204}
205
206call_once2_pic_body() {
207	cat > test.cpp << EOF
208#include <stdlib.h>
209int callpic(void);
210int main(void) {callpic();exit(0);}
211EOF
212	cat > pic.cpp << EOF
213#include <mutex>
214#include <thread>
215#include <iostream>
216std::once_flag flag, flag_throw;
217void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
218void throw_once(void) { throw std::exception(); }
219int callpic(void) {
220        static const int nr_threads(4);
221        std::thread threads[nr_threads];
222
223        for (int i = 0; i < nr_threads; ++i) {
224                threads[i] = std::thread(print_once);
225        }
226        for (int i = 0; i < nr_threads; ++i) {
227                threads[i].join();
228        }
229
230        try {
231                std::call_once(flag_throw, throw_once);
232        } catch (...) {
233                std::cout << "world!" << std::endl;
234        }
235        return 0;
236}
237EOF
238
239	atf_check -s exit:0 -o ignore -e ignore \
240	    c++ -fPIC -shared -o libtest.so pic.cpp
241	atf_check -s exit:0 -o ignore -e ignore \
242	    c++ -o call_once2 test.cpp -L. -ltest -pthread
243
244	export LD_LIBRARY_PATH=.
245	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2
246}
247
248call_once2_pic_32_body() {
249	# check whether this arch is 64bit
250	if ! c++ -dM -E - < /dev/null | fgrep -q _LP64; then
251		atf_skip "this is not a 64 bit architecture"
252	fi
253	if ! c++ -m32 -dM -E - < /dev/null 2>/dev/null > ./def32; then
254		atf_skip "c++ -m32 not supported on this architecture"
255	else
256		if fgrep -q _LP64 ./def32; then
257			atf_fail "c++ -m32 does not generate netbsd32 binaries"
258		fi
259	fi
260
261	cat > test.cpp << EOF
262#include <stdlib.h>
263int callpic(void);
264int main(void) {callpic();exit(0);}
265EOF
266	cat > pic.cpp << EOF
267#include <mutex>
268#include <thread>
269#include <iostream>
270std::once_flag flag, flag_throw;
271void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
272void throw_once(void) { throw std::exception(); }
273int callpic(void) {
274        static const int nr_threads(4);
275        std::thread threads[nr_threads];
276
277        for (int i = 0; i < nr_threads; ++i) {
278                threads[i] = std::thread(print_once);
279        }
280        for (int i = 0; i < nr_threads; ++i) {
281                threads[i].join();
282        }
283
284        try {
285                std::call_once(flag_throw, throw_once);
286        } catch (...) {
287                std::cout << "world!" << std::endl;
288        }
289        return 0;
290}
291EOF
292
293	atf_check -s exit:0 -o ignore -e ignore \
294	    c++ -m32 -fPIC -shared -o libtest.so pic.cpp
295	atf_check -s exit:0 -o ignore -e ignore \
296	    c++ -m32 -o call_once2 test.cpp -L. -ltest -pthread
297
298	export LD_LIBRARY_PATH=.
299	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2
300}
301
302call_once2_pic_profile_body() {
303	atf_expect_fail "profiling option doesn't work with pic"
304	cat > test.cpp << EOF
305#include <stdlib.h>
306int callpic(void);
307int main(void) {callpic();exit(0);}
308EOF
309	cat > pic.cpp << EOF
310#include <mutex>
311#include <thread>
312#include <iostream>
313std::once_flag flag, flag_throw;
314void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
315void throw_once(void) { throw std::exception(); }
316int callpic(void) {
317        static const int nr_threads(4);
318        std::thread threads[nr_threads];
319
320        for (int i = 0; i < nr_threads; ++i) {
321                threads[i] = std::thread(print_once);
322        }
323        for (int i = 0; i < nr_threads; ++i) {
324                threads[i].join();
325        }
326
327        try {
328                std::call_once(flag_throw, throw_once);
329        } catch (...) {
330                std::cout << "world!" << std::endl;
331        }
332        return 0;
333}
334EOF
335
336	atf_check -s exit:0 -o ignore -e ignore \
337	    c++ -pg -fPIC -shared -o libtest.so pic.cpp
338	atf_check -s exit:0 -o ignore -e ignore \
339	    c++ -pg -o call_once2 test.cpp -L. -ltest -pthread
340
341	export LD_LIBRARY_PATH=.
342	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2
343}
344
345call_once2_pic_profile_32_body() {
346	atf_expect_fail "profiling option doesn't work with shared libraries"
347	# check whether this arch is 64bit
348	if ! c++ -dM -E - < /dev/null | fgrep -q _LP64; then
349		atf_skip "this is not a 64 bit architecture"
350	fi
351	if ! c++ -m32 -dM -E - < /dev/null 2>/dev/null > ./def32; then
352		atf_skip "c++ -m32 not supported on this architecture"
353	else
354		if fgrep -q _LP64 ./def32; then
355			atf_fail "c++ -m32 does not generate netbsd32 binaries"
356		fi
357	fi
358
359	cat > test.cpp << EOF
360#include <stdlib.h>
361int callpic(void);
362int main(void) {callpic();exit(0);}
363EOF
364	cat > pic.cpp << EOF
365#include <mutex>
366#include <thread>
367#include <iostream>
368std::once_flag flag, flag_throw;
369void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
370void throw_once(void) { throw std::exception(); }
371int callpic(void) {
372        static const int nr_threads(4);
373        std::thread threads[nr_threads];
374
375        for (int i = 0; i < nr_threads; ++i) {
376                threads[i] = std::thread(print_once);
377        }
378        for (int i = 0; i < nr_threads; ++i) {
379                threads[i].join();
380        }
381
382        try {
383                std::call_once(flag_throw, throw_once);
384        } catch (...) {
385                std::cout << "world!" << std::endl;
386        }
387        return 0;
388}
389EOF
390
391	atf_check -s exit:0 -o ignore -e ignore \
392	    c++ -m32 -pg -fPIC -shared -o libtest.so pic.cpp
393	atf_check -s exit:0 -o ignore -e ignore \
394	    c++ -m32 -pg -o call_once2 test.cpp -L. -ltest -pthread
395
396	export LD_LIBRARY_PATH=.
397	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2
398}
399
400call_once2_pie_body() {
401	# check whether this arch supports -pie
402	if ! c++ -pie -dM -E - < /dev/null 2>/dev/null >/dev/null; then
403		atf_skip "c++ -pie not supported on this architecture"
404	fi
405	cat > test.cpp << EOF
406#include <mutex>
407#include <thread>
408#include <iostream>
409std::once_flag flag, flag_throw;
410void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
411void throw_once(void) { throw std::exception(); }
412int main(void) {
413        static const int nr_threads(4);
414        std::thread threads[nr_threads];
415
416        for (int i = 0; i < nr_threads; ++i) {
417                threads[i] = std::thread(print_once);
418        }
419        for (int i = 0; i < nr_threads; ++i) {
420                threads[i].join();
421        }
422
423        try {
424                std::call_once(flag_throw, throw_once);
425        } catch (...) {
426                std::cout << "world!" << std::endl;
427        }
428        return 0;
429}
430EOF
431	atf_check -s exit:0 -o ignore -e ignore c++ -fpie -pie -o call_once2 test.cpp -pthread
432	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2
433}
434
435call_once2_32_body() {
436	# check whether this arch is 64bit
437	if ! c++ -dM -E - < /dev/null | fgrep -q _LP64; then
438		atf_skip "this is not a 64 bit architecture"
439	fi
440	if ! c++ -m32 -dM -E - < /dev/null 2>/dev/null > ./def32; then
441		atf_skip "c++ -m32 not supported on this architecture"
442	else
443		if fgrep -q _LP64 ./def32; then
444			atf_fail "c++ -m32 does not generate netbsd32 binaries"
445		fi
446	fi
447
448	cat > test.cpp << EOF
449#include <mutex>
450#include <thread>
451#include <iostream>
452std::once_flag flag, flag_throw;
453void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
454void throw_once(void) { throw std::exception(); }
455int main(void) {
456        static const int nr_threads(4);
457        std::thread threads[nr_threads];
458
459        for (int i = 0; i < nr_threads; ++i) {
460                threads[i] = std::thread(print_once);
461        }
462        for (int i = 0; i < nr_threads; ++i) {
463                threads[i].join();
464        }
465
466        try {
467                std::call_once(flag_throw, throw_once);
468        } catch (...) {
469                std::cout << "world!" << std::endl;
470        }
471        return 0;
472}
473EOF
474	atf_check -s exit:0 -o ignore -e ignore c++ -o call_once2_32 -m32 test.cpp -pthread
475	atf_check -s exit:0 -o ignore -e ignore c++ -o call_once2_64 test.cpp -pthread
476	file -b ./call_once2_32 > ./ftype32
477	file -b ./call_once2_64 > ./ftype64
478	if diff ./ftype32 ./ftype64 >/dev/null; then
479		atf_fail "generated binaries do not differ"
480	fi
481	echo "32bit binaries on this platform are:"
482	cat ./ftype32
483	echo "While native (64bit) binaries are:"
484	cat ./ftype64
485	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2_32
486
487	# do another test with static 32bit binaries
488	cat > test.cpp << EOF
489#include <mutex>
490#include <thread>
491#include <iostream>
492std::once_flag flag, flag_throw;
493void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
494void throw_once(void) { throw std::exception(); }
495int main(void) {
496        static const int nr_threads(4);
497        std::thread threads[nr_threads];
498
499        for (int i = 0; i < nr_threads; ++i) {
500                threads[i] = std::thread(print_once);
501        }
502        for (int i = 0; i < nr_threads; ++i) {
503                threads[i].join();
504        }
505
506        try {
507                std::call_once(flag_throw, throw_once);
508        } catch (...) {
509                std::cout << "world!" << std::endl;
510        }
511        return 0;
512}
513EOF
514	atf_check -s exit:0 -o ignore -e ignore c++ -o call_once2 -m32 -pthread \
515	    -static test.cpp
516	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2
517}
518
519call_once2_static_body() {
520	cat > test.cpp << EOF
521#include <mutex>
522#include <thread>
523#include <iostream>
524std::once_flag flag, flag_throw;
525void print_once(void) { std::call_once(flag, [](){ std::cout << "hello, " << std::flush; }); }
526void throw_once(void) { throw std::exception(); }
527int main(void) {
528        static const int nr_threads(4);
529        std::thread threads[nr_threads];
530
531        for (int i = 0; i < nr_threads; ++i) {
532                threads[i] = std::thread(print_once);
533        }
534        for (int i = 0; i < nr_threads; ++i) {
535                threads[i].join();
536        }
537
538        try {
539                std::call_once(flag_throw, throw_once);
540        } catch (...) {
541                std::cout << "world!" << std::endl;
542        }
543        return 0;
544}
545EOF
546	atf_check -s exit:0 -o ignore -e ignore c++ -static -o call_once2 test.cpp -pthread
547	atf_check -s exit:0 -o inline:"hello, world!\n" ./call_once2
548}
549
550atf_init_test_cases()
551{
552
553	atf_add_test_case call_once2
554	atf_add_test_case call_once2_profile
555	atf_add_test_case call_once2_pic
556	atf_add_test_case call_once2_pie
557	atf_add_test_case call_once2_32
558	atf_add_test_case call_once2_static
559	atf_add_test_case call_once2_pic_32
560	atf_add_test_case call_once2_pic_profile
561	atf_add_test_case call_once2_pic_profile_32
562	atf_add_test_case call_once2_profile_32
563}
564