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*/ 88sem_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. */ 129int 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