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