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