1 /*        $NetBSD: t_thrd.c,v 1.2 2020/05/14 08:34:19 msaitoh Exp $   */
2 
3 /*-
4  * Copyright (c) 2019 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Kamil Rytarowski.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __COPYRIGHT("@(#) Copyright (c) 2019\
34  The NetBSD Foundation, inc. All rights reserved.");
35 __RCSID("$NetBSD: t_thrd.c,v 1.2 2020/05/14 08:34:19 msaitoh Exp $");
36 
37 #include <signal.h>
38 #include <stdbool.h>
39 #include <threads.h>
40 #include <time.h>
41 
42 #include <atf-c.h>
43 
44 ATF_TC(thrd_create);
ATF_TC_HEAD(thrd_create,tc)45 ATF_TC_HEAD(thrd_create, tc)
46 {
47           atf_tc_set_md_var(tc, "descr", "Test C11 thrd_create(3)");
48 }
49 
50 #define TC_ADDON 5
51 
52 static int
tcr_func(void * arg)53 tcr_func(void *arg)
54 {
55           int a;
56 
57           a = (int)(intptr_t)arg;
58 
59           return a + TC_ADDON;
60 }
61 
ATF_TC_BODY(thrd_create,tc)62 ATF_TC_BODY(thrd_create, tc)
63 {
64           thrd_t t;
65           const int a = 5;
66           int b;
67           void *v;
68 
69           v = (void *)(intptr_t)a;
70 
71           ATF_REQUIRE_EQ(thrd_create(&t, tcr_func, v), thrd_success);
72           ATF_REQUIRE_EQ(thrd_join(t, &b), thrd_success);
73           ATF_REQUIRE_EQ(a + TC_ADDON, b);
74 }
75 
76 ATF_TC(thrd_current);
ATF_TC_HEAD(thrd_current,tc)77 ATF_TC_HEAD(thrd_current, tc)
78 {
79           atf_tc_set_md_var(tc, "descr", "Test C11 thrd_current(3)");
80 }
81 
82 static int
tcur_func(void * arg __unused)83 tcur_func(void *arg __unused)
84 {
85 
86           return 0;
87 }
88 
ATF_TC_BODY(thrd_current,tc)89 ATF_TC_BODY(thrd_current, tc)
90 {
91           thrd_t s, t;
92 
93           s = thrd_current();
94 
95           ATF_REQUIRE(thrd_equal(s, s) != 0);
96           ATF_REQUIRE_EQ(thrd_create(&t, tcur_func, NULL), thrd_success);
97           ATF_REQUIRE(thrd_equal(t, s) == 0);
98           ATF_REQUIRE(thrd_equal(s, t) == 0);
99           ATF_REQUIRE(thrd_equal(t, t) != 0);
100 
101           ATF_REQUIRE_EQ(thrd_join(t, NULL), thrd_success);
102 }
103 
104 ATF_TC(thrd_detach);
ATF_TC_HEAD(thrd_detach,tc)105 ATF_TC_HEAD(thrd_detach, tc)
106 {
107           atf_tc_set_md_var(tc, "descr", "Test C11 thrd_detach(3)");
108 }
109 
110 static int
tdet_func(void * arg __unused)111 tdet_func(void *arg __unused)
112 {
113 
114           return 0;
115 }
116 
ATF_TC_BODY(thrd_detach,tc)117 ATF_TC_BODY(thrd_detach, tc)
118 {
119           thrd_t t;
120 
121           ATF_REQUIRE_EQ(thrd_create(&t, tdet_func, NULL), thrd_success);
122           ATF_REQUIRE_EQ(thrd_detach(t), thrd_success);
123 }
124 
125 ATF_TC(thrd_exit);
ATF_TC_HEAD(thrd_exit,tc)126 ATF_TC_HEAD(thrd_exit, tc)
127 {
128           atf_tc_set_md_var(tc, "descr", "Test C11 thrd_exit(3)");
129 }
130 
131 static void
tex_func2(void)132 tex_func2(void)
133 {
134 
135           thrd_exit(1);
136 }
137 
138 static int
tex_func(void * arg __unused)139 tex_func(void *arg __unused)
140 {
141 
142           tex_func2();
143 
144           return -1;
145 }
146 
ATF_TC_BODY(thrd_exit,tc)147 ATF_TC_BODY(thrd_exit, tc)
148 {
149           thrd_t t;
150           int b = 0;
151 
152           ATF_REQUIRE_EQ(thrd_create(&t, tex_func, NULL), thrd_success);
153           ATF_REQUIRE_EQ(thrd_join(t, &b), thrd_success);
154           ATF_REQUIRE_EQ(b, 1);
155 }
156 
157 ATF_TC(thrd_sleep);
ATF_TC_HEAD(thrd_sleep,tc)158 ATF_TC_HEAD(thrd_sleep, tc)
159 {
160           atf_tc_set_md_var(tc, "descr", "Test C11 thrd_sleep(3)");
161 }
162 
163 static int alarmed;
164 
165 static void
alarm_handler(int signum)166 alarm_handler(int signum)
167 {
168 
169           ATF_REQUIRE_EQ(signum, SIGALRM);
170           ++alarmed;
171 }
172 
ATF_TC_BODY(thrd_sleep,tc)173 ATF_TC_BODY(thrd_sleep, tc)
174 {
175           struct timespec start, stop, diff;
176           struct timespec ts, rem;
177           struct timespec zero;
178           struct sigaction sa;
179           struct itimerval timer;
180 
181           zero.tv_sec = 0;
182           zero.tv_nsec = 0;
183 
184           ts.tv_sec = 1;
185           ts.tv_nsec = -1;
186           ATF_REQUIRE_EQ(!thrd_sleep(&ts, NULL), 0);
187 
188           ts.tv_sec = 0;
189           ts.tv_nsec = 1000000000/100; /* 1/100 sec */
190           ATF_REQUIRE_EQ(clock_gettime(CLOCK_MONOTONIC, &start), 0);
191           ATF_REQUIRE_EQ(thrd_sleep(&ts, &rem), 0);
192           ATF_REQUIRE_EQ(clock_gettime(CLOCK_MONOTONIC, &stop), 0);
193           timespecsub(&stop, &start, &diff);
194           ATF_REQUIRE(timespeccmp(&diff, &ts, >=));
195           ATF_REQUIRE(timespeccmp(&zero, &rem, ==));
196 
197           ts.tv_sec = 1;
198           ts.tv_nsec = 0;
199           memset(&sa, 0, sizeof(sa));
200           sa.sa_handler = alarm_handler;
201           sigaction(SIGALRM, &sa, NULL);
202           memset(&timer, 0, sizeof(timer));
203           timer.it_value.tv_sec = 0;
204           timer.it_value.tv_usec = 100000; /* 100 msec */
205           ATF_REQUIRE_EQ(setitimer(ITIMER_MONOTONIC, &timer, NULL), 0);
206           ATF_REQUIRE_EQ(clock_gettime(CLOCK_MONOTONIC, &start), 0);
207           ATF_REQUIRE_EQ(!thrd_sleep(&ts, &rem), 0);
208           ATF_REQUIRE_EQ(clock_gettime(CLOCK_MONOTONIC, &stop), 0);
209           timespecsub(&stop, &start, &diff);
210           ATF_REQUIRE(timespeccmp(&diff, &ts, <));
211           ATF_REQUIRE(timespeccmp(&zero, &rem, !=));
212           ATF_REQUIRE_EQ(alarmed, 1);
213 }
214 
215 ATF_TC(thrd_yield);
ATF_TC_HEAD(thrd_yield,tc)216 ATF_TC_HEAD(thrd_yield, tc)
217 {
218           atf_tc_set_md_var(tc, "descr", "Test C11 thrd_yield(3)");
219 }
220 
ATF_TC_BODY(thrd_yield,tc)221 ATF_TC_BODY(thrd_yield, tc)
222 {
223 
224           thrd_yield();
225 }
226 
ATF_TP_ADD_TCS(tp)227 ATF_TP_ADD_TCS(tp)
228 {
229           ATF_TP_ADD_TC(tp, thrd_create);
230           ATF_TP_ADD_TC(tp, thrd_current);
231           ATF_TP_ADD_TC(tp, thrd_detach);
232           ATF_TP_ADD_TC(tp, thrd_exit);
233           ATF_TP_ADD_TC(tp, thrd_sleep);
234           ATF_TP_ADD_TC(tp, thrd_yield);
235 
236           return atf_no_error();
237 }
238