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