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