]> git.saurik.com Git - apple/xnu.git/blame_incremental - tools/tests/libMicro/pipe.c
xnu-3248.60.10.tar.gz
[apple/xnu.git] / tools / tests / libMicro / pipe.c
... / ...
CommitLineData
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms
5 * of the Common Development and Distribution License
6 * (the "License"). You may not use this file except
7 * in compliance with the License.
8 *
9 * You can obtain a copy of the license at
10 * src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing
13 * permissions and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL
16 * HEADER in each file and include the License file at
17 * usr/src/OPENSOLARIS.LICENSE. If applicable,
18 * add the following below this CDDL HEADER, with the
19 * fields enclosed by brackets "[]" replaced with your
20 * own identifying information: Portions Copyright [yyyy]
21 * [name of copyright owner]
22 *
23 * CDDL HEADER END
24 */
25
26/*
27 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <sys/wait.h>
34#include <sys/socket.h>
35#include <netinet/in.h>
36#include <netinet/tcp.h>
37#include <arpa/inet.h>
38#include <netdb.h>
39#include <pthread.h>
40#include <signal.h>
41#include <string.h>
42#include <unistd.h>
43#include <stdlib.h>
44#include <stdio.h>
45#include <fcntl.h>
46#include <errno.h>
47
48#include "libmicro.h"
49
50typedef struct {
51 int ts_once;
52 pid_t ts_child;
53 pthread_t ts_thread;
54 int ts_in;
55 int ts_out;
56 int ts_in2;
57 int ts_out2;
58 int ts_lsn;
59 struct sockaddr_in ts_add;
60} tsd_t;
61
62#define FIRSTPORT 12345
63
64static char *modes[] = {"st", "mt", "mp", NULL};
65#define MD_SINGLE 0
66#define MD_MULTITHREAD 1
67#define MD_MULTIPROCESS 2
68
69static char *xports[] = {"pipe", "fifo", "sock", "tcp",
70 NULL};
71#define XP_PIPES 0
72#define XP_FIFOS 1
73#define XP_SOCKETPAIR 2
74#define XP_LOCALTCP 3
75
76#define DEFM MD_SINGLE
77#define DEFS 1024
78#define DEFX XP_PIPES
79
80static int optm = DEFM;
81static size_t opts = DEFS;
82static int optx = DEFX;
83static void *rbuf = NULL;
84static void *wbuf = NULL;
85
86int readall(int s, void *buf, size_t len);
87void *loopback(void *arg);
88int prepare_pipes(tsd_t *tsd);
89int prepare_fifos(tsd_t *tsd);
90int cleanup_fifos(tsd_t *tsd);
91int prepare_socketpair(tsd_t *tsd);
92int prepare_localtcp(tsd_t *tsd);
93int prepare_localtcp_once(tsd_t *tsd);
94char *lookupa(int x, char *names[]);
95int lookup(char *x, char *names[]);
96
97int
98benchmark_init()
99{
100 lm_tsdsize = sizeof (tsd_t);
101
102 (void) sprintf(lm_optstr, "m:s:x:");
103
104 (void) sprintf(lm_usage,
105 " [-m mode (st|mt|mp, default %s)]\n"
106 " [-s buffer-size (default %d)]\n"
107 " [-x transport (pipe|fifo|sock|tcp, default %s)]\n"
108 "notes: measures write()/read() across various transports\n",
109 lookupa(DEFM, modes), DEFS, lookupa(DEFX, xports));
110
111 (void) sprintf(lm_header, "%2s %4s", "md", "xprt");
112
113 return (0);
114}
115
116int
117benchmark_optswitch(int opt, char *optarg)
118{
119 int x;
120
121 switch (opt) {
122 case 'm':
123 x = lookup(optarg, modes);
124 if (x == -1)
125 return (-1);
126 optm = x;
127 break;
128 case 's':
129 opts = sizetoll(optarg);
130 break;
131 case 'x':
132 x = lookup(optarg, xports);
133 if (x == -1)
134 return (-1);
135 optx = x;
136 break;
137 default:
138 return (-1);
139 }
140 return (0);
141}
142
143int
144benchmark_initrun()
145{
146 if (optx == XP_FIFOS) {
147 if (geteuid() != 0) {
148 (void) printf("sorry, must be root to create fifos\n");
149 exit(1);
150 }
151 }
152
153 (void) setfdlimit(4 * lm_optT + 10);
154
155 rbuf = malloc(opts);
156 wbuf = malloc(opts);
157
158 return (0);
159}
160
161int
162benchmark_initbatch(void *tsd)
163{
164 tsd_t *ts = (tsd_t *)tsd;
165 int result;
166 pid_t pid;
167
168 switch (optx) {
169 case XP_SOCKETPAIR:
170 result = prepare_socketpair(ts);
171 break;
172 case XP_LOCALTCP:
173 result = prepare_localtcp(ts);
174 break;
175 case XP_FIFOS:
176 result = prepare_fifos(ts);
177 break;
178 case XP_PIPES:
179 default:
180 result = prepare_pipes(ts);
181 break;
182 }
183 if (result == -1) {
184 return (1);
185 }
186
187 switch (optm) {
188 case MD_MULTITHREAD:
189 result = pthread_create(&ts->ts_thread, NULL, loopback, tsd);
190 if (result == -1) {
191 return (1);
192 }
193 break;
194 case MD_MULTIPROCESS:
195 pid = fork();
196 switch (pid) {
197 case 0:
198 (void) loopback(tsd);
199 exit(0);
200 break;
201 case -1:
202 return (-1);
203 default:
204 ts->ts_child = pid;
205 break;
206 }
207 break;
208 case MD_SINGLE:
209 default:
210 break;
211 }
212
213 /* Prime the loopback */
214 if (write(ts->ts_out, wbuf, opts) != opts) {
215 return (1);
216 }
217 if (readall(ts->ts_in, rbuf, opts) != opts) {
218 return (1);
219 }
220
221 return (0);
222}
223
224int
225benchmark(void *tsd, result_t *res)
226{
227 tsd_t *ts = (tsd_t *)tsd;
228 int i;
229 int n;
230
231 for (i = 0; i < lm_optB; i++) {
232 if (write(ts->ts_out, wbuf, opts) != opts) {
233 res->re_errors++;
234 continue;
235 }
236
237 n = readall(ts->ts_in, rbuf, opts);
238 if (n == -1) {
239 res->re_errors++;
240 continue;
241 }
242 }
243 res->re_count = i;
244
245 return (0);
246}
247
248int
249benchmark_finibatch(void *tsd)
250{
251 tsd_t *ts = (tsd_t *)tsd;
252
253 /* Terminate the loopback */
254 (void) write(ts->ts_out, wbuf, opts);
255 (void) readall(ts->ts_in, rbuf, opts);
256
257 switch (optm) {
258 case MD_MULTITHREAD:
259 (void) close(ts->ts_in2);
260 (void) close(ts->ts_out2);
261 (void) pthread_join(ts->ts_thread, NULL);
262 break;
263 case MD_MULTIPROCESS:
264 (void) close(ts->ts_in2);
265 (void) close(ts->ts_out2);
266 (void) waitpid(ts->ts_child, NULL, 0);
267 break;
268 case MD_SINGLE:
269 default:
270 break;
271 }
272
273 (void) close(ts->ts_in);
274 (void) close(ts->ts_out);
275
276 if (optx == XP_FIFOS) {
277 (void) cleanup_fifos(ts);
278 }
279
280 return (0);
281}
282
283char *
284benchmark_result()
285{
286 static char result[256];
287
288 (void) sprintf(result, "%2s %4s",
289 lookupa(optm, modes), lookupa(optx, xports));
290
291 return (result);
292}
293
294int
295readall(int s, void *buf, size_t len)
296{
297 size_t n;
298 size_t total = 0;
299
300 for (;;) {
301 n = read(s, (void *)((long)buf + total), len - total);
302 if (n < 1) {
303 return (-1);
304 }
305 total += n;
306 if (total >= len) {
307 return (total);
308 }
309 }
310}
311
312void *
313loopback(void *arg)
314{
315 tsd_t *ts = (tsd_t *)arg;
316 int i, n, m;
317
318 /* Include priming and termination */
319 m = lm_optB + 2;
320
321 for (i = 0; i < m; i++) {
322 n = readall(ts->ts_in2, rbuf, opts);
323 if (n == -1) {
324 break;
325 }
326 if (write(ts->ts_out2, wbuf, opts) != opts) {
327 break;
328 }
329 }
330
331 return (NULL);
332}
333
334int
335prepare_localtcp_once(tsd_t *ts)
336{
337 int j;
338 int opt = 1;
339 struct hostent *host;
340
341 j = FIRSTPORT;
342
343 ts->ts_lsn = socket(AF_INET, SOCK_STREAM, 0);
344 if (ts->ts_lsn == -1) {
345 return (-1);
346 }
347
348 if (setsockopt(ts->ts_lsn, SOL_SOCKET, SO_REUSEADDR,
349 &opt, sizeof (int)) == -1) {
350 return (-1);
351 }
352
353 if ((host = gethostbyname("localhost")) == NULL) {
354 return (-1);
355 }
356
357 for (;;) {
358 (void) memset(&ts->ts_add, 0,
359 sizeof (struct sockaddr_in));
360 ts->ts_add.sin_family = AF_INET;
361 ts->ts_add.sin_port = htons(j++);
362 (void) memcpy(&ts->ts_add.sin_addr.s_addr,
363 host->h_addr_list[0], sizeof (struct in_addr));
364
365 if (bind(ts->ts_lsn,
366 (struct sockaddr *)&ts->ts_add,
367 sizeof (struct sockaddr_in)) == 0) {
368 break;
369 }
370
371 if (errno != EADDRINUSE) {
372 return (-1);
373 }
374 }
375
376 if (listen(ts->ts_lsn, 5) == -1) {
377 return (-1);
378 }
379
380 return (0);
381}
382
383int
384prepare_localtcp(tsd_t *ts)
385{
386 int result;
387 struct sockaddr_in addr;
388 int opt = 1;
389 socklen_t size;
390
391 if (ts->ts_once++ == 0) {
392 if (prepare_localtcp_once(ts) == -1) {
393 return (-1);
394 }
395 }
396
397 ts->ts_out = socket(AF_INET, SOCK_STREAM, 0);
398 if (ts->ts_out == -1) {
399 return (-1);
400 }
401
402 if (fcntl(ts->ts_out, F_SETFL, O_NDELAY) == -1) {
403 return (-1);
404 }
405
406 result = connect(ts->ts_out, (struct sockaddr *)&ts->ts_add,
407 sizeof (struct sockaddr_in));
408 if ((result == -1) && (errno != EINPROGRESS)) {
409 return (-1);
410 }
411
412 if (fcntl(ts->ts_out, F_SETFL, 0) == -1) {
413 return (-1);
414 }
415
416 size = sizeof (struct sockaddr);
417 result = accept(ts->ts_lsn, (struct sockaddr *)&addr, &size);
418 if (result == -1) {
419 return (-1);
420 }
421 ts->ts_out2 = result;
422
423 if (setsockopt(ts->ts_out, IPPROTO_TCP, TCP_NODELAY,
424 &opt, sizeof (int)) == -1) {
425 return (-1);
426 }
427
428 if (setsockopt(ts->ts_out2, IPPROTO_TCP, TCP_NODELAY,
429 &opt, sizeof (int)) == -1) {
430 return (-1);
431 }
432
433 if (optm == MD_SINGLE) {
434 ts->ts_in = ts->ts_out2;
435 } else {
436 ts->ts_in = ts->ts_out;
437 ts->ts_in2 = ts->ts_out2;
438 }
439
440 return (0);
441}
442
443int
444prepare_socketpair(tsd_t *ts)
445{
446 int s[2];
447
448 if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) == -1) {
449 return (-1);
450 }
451
452 if (optm == MD_SINGLE) {
453 ts->ts_in = s[0];
454 ts->ts_out = s[1];
455 } else {
456 ts->ts_in = s[0];
457 ts->ts_out = s[0];
458 ts->ts_in2 = s[1];
459 ts->ts_out2 = s[1];
460 }
461
462 return (0);
463}
464
465int
466prepare_fifos(tsd_t *ts)
467{
468 char path[64];
469
470 (void) sprintf(path, "/private/tmp/pipe_%ld.%dA",
471 getpid(), pthread_self());
472 if (mknod(path, 0600, S_IFIFO) == -1) {
473 return (-1);
474 }
475
476 if (optm == MD_SINGLE) {
477 ts->ts_in = open(path, O_RDONLY);
478 ts->ts_out = open(path, O_WRONLY);
479 } else {
480 ts->ts_in = open(path, O_RDONLY);
481 ts->ts_out2 = open(path, O_WRONLY);
482
483 (void) sprintf(path, "/private/tmp/pipe_%ld.%dB",
484 getpid(), pthread_self());
485 if (mknod(path, 0600, S_IFIFO) == -1) {
486 return (-1);
487 }
488
489 ts->ts_in2 = open(path, O_RDONLY);
490 ts->ts_out = open(path, O_WRONLY);
491 }
492
493 return (0);
494}
495
496/*ARGSUSED*/
497int
498cleanup_fifos(tsd_t *ts)
499{
500 char path[64];
501
502 (void) sprintf(path, "/private/tmp/pipe_%ld.%dA", getpid(), pthread_self());
503 (void) unlink(path);
504 (void) sprintf(path, "/private/tmp/pipe_%ld.%dB", getpid(), pthread_self());
505 (void) unlink(path);
506
507 return (0);
508}
509
510int
511prepare_pipes(tsd_t *ts)
512{
513 int p[2];
514
515 if (optm == MD_SINGLE) {
516 if (pipe(p) == -1) {
517 return (-1);
518 }
519 ts->ts_in = p[0];
520 ts->ts_out = p[1];
521
522 } else {
523 if (pipe(p) == -1) {
524 return (-1);
525 }
526 ts->ts_in = p[0];
527 ts->ts_out2 = p[1];
528
529 if (pipe(p) == -1) {
530 return (-1);
531 }
532 ts->ts_in2 = p[0];
533 ts->ts_out = p[1];
534 }
535
536 return (0);
537}
538
539char *
540lookupa(int x, char *names[])
541{
542 int i = 0;
543
544 while (names[i] != NULL) {
545 if (x == i) {
546 return (names[i]);
547 }
548 i++;
549 }
550 return (NULL);
551}
552
553int
554lookup(char *x, char *names[])
555{
556 int i = 0;
557
558 while (names[i] != NULL) {
559 if (strcmp(names[i], x) == 0) {
560 return (i);
561 }
562 i++;
563 }
564 return (-1);
565}