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