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/********************************************************************************************/
99pthread_mutex_t mtx[5];
100sem_t semsig, semstart;
101int ctrl=0;
102
103/*********  signal handler  **********/
104void sighdl(int sig)
105{
106	if (sem_post(&semsig))
107	{ UNRESOLVED(errno, "Sem_post in signal handler"); }
108}
109
110/********** thread *********/
111void * 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 ********/
142int 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