1 /*
2  * Copyright (c) 2004, 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., 59
15  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
16 
17 
18  * This sample test aims to check the following assertion:
19  *
20  * fork() creates a new process.
21 
22  * The steps are:
23  * -> create a new process
24  * -> the parent and the child sleep 1 sec (check concurrent execution)
25  * -> the child posts a semaphore, the parents waits for thsi semaphore
26  *    (check the child really executes)
27  * -> join and check that total execution time is < 2 sec.
28 
29  * The test fails if the duration is > 2 seconds or if semaphore is not posted.
30 
31  */
32 
33 
34  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
35  #define _POSIX_C_SOURCE 200112L
36 
37 /********************************************************************************************/
38 /****************************** standard includes *****************************************/
39 /********************************************************************************************/
40  #include <pthread.h>
41  #include <stdarg.h>
42  #include <stdio.h>
43  #include <stdlib.h>
44  #include <string.h>
45  #include <unistd.h>
46 
47  #include <sys/wait.h>
48  #include <errno.h>
49 
50  #include <semaphore.h>
51  #include <time.h>
52  #include <fcntl.h>
53 
54 /********************************************************************************************/
55 /******************************   Test framework   *****************************************/
56 /********************************************************************************************/
57  #include "testfrmw.h"
58  #include "testfrmw.c"
59  /* This header is responsible for defining the following macros:
60   * UNRESOLVED(ret, descr);
61   *    where descr is a description of the error and ret is an int (error code for example)
62   * FAILED(descr);
63   *    where descr is a short text saying why the test has failed.
64   * PASSED();
65   *    No parameter.
66   *
67   * Both three macros shall terminate the calling process.
68   * The testcase shall not terminate in any other maneer.
69   *
70   * The other file defines the functions
71   * void output_init()
72   * void output(char * string, ...)
73   *
74   * Those may be used to output information.
75   */
76 
77 /********************************************************************************************/
78 /********************************** Configuration ******************************************/
79 /********************************************************************************************/
80 #ifndef VERBOSE
81 #define VERBOSE 1
82 #endif
83 
84 #define SEM_NAME "/semfork1_1"
85 
86 /********************************************************************************************/
87 /***********************************    Test case   *****************************************/
88 /********************************************************************************************/
89 
90 /* The main test function. */
main(int argc,char * argv[])91 int main(int argc, char * argv[])
92 {
93 	int ret, status;
94 	pid_t child, ctl;
95 	sem_t *sem;
96 	struct timespec tsini, tsfin;
97 
98 	/* Initialize output */
99 	output_init();
100 
101 	/* read current time */
102 	ret = clock_gettime(CLOCK_REALTIME, &tsini);
103 	if (ret != 0)  {  UNRESOLVED(errno, "Unable to read CLOCK_REALTIME clock");  }
104 
105 	/* Set temporary value in tsfin for semaphore timeout */
106 	tsfin.tv_sec  = tsini.tv_sec + 3;
107 	tsfin.tv_nsec = tsini.tv_nsec;
108 
109 	/* Create the child */
110 	child = fork();
111 	if (child == (pid_t) -1)  {  UNRESOLVED(errno, "Failed to fork");  }
112 
113 	/* Open the semaphore */
114 	sem = sem_open(SEM_NAME, O_CREAT, O_RDWR, 0);
115 	if (sem == (sem_t *)SEM_FAILED)  {  UNRESOLVED(errno, "Failed to open the semaphore");  }
116 
117 	/* sleep 1 second */
118 	sleep(1);
119 
120 	/* child posts the semaphore and terminates */
121 	if (child == (pid_t) 0)
122 	{
123 		do { ret = sem_post(sem); }
124 		while ((ret == -1) && (errno == EINTR));
125 		if (ret != 0)  {  UNRESOLVED(errno, "Failed to post the semaphore");  }
126 
127 		ret = sem_close(sem);
128 		if (ret != 0)  {  UNRESOLVED(errno, "Failed to close the semaphore");  }
129 
130 		/* The child stops here */
131 		exit(0);
132 	}
133 
134 	/* Parent waits for the semaphore */
135 	do { ret = sem_timedwait(sem, &tsfin); }
136 	while ((ret != 0) && (errno == EINTR));
137 	if (ret != 0)
138 	{
139 		if (errno == ETIMEDOUT) { FAILED("The new process does not execute"); }
140 		UNRESOLVED(errno, "Failed to wait for the semaphore");
141 	}
142 
143 	/* We don't need the semaphore anymore */
144 	ret = sem_unlink(SEM_NAME);
145 	if (ret != 0)  {  UNRESOLVED(errno, "Unable to unlink the semaphore");  }
146 	ret = sem_close(sem);
147 	if (ret != 0)  {  UNRESOLVED(errno, "Failed to close the semaphore");  }
148 
149 	/* Parent joins the child */
150 	ctl = waitpid(child, &status, 0);
151 	if (ctl != child)  {  UNRESOLVED(errno, "Waitpid returned the wrong PID");  }
152 	if ((!WIFEXITED(status)) || (WEXITSTATUS(status) != 0))
153 	{
154 		UNRESOLVED(status, "Child exited abnormally");
155 	}
156 
157 	/* Check the global duration */
158 	ret = clock_gettime(CLOCK_REALTIME, &tsfin);
159 	if (ret != 0)  {  UNRESOLVED(errno, "Unable to read CLOCK_REALTIME clock");  }
160 
161 	if (tsfin.tv_nsec < tsini.tv_nsec)
162 		tsfin.tv_sec -= 1;
163 
164 	status = tsfin.tv_sec - tsini.tv_sec;
165 	if (status >= 2)
166 	{
167 		/* the operation was more than 2 secs long */
168 		FAILED("the processes did not execute concurrently");
169 	}
170 
171 	/* Test passed */
172 	#if VERBOSE > 0
173 	output("Test passed\n");
174 	#endif
175 
176 	PASSED;
177 }
178 
179 
180