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., 59
15  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
16  *
17 
18 
19  * This sample test aims to check the following assertion:
20  * If a signal is delivered to a thread waiting for a mutex,
21  * upon return from the signal handler the thread resumes
22  * waiting for the mutex as if it had not been interrupted.
23 
24 
25  * The steps are:
26  * -> Create a child thread
27  * -> Child registers a signal handler
28  * -> Child tries to lock a mutex owned by another thread
29  * -> A signal is sent to the child
30  * -> Check that the signal handler executes and then that the thread still
31           waits for the mutex.
32  * -> Release the mutex and check that the child takes it.
33  * -> Do all of this several times with different mutex attributes
34  *
35  * The test shall be considered to FAIL if it hangs!
36  * a call to alarm() might eventually be added but this is a problem under high
37  * system stress.
38  */
39 
40  /*
41   * - adam.li@intel.com 2004-05-13
42   *   Add to PTS. Please refer to http://nptl.bullopensource.org/phpBB/
43   *   for general information
44   */
45 
46   /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
47  #define _POSIX_C_SOURCE 200112L
48 
49  /* We enable the following line to have mutex attributes defined */
50 #ifndef WITHOUT_XOPEN
51  #define _XOPEN_SOURCE	600
52 #endif
53 
54 /********************************************************************************************/
55 /****************************** standard includes *****************************************/
56 /********************************************************************************************/
57  #include <pthread.h>
58  #include <semaphore.h>
59  #include <errno.h>
60  #include <signal.h>
61  #include <unistd.h>
62  #include <stdio.h>
63  #include <stdlib.h>
64  #include <stdarg.h>
65 
66 /********************************************************************************************/
67 /******************************   Test framework   *****************************************/
68 /********************************************************************************************/
69  #include "testfrmw.h"
70  #include "testfrmw.c"
71  /* This header is responsible for defining the following macros:
72   * UNRESOLVED(ret, descr);
73   *    where descr is a description of the error and ret is an int (error code for example)
74   * FAILED(descr);
75   *    where descr is a short text saying why the test has failed.
76   * PASSED();
77   *    No parameter.
78   *
79   * Both three macros shall terminate the calling process.
80   * The testcase shall not terminate in any other maneer.
81   *
82   * The other file defines the functions
83   * void output_init()
84   * void output(char * string, ...)
85   *
86   * Those may be used to output information.
87   */
88 
89 /********************************************************************************************/
90 /********************************** Configuration ******************************************/
91 /********************************************************************************************/
92 #ifndef VERBOSE
93 #define VERBOSE 1
94 #endif
95 
96 /********************************************************************************************/
97 /***********************************    Test case   *****************************************/
98 /********************************************************************************************/
99 pthread_mutex_t mtx[5];
100 sem_t semsig, semstart;
101 int ctrl=0;
102 
103 /*********  signal handler  **********/
sighdl(int sig)104 void sighdl(int sig)
105 {
106 	if (sem_post(&semsig))
107 	{ UNRESOLVED(errno, "Sem_post in signal handler"); }
108 }
109 
110 /********** thread *********/
threaded(void * arg)111 void * threaded(void * arg)
112 {
113 	int ret, i;
114 
115 	/* We register the signal handler */
116 	struct sigaction sa;
117 	sigemptyset (&sa.sa_mask);
118 	sa.sa_flags = 0;
119 	sa.sa_handler = sighdl;
120 	if ((ret = sigaction (SIGUSR1, &sa, NULL)))
121 	{ UNRESOLVED(ret, "Unable to register signal handler"); }
122 
123 	/* Start the real work */
124 	for (i=0; i<5; i++) /* We'll do this with the 5 kinds of mutex */
125 	{
126 		if (sem_post(&semstart)) /* Tell the father we are ready */
127 		{ UNRESOLVED(errno, "Sem post in thread"); }
128 
129 		if ((ret = pthread_mutex_lock(&mtx[i]))) /* Attempt to lock the mutex */
130 		{ UNRESOLVED(ret, "Mutex lock failed in thread"); }
131 
132 		ctrl++; /* Notify the main we have passed the lock */
133 
134 		if ((ret = pthread_mutex_unlock(&mtx[i]))) /* We don't need the mutex anymore */
135 		{ UNRESOLVED(ret, "Mutex unlock failed in thread"); }
136 	}
137 	return NULL;
138 }
139 
140 
141 /********* main ********/
main(int argc,char * argv[])142 int main (int argc, char * argv[])
143 {
144 	int ret, i, j;
145 	pthread_t th;
146 	pthread_mutexattr_t ma[4], *pma[5];
147 	pma[4]=NULL;
148 
149 	output_init();
150 
151 	/* Initialize the mutex attributes */
152 	for (i=0; i<4; i++)
153 	{
154 		pma[i]=&ma[i];
155 		if ((ret = pthread_mutexattr_init(pma[i])))
156 		{ UNRESOLVED(ret, "pthread_mutexattr_init"); }
157 	}
158 	#ifndef WITHOUT_XOPEN
159 		if ((ret = pthread_mutexattr_settype(pma[0], PTHREAD_MUTEX_NORMAL)))
160 		{ UNRESOLVED(ret, "pthread_mutexattr_settype (normal)"); }
161 		if ((ret = pthread_mutexattr_settype(pma[1], PTHREAD_MUTEX_ERRORCHECK)))
162 		{ UNRESOLVED(ret, "pthread_mutexattr_settype (errorcheck)"); }
163 		if ((ret = pthread_mutexattr_settype(pma[2], PTHREAD_MUTEX_RECURSIVE)))
164 		{ UNRESOLVED(ret, "pthread_mutexattr_settype (recursive)"); }
165 		if ((ret = pthread_mutexattr_settype(pma[3], PTHREAD_MUTEX_DEFAULT)))
166 		{ UNRESOLVED(ret, "pthread_mutexattr_settype (default)"); }
167 		#if VERBOSE >1
168 		output("Mutex attributes NORMAL,ERRORCHECK,RECURSIVE,DEFAULT initialized\n");
169 		#endif
170 	#else
171 		#if VERBOSE > 0
172 		output("Mutex attributes NORMAL,ERRORCHECK,RECURSIVE,DEFAULT unavailable\n");
173 		#endif
174 	#endif
175 
176 	/* Initialize the 5 mutex */
177 	for (i=0; i<5; i++)
178 	{
179 		if ((ret = pthread_mutex_init(&mtx[i], pma[i])))
180 		{ UNRESOLVED(ret, "pthread_mutex_init failed")}
181 		if ((ret = pthread_mutex_lock(&mtx[i])))
182 		{ UNRESOLVED(ret, "Initial pthread_mutex_lock failed")}
183 	}
184 
185 	#if VERBOSE >1
186 	output("Mutex objects are initialized\n");
187 	#endif
188 
189 	/* We don't need the mutex attribute objects anymore */
190 	for (i=0; i<4; i++)
191 	{
192 		if ((ret = pthread_mutexattr_destroy(pma[i])))
193 		{ UNRESOLVED(ret, "pthread_mutexattr_destroy"); }
194 	}
195 
196 	/* Initialize the semaphores */
197 	if (sem_init(&semsig, 0, 1))
198 	{ UNRESOLVED(errno, "Sem init (1) failed"); }
199 	if (sem_init(&semstart, 0, 0))
200 	{ UNRESOLVED(errno, "Sem init (0) failed"); }
201 
202 
203 	#if VERBOSE >1
204 	output("Going to create the child thread\n");
205 	#endif
206 	/* Start the child */
207 	if ((ret = pthread_create(&th, NULL, threaded, NULL)))
208 	{ UNRESOLVED(ret, "Unable to create the thread"); }
209 	#if VERBOSE >1
210 	output("Child created\n");
211 	#endif
212 
213 
214 	/* Monitor the child */
215 	for (i=0; i<5; i++) /* We will do this for the 5 kinds of mutex */
216 	{
217 		if (sem_wait(&semstart))  /* Wait for the thread to be ready */
218 		{ UNRESOLVED(errno, "Unable to wait for the child"); }
219 
220 		#if VERBOSE >1
221 		output("Child is ready for iteration %i\n", i+1);
222 		#endif
223 
224 
225 		ctrl=0; /* init the ctrl var */
226 
227 		/* Send some signals to the thread */
228 		for (j=0; j<10; j++)
229 		{
230 			if ((ret = sem_wait(&semsig)))
231 			{ UNRESOLVED(errno, "Sem_wait failed from the signal handler"); }
232 
233 			sched_yield(); /* Let the child do its stuff - might be a nanosleep here*/
234 
235 			if ((ret = pthread_kill (th, SIGUSR1)))
236 			{ UNRESOLVED(ret, "Pthread_kill failed"); }
237 		}
238 		#if VERBOSE >1
239 		output("Child was killed 10 times\n");
240 		#endif
241 
242 		/* Now check the thread is still waiting for the mutex */
243 		if (ctrl != 0)
244 		{
245 			FAILED("Killed child passed the pthread_mutex_lock without owning it");
246 		}
247 
248 		#if VERBOSE >1
249 		output("Control was OK\n");
250 		#endif
251 
252 		/* Unlock the mutex so the thread can proceed to the next one */
253 		if ((ret = pthread_mutex_unlock(&mtx[i])))
254 		{  UNRESOLVED(ret, "Mutex unlock in main failed"); }
255 	}
256 
257 	#if VERBOSE >1
258 	output("The test has passed, we are now going to clean up everything.\n");
259 	#endif
260 
261 	/* Clean everything: the test has passed */
262 	if ((ret = pthread_join(th, NULL)))
263 	{  UNRESOLVED(ret, "Unable to join the child"); }
264 
265 	for (i=0; i<5; i++)
266 	{
267 		if ((ret = pthread_mutex_destroy(&mtx[i])))
268 		{ UNRESOLVED(ret, "Unable to finally destroy a mutex"); }
269 	}
270 
271 	if (sem_destroy(&semstart))
272 	{ UNRESOLVED(errno, "Unable to destroy semstart semaphore"); }
273 
274 	if (sem_destroy(&semsig))
275 	{ UNRESOLVED(errno, "Unable to destroy semsig semaphore"); }
276 
277 	PASSED;
278 }
279