xref: /aosp_15_r20/external/ltp/testcases/open_posix_testsuite/conformance/interfaces/pthread_once/6-1.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 /*
2 * Copyright (c) 2004, Bull S.A..  All rights reserved.
3 * Created by: Sebastien Decugis
4 
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 
17 * This sample test aims to check the following assertion:
18 *
19 * The function does not return EINTR
20 
21 * The steps are:
22 * -> kill a thread which calls pthread_once
23 * -> check that EINTR is never returned
24 
25 */
26 
27 
28 /********************************************************************************************/
29 /****************************** standard includes *****************************************/
30 /********************************************************************************************/
31 #include <errno.h>
32 #include <pthread.h>
33 #include <semaphore.h>
34 #include <signal.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 /********************************************************************************************/
42 /******************************   Test framework   *****************************************/
43 /********************************************************************************************/
44 #include "../testfrmw/testfrmw.h"
45 #include "../testfrmw/testfrmw.c"
46 /* This header is responsible for defining the following macros:
47  * UNRESOLVED(ret, descr);
48  *    where descr is a description of the error and ret is an int (error code for example)
49  * FAILED(descr);
50  *    where descr is a short text saying why the test has failed.
51  * PASSED();
52  *    No parameter.
53  *
54  * Both three macros shall terminate the calling process.
55  * The testcase shall not terminate in any other maneer.
56  *
57  * The other file defines the functions
58  * void output_init()
59  * void output(char * string, ...)
60  *
61  * Those may be used to output information.
62  */
63 
64 /********************************************************************************************/
65 /********************************** Configuration ******************************************/
66 /********************************************************************************************/
67 #ifndef VERBOSE
68 #define VERBOSE 1
69 #endif
70 
71 #define WITH_SYNCHRO
72 
73 /********************************************************************************************/
74 /***********************************    Test cases  *****************************************/
75 /********************************************************************************************/
76 
77 static char do_it = 1;
78 static unsigned long count_ope = 0;
79 #ifdef WITH_SYNCHRO
80 static sem_t semsig1;
81 static sem_t semsig2;
82 static unsigned long count_sig = 0;
83 #endif
84 
85 static sigset_t usersigs;
86 
87 typedef struct {
88 	int sig;
89 #ifdef WITH_SYNCHRO
90 	sem_t *sem;
91 #endif
92 } thestruct;
93 
94 /* the following function keeps on sending the signal to the process */
sendsig(void * arg)95 static void *sendsig(void *arg)
96 {
97 	thestruct *thearg = (thestruct *) arg;
98 	int ret;
99 	pid_t process;
100 
101 	process = getpid();
102 
103 	/* We block the signals SIGUSR1 and SIGUSR2 for this THREAD */
104 	ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
105 
106 	if (ret != 0) {
107 		UNRESOLVED(ret,
108 			   "Unable to block SIGUSR1 and SIGUSR2 in signal thread");
109 	}
110 
111 	while (do_it) {
112 #ifdef WITH_SYNCHRO
113 
114 		if ((ret = sem_wait(thearg->sem))) {
115 			UNRESOLVED(errno, "Sem_wait in sendsig");
116 		}
117 
118 		count_sig++;
119 #endif
120 
121 		ret = kill(process, thearg->sig);
122 
123 		if (ret != 0) {
124 			UNRESOLVED(errno, "Kill in sendsig");
125 		}
126 
127 	}
128 
129 	return NULL;
130 }
131 
132 /* Next are the signal handlers. */
133 /* This one is registered for signal SIGUSR1 */
sighdl1(int sig PTS_ATTRIBUTE_UNUSED)134 static void sighdl1(int sig PTS_ATTRIBUTE_UNUSED)
135 {
136 #ifdef WITH_SYNCHRO
137 
138 	if (sem_post(&semsig1)) {
139 		UNRESOLVED(errno, "Sem_post in signal handler 1");
140 	}
141 #endif
142 }
143 
144 /* This one is registered for signal SIGUSR2 */
sighdl2(int sig PTS_ATTRIBUTE_UNUSED)145 static void sighdl2(int sig PTS_ATTRIBUTE_UNUSED)
146 {
147 #ifdef WITH_SYNCHRO
148 
149 	if (sem_post(&semsig2)) {
150 		UNRESOLVED(errno, "Sem_post in signal handler 2");
151 	}
152 #endif
153 }
154 
155 static int init_ctl;
156 /* Init function */
initializer(void)157 static void initializer(void)
158 {
159 	init_ctl++;
160 	return;
161 }
162 
163 /* Test function -- calls pthread_equal() and checks that EINTR is never returned. */
test(void * arg PTS_ATTRIBUTE_UNUSED)164 static void *test(void *arg PTS_ATTRIBUTE_UNUSED)
165 {
166 	int ret = 0;
167 
168 	/* We don't block the signals SIGUSR1 and SIGUSR2 for this THREAD */
169 	ret = pthread_sigmask(SIG_UNBLOCK, &usersigs, NULL);
170 
171 	if (ret != 0) {
172 		UNRESOLVED(ret,
173 			   "Unable to unblock SIGUSR1 and SIGUSR2 in worker thread");
174 	}
175 
176 	while (do_it) {
177 
178 		pthread_once_t once_ctl = PTHREAD_ONCE_INIT;
179 
180 		count_ope++;
181 
182 		init_ctl = 0;
183 
184 		ret = pthread_once(&once_ctl, initializer);
185 
186 		if (ret == EINTR) {
187 			FAILED("pthread_once returned EINTR");
188 		}
189 
190 		if (ret != 0) {
191 			UNRESOLVED(ret, "pthread_once failed");
192 		}
193 
194 		ret = pthread_once(&once_ctl, initializer);
195 
196 		if (ret == EINTR) {
197 			FAILED("pthread_once returned EINTR");
198 		}
199 
200 		if (ret != 0) {
201 			UNRESOLVED(ret, "pthread_once failed");
202 		}
203 
204 		if (init_ctl != 1) {
205 			output("init_ctl: %d\n", init_ctl);
206 			FAILED("The initializer did not execute as expected");
207 		}
208 
209 	}
210 
211 	return NULL;
212 }
213 
214 /* Main function */
main(void)215 int main(void)
216 {
217 	int ret;
218 	pthread_t th_work, th_sig1, th_sig2;
219 	thestruct arg1, arg2;
220 
221 	struct sigaction sa;
222 
223 	/* Initialize output routine */
224 	output_init();
225 
226 	/* We need to register the signal handlers for the PROCESS */
227 	sigemptyset(&sa.sa_mask);
228 	sa.sa_flags = 0;
229 	sa.sa_handler = sighdl1;
230 
231 	if ((ret = sigaction(SIGUSR1, &sa, NULL)) == -1) {
232 		UNRESOLVED(ret, "Unable to register signal handler1");
233 	}
234 
235 	sa.sa_handler = sighdl2;
236 
237 	if ((ret = sigaction(SIGUSR2, &sa, NULL)) == -1) {
238 		UNRESOLVED(ret, "Unable to register signal handler2");
239 	}
240 
241 	/* We prepare a signal set which includes SIGUSR1 and SIGUSR2 */
242 	sigemptyset(&usersigs);
243 
244 	ret = sigaddset(&usersigs, SIGUSR1);
245 
246 	ret |= sigaddset(&usersigs, SIGUSR2);
247 
248 	if (ret != 0) {
249 		UNRESOLVED(ret, "Unable to add SIGUSR1 or 2 to a signal set");
250 	}
251 
252 	/* We now block the signals SIGUSR1 and SIGUSR2 for this THREAD */
253 	ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
254 
255 	if (ret != 0) {
256 		UNRESOLVED(ret,
257 			   "Unable to block SIGUSR1 and SIGUSR2 in main thread");
258 	}
259 #ifdef WITH_SYNCHRO
260 	if (sem_init(&semsig1, 0, 1)) {
261 		UNRESOLVED(errno, "Semsig1  init");
262 	}
263 
264 	if (sem_init(&semsig2, 0, 1)) {
265 		UNRESOLVED(errno, "Semsig2  init");
266 	}
267 #endif
268 
269 	if ((ret = pthread_create(&th_work, NULL, test, NULL))) {
270 		UNRESOLVED(ret, "Worker thread creation failed");
271 	}
272 
273 	arg1.sig = SIGUSR1;
274 	arg2.sig = SIGUSR2;
275 #ifdef WITH_SYNCHRO
276 	arg1.sem = &semsig1;
277 	arg2.sem = &semsig2;
278 #endif
279 
280 	if ((ret = pthread_create(&th_sig1, NULL, sendsig, (void *)&arg1))) {
281 		UNRESOLVED(ret, "Signal 1 sender thread creation failed");
282 	}
283 
284 	if ((ret = pthread_create(&th_sig2, NULL, sendsig, (void *)&arg2))) {
285 		UNRESOLVED(ret, "Signal 2 sender thread creation failed");
286 	}
287 
288 	/* Let's wait for a while now */
289 	sleep(1);
290 
291 	/* Now stop the threads and join them */
292 	do {
293 		do_it = 0;
294 	}
295 	while (do_it);
296 
297 	if ((ret = pthread_join(th_sig1, NULL))) {
298 		UNRESOLVED(ret, "Signal 1 sender thread join failed");
299 	}
300 
301 	if ((ret = pthread_join(th_sig2, NULL))) {
302 		UNRESOLVED(ret, "Signal 2 sender thread join failed");
303 	}
304 
305 	if ((ret = pthread_join(th_work, NULL))) {
306 		UNRESOLVED(ret, "Worker thread join failed");
307 	}
308 #if VERBOSE > 0
309 	output("Test executed successfully.\n");
310 
311 	output("  %d initializations.\n", count_ope);
312 
313 #ifdef WITH_SYNCHRO
314 	output("  %d signals were sent meanwhile.\n", count_sig);
315 
316 #endif
317 #endif
318 	PASSED;
319 }
320