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