1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * NAME
22 * pipe11.c
23 *
24 * DESCRIPTION
25 * Check if many children can read what is written to a pipe by the
26 * parent.
27 *
28 * ALGORITHM
29 * 1. Open a pipe and write to it
30 * 2. Fork a large number of children
31 * 3. Have the children read the pipe and check how many characters
32 * each got
33 *
34 * USAGE: <for command-line>
35 * pipe11 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
36 * where, -c n : Run n copies concurrently.
37 * -f : Turn off functionality Testing.
38 * -i n : Execute test n times.
39 * -I x : Execute test for x seconds.
40 * -P x : Pause for x seconds between iterations.
41 * -t : Turn on syscall timing.
42 *
43 * HISTORY
44 * 07/2001 Ported by Wayne Boyer
45 *
46 * RESTRICTIONS
47 * None
48 */
49 #include <sys/types.h>
50 #include <sys/wait.h>
51 #include <errno.h>
52 #include <stdio.h>
53 #include <limits.h>
54 #include "test.h"
55
56 char *TCID = "pipe11";
57 int TST_TOTAL = 1;
58
59 void do_child(void);
60 void do_child_uclinux(void);
61 void setup(void);
62 void cleanup(void);
63
64 #define NUMCHILD 50
65 #define NCPERCHILD 50
66 char rawchars[] =
67 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
68 int kidid;
69 int numchild; /* no of children to fork */
70 int ncperchild; /* no of chars child should read */
71 int szcharbuf; /* size of char buf */
72 int pipewrcnt; /* chars written to pipe */
73 char *wrbuf, *rdbuf;
74 int fd[2]; /* fds for pipe read/write */
75
do_read(int fd,void * buf,size_t count)76 ssize_t do_read(int fd, void *buf, size_t count)
77 {
78 ssize_t n;
79
80 do {
81 n = read(fd, buf, count);
82 } while (n < 0 && errno == EINTR);
83
84 return n;
85 }
86
main(int ac,char ** av)87 int main(int ac, char **av)
88 {
89 int lc;
90
91 int i;
92 int fork_ret, status;
93 int written; /* no of chars read and written */
94
95 tst_parse_opts(ac, av, NULL, NULL);
96 #ifdef UCLINUX
97 maybe_run_child(&do_child_uclinux, "ddddd", &fd[0], &fd[1], &kidid,
98 &ncperchild, &szcharbuf);
99 #endif
100
101 setup();
102
103 for (lc = 0; TEST_LOOPING(lc); lc++) {
104
105 /* reset tst_count in case we are looping */
106 tst_count = 0;
107
108 TEST(pipe(fd));
109
110 if (TEST_RETURN != 0) {
111 tst_resm(TFAIL, "pipe creation failed");
112 continue;
113 }
114
115 written = write(fd[1], wrbuf, szcharbuf);
116 if (written != szcharbuf) {
117 tst_brkm(TBROK, cleanup, "write to pipe failed");
118 }
119
120 refork:
121 ++kidid;
122 fork_ret = FORK_OR_VFORK();
123
124 if (fork_ret < 0) {
125 tst_brkm(TBROK, cleanup, "fork() failed");
126 }
127
128 if ((fork_ret != 0) && (fork_ret != -1) && (kidid < numchild)) {
129 goto refork;
130 }
131
132 if (fork_ret == 0) { /* child */
133 #ifdef UCLINUX
134 if (self_exec(av[0], "ddddd", fd[0], fd[1], kidid,
135 ncperchild, szcharbuf) < 0) {
136 tst_brkm(TBROK, cleanup, "self_exec failed");
137 }
138 #else
139 do_child();
140 #endif
141 }
142
143 /* parent */
144 sleep(5);
145 tst_resm(TINFO, "There are %d children to wait for", kidid);
146 for (i = 1; i <= kidid; ++i) {
147 wait(&status);
148 if (status == 0) {
149 tst_resm(TPASS, "child %d exitted successfully",
150 i);
151 } else {
152 tst_resm(TFAIL, "child %d exitted with bad "
153 "status", i);
154 }
155 }
156 }
157 cleanup();
158
159 tst_exit();
160 }
161
162 /*
163 * do_child()
164 */
do_child(void)165 void do_child(void)
166 {
167 int nread;
168
169 if (close(fd[1])) {
170 tst_resm(TINFO, "child %d " "could not close pipe", kidid);
171 exit(0);
172 }
173 nread = do_read(fd[0], rdbuf, ncperchild);
174 if (nread == ncperchild) {
175 tst_resm(TINFO, "child %d " "got %d chars", kidid, nread);
176 exit(0);
177 } else {
178 tst_resm(TFAIL, "child %d did not receive expected no of "
179 "characters, got %d characters", kidid, nread);
180 exit(1);
181 }
182 }
183
184 /*
185 * do_child_uclinux() - as above, but mallocs rdbuf first
186 */
do_child_uclinux(void)187 void do_child_uclinux(void)
188 {
189 if ((rdbuf = malloc(szcharbuf)) == NULL) {
190 tst_brkm(TBROK, cleanup, "malloc of rdbuf failed");
191 }
192
193 do_child();
194 }
195
196 /*
197 * setup() - performs all ONE TIME setup for this test.
198 */
setup(void)199 void setup(void)
200 {
201 int i, j;
202
203 tst_sig(FORK, DEF_HANDLER, cleanup);
204
205 TEST_PAUSE;
206
207 numchild = NUMCHILD;
208 ncperchild = NCPERCHILD;
209
210 kidid = 0;
211
212 /* allocate read and write buffers */
213 szcharbuf = numchild * ncperchild;
214
215 /* make sure pipe write doesn't block */
216 if (szcharbuf == PIPE_BUF) {
217 /* adjust number of characters per child */
218 ncperchild = szcharbuf / numchild;
219 }
220
221 if ((wrbuf = malloc(szcharbuf)) == NULL) {
222 tst_brkm(TBROK, cleanup, "malloc failed");
223 }
224
225 if ((rdbuf = malloc(szcharbuf)) == NULL) {
226 tst_brkm(TBROK, cleanup, "malloc of rdbuf failed");
227 }
228
229 /* initialize wrbuf */
230 j = 0;
231 for (i = 0; i < szcharbuf;) {
232 wrbuf[i++] = rawchars[j++];
233 if (j >= sizeof(rawchars)) {
234 j = 0;
235 }
236 }
237 }
238
239 /*
240 * cleanup() - performs all ONE TIME cleanup for this test at
241 * completion or premature exit.
242 */
cleanup(void)243 void cleanup(void)
244 {
245
246 }
247