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 * Destruction of the semaphore is postponed until all processes which were using 20 * the semaphore have called sem_close, _exit or exec. 21 22 * The steps are: 23 * -> Create a named semaphore with value = 0. 24 * -> create 3 processes. Each call sem_wait, then sem_post, then sem_close/_exit/exec 25 * -> the main process unlinks the semaphore, the posts it and close it. 26 * -> Check all child processes have returned successfully. 27 28 * The test fails if a semaphore operation returns an error in one of the children. 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 <semaphore.h> 46 #include <errno.h> 47 #include <fcntl.h> 48 #include <sys/wait.h> 49 50 /******************************************************************************/ 51 /*************************** Test framework *******************************/ 52 /******************************************************************************/ 53 #include "../testfrmw/testfrmw.h" 54 #include "../testfrmw/testfrmw.c" 55 /* This header is responsible for defining the following macros: 56 * UNRESOLVED(ret, descr); 57 * where descr is a description of the error and ret is an int 58 * (error code for example) 59 * FAILED(descr); 60 * where descr is a short text saying why the test has failed. 61 * PASSED(); 62 * No parameter. 63 * 64 * Both three macros shall terminate the calling process. 65 * The testcase shall not terminate in any other maneer. 66 * 67 * The other file defines the functions 68 * void output_init() 69 * void output(char * string, ...) 70 * 71 * Those may be used to output information. 72 */ 73 74 /******************************************************************************/ 75 /**************************** Configuration ***********************************/ 76 /******************************************************************************/ 77 #ifndef VERBOSE 78 #define VERBOSE 1 79 #endif 80 81 #define SEM_NAME "/sem_unlink_9_1" 82 83 /******************************************************************************/ 84 /*************************** Test case ***********************************/ 85 /******************************************************************************/ 86 87 /* Operations common to all processes on the semaphore*/ 88 sem_t *common() 89 { 90 int ret; 91 sem_t *sem; 92 93 /* Reconnect to the semaphore */ 94 sem = sem_open(SEM_NAME, 0); 95 96 if (sem == SEM_FAILED) { 97 UNRESOLVED(errno, "Failed to reconnect the semaphore"); 98 } 99 100 /* block until the semaphore is posted */ 101 102 do { 103 ret = sem_wait(sem); 104 } 105 while (ret != 0 && errno == EINTR); 106 107 if (ret != 0) { 108 FAILED("Waiting for the semaphore failed"); 109 } 110 111 /* spend some time... */ 112 sched_yield(); 113 114 sched_yield(); 115 116 sched_yield(); 117 118 /* Post the semaphore back */ 119 ret = sem_post(sem); 120 121 if (ret != 0) { 122 FAILED("Failed to post the semaphore"); 123 } 124 125 return sem; 126 } 127 128 /* The main test function. */ 129 int main(void) 130 { 131 int ret, status; 132 pid_t p1, p2, p3, ctl; 133 134 sem_t *sem; 135 136 /* Initialize output */ 137 output_init(); 138 139 /* Create the semaphore */ 140 sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, 0777, 0); 141 142 if ((sem == SEM_FAILED) && (errno == EEXIST)) { 143 sem_unlink(SEM_NAME); 144 sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, 0777, 0); 145 } 146 147 if (sem == SEM_FAILED) { 148 UNRESOLVED(errno, "Failed to create the semaphore"); 149 } 150 151 /* fork 3 times */ 152 p1 = fork(); 153 154 if (p1 == -1) { 155 UNRESOLVED(errno, "Failed to fork"); 156 } 157 158 if (p1 == 0) { /* child */ 159 sem = common(); 160 ret = sem_close(sem); 161 162 if (ret != 0) { 163 FAILED("Failed to sem_close in child"); 164 } 165 166 exit(0); 167 } 168 169 p2 = fork(); 170 171 if (p2 == -1) { 172 UNRESOLVED(errno, "Failed to fork"); 173 } 174 175 if (p2 == 0) { /* child */ 176 sem = common(); 177 _exit(0); 178 } 179 180 p3 = fork(); 181 182 if (p3 == -1) { 183 UNRESOLVED(errno, "Failed to fork"); 184 } 185 186 if (p3 == 0) { /* child */ 187 sem = common(); 188 ret = execl("/bin/ls", "ls", NULL); 189 UNRESOLVED(errno, "Failed to exec"); 190 } 191 192 /* Let all processes start and wait for the semaphore */ 193 sleep(1); 194 195 /* Unlink */ 196 ret = sem_unlink(SEM_NAME); 197 198 if (ret != 0) { 199 UNRESOLVED(errno, "Failed to unlink the semaphore"); 200 } 201 202 /* Post the semaphore */ 203 ret = sem_post(sem); 204 205 if (ret != 0) { 206 UNRESOLVED(errno, "Failed to post the semaphore"); 207 } 208 209 /* and close it in this process */ 210 ret = sem_close(sem); 211 212 if (ret != 0) { 213 UNRESOLVED(errno, "Failed to close the semaphore"); 214 } 215 216 /* Wait all processes */ 217 ctl = waitpid(p1, &status, 0); 218 219 if (ctl != p1) { 220 UNRESOLVED(errno, "Waitpid returned the wrong PID"); 221 } 222 223 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { 224 FAILED("Child 'sem_close' exited abnormally"); 225 } 226 227 ctl = waitpid(p2, &status, 0); 228 229 if (ctl != p2) { 230 UNRESOLVED(errno, "Waitpid returned the wrong PID"); 231 } 232 233 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { 234 FAILED("Child '_exit' exited abnormally"); 235 } 236 237 ctl = waitpid(p3, &status, 0); 238 239 if (ctl != p3) { 240 UNRESOLVED(errno, "Waitpid returned the wrong PID"); 241 } 242 243 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { 244 FAILED("Child 'exec' exited abnormally"); 245 } 246 247 /* Test passed */ 248 #if VERBOSE > 0 249 output("Test passed\n"); 250 251 #endif 252 PASSED; 253 } 254