1 /* 2 * Copyright (c) 2005, 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 * This sample test aims to check the following assertion: 18 * 19 * If several threads are blocked in a call to sigwait, 20 * only one is unblocked when the signal becomes pending. 21 22 * The steps are: 23 * -> mask SIGUSR1 24 * -> create several threads which sigwait for SIGUSR1 25 * -> raise SIGUSR1 26 * -> Check than only 1 thread has been awaken. 27 28 * The test fails if less or more than 1 thread returns from sigwait when the 29 * signal is raised. 30 31 */ 32 33 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 34 #define _POSIX_C_SOURCE 200112L 35 36 /******************************************************************************/ 37 /*************************** standard includes ********************************/ 38 /******************************************************************************/ 39 #include <pthread.h> 40 #include <stdarg.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include <signal.h> 47 #include <errno.h> 48 49 /******************************************************************************/ 50 /*************************** Test framework *******************************/ 51 /******************************************************************************/ 52 #include "../testfrmw/testfrmw.h" 53 #include "../testfrmw/testfrmw.c" 54 /* This header is responsible for defining the following macros: 55 * UNRESOLVED(ret, descr); 56 * where descr is a description of the error and ret is an int 57 * (error code for example) 58 * FAILED(descr); 59 * where descr is a short text saying why the test has failed. 60 * PASSED(); 61 * No parameter. 62 * 63 * Both three macros shall terminate the calling process. 64 * The testcase shall not terminate in any other maneer. 65 * 66 * The other file defines the functions 67 * void output_init() 68 * void output(char * string, ...) 69 * 70 * Those may be used to output information. 71 */ 72 73 /******************************************************************************/ 74 /**************************** Configuration ***********************************/ 75 /******************************************************************************/ 76 #ifndef VERBOSE 77 #define VERBOSE 1 78 #endif 79 80 #define NTHREADS 5 81 82 /******************************************************************************/ 83 /*************************** Test case ***********************************/ 84 /******************************************************************************/ 85 86 int n_awaken = 0; 87 sigset_t setusr; 88 89 /* Thread function */ 90 void *threaded(void *arg) 91 { 92 int ret; 93 int sig; 94 95 /* The signal is already masked, because inherited from the parent */ 96 97 /* wait for the signal */ 98 ret = sigwait(&setusr, &sig); 99 100 if (ret != 0) { 101 UNRESOLVED(ret, "failed to wait for signal in thread"); 102 } 103 104 n_awaken++; 105 106 /* quit */ 107 return NULL; 108 } 109 110 /* The main test function. */ 111 int main(void) 112 { 113 int ret, i; 114 pthread_t ch[NTHREADS]; 115 116 /* Initialize output */ 117 output_init(); 118 119 /* Set the signal mask */ 120 ret = sigemptyset(&setusr); 121 122 if (ret != 0) { 123 UNRESOLVED(ret, "Failed to empty signal set"); 124 } 125 126 ret = sigaddset(&setusr, SIGUSR1); 127 128 if (ret != 0) { 129 UNRESOLVED(ret, "failed to add SIGUSR1 to signal set"); 130 } 131 132 ret = pthread_sigmask(SIG_BLOCK, &setusr, NULL); 133 134 if (ret != 0) { 135 UNRESOLVED(ret, "Failed to block SIGUSR1"); 136 } 137 138 /* Create the children */ 139 140 for (i = 0; i < NTHREADS; i++) { 141 ret = pthread_create(&ch[i], NULL, threaded, NULL); 142 143 if (ret != 0) { 144 UNRESOLVED(ret, "Failed to create a thread"); 145 } 146 } 147 148 /* raise the signal */ 149 ret = kill(getpid(), SIGUSR1); 150 151 if (ret != 0) { 152 UNRESOLVED(ret, "Failed to raise the signal"); 153 } 154 155 sleep(1); 156 157 if (n_awaken != 1) { 158 output("%d threads were awaken\n", n_awaken); 159 FAILED("Unexpected number of threads awaken"); 160 } 161 162 /* Wake other threads */ 163 for (; n_awaken < NTHREADS; sched_yield()) { 164 ret = kill(getpid(), SIGUSR1); 165 166 if (ret != 0) { 167 UNRESOLVED(ret, "Failed to raise the signal"); 168 } 169 } 170 171 /* Wait for child thread termination */ 172 for (i = 0; i < NTHREADS; i++) { 173 ret = pthread_join(ch[i], NULL); 174 175 if (ret != 0) { 176 UNRESOLVED(ret, "Failed to join the thread"); 177 } 178 } 179 180 /* Test passed */ 181 #if VERBOSE > 0 182 183 output("Test passed\n"); 184 185 #endif 186 187 PASSED; 188 } 189