summaryrefslogtreecommitdiff
path: root/native/libMicro-0.4.0/pipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'native/libMicro-0.4.0/pipe.c')
-rw-r--r--native/libMicro-0.4.0/pipe.c566
1 files changed, 566 insertions, 0 deletions
diff --git a/native/libMicro-0.4.0/pipe.c b/native/libMicro-0.4.0/pipe.c
new file mode 100644
index 0000000..e873d9f
--- /dev/null
+++ b/native/libMicro-0.4.0/pipe.c
@@ -0,0 +1,566 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms
+ * of the Common Development and Distribution License
+ * (the "License"). You may not use this file except
+ * in compliance with the License.
+ *
+ * You can obtain a copy of the license at
+ * src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL
+ * HEADER in each file and include the License file at
+ * usr/src/OPENSOLARIS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your
+ * own identifying information: Portions Copyright [yyyy]
+ * [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "libmicro.h"
+
+typedef struct {
+ int ts_once;
+ pid_t ts_child;
+ pthread_t ts_thread;
+ int ts_in;
+ int ts_out;
+ int ts_in2;
+ int ts_out2;
+ int ts_lsn;
+ struct sockaddr_in ts_add;
+} tsd_t;
+
+#define FIRSTPORT 12345
+
+static char *modes[] = {"st", "mt", "mp", NULL};
+#define MD_SINGLE 0
+#define MD_MULTITHREAD 1
+#define MD_MULTIPROCESS 2
+
+static char *xports[] = {"pipe", "fifo", "sock", "tcp",
+ NULL};
+#define XP_PIPES 0
+#define XP_FIFOS 1
+#define XP_SOCKETPAIR 2
+#define XP_LOCALTCP 3
+
+#define DEFM MD_SINGLE
+#define DEFS 1024
+#define DEFX XP_PIPES
+
+static int optm = DEFM;
+static size_t opts = DEFS;
+static int optx = DEFX;
+static void *rbuf = NULL;
+static void *wbuf = NULL;
+
+int readall(int s, void *buf, size_t len);
+void *loopback(void *arg);
+int prepare_pipes(tsd_t *tsd);
+int prepare_fifos(tsd_t *tsd);
+int cleanup_fifos(tsd_t *tsd);
+int prepare_socketpair(tsd_t *tsd);
+int prepare_localtcp(tsd_t *tsd);
+int prepare_localtcp_once(tsd_t *tsd);
+char *lookupa(int x, char *names[]);
+int lookup(char *x, char *names[]);
+
+int
+benchmark_init()
+{
+ lm_tsdsize = sizeof (tsd_t);
+
+ (void) sprintf(lm_optstr, "m:s:x:");
+
+ (void) sprintf(lm_usage,
+ " [-m mode (st|mt|mp, default %s)]\n"
+ " [-s buffer-size (default %d)]\n"
+ " [-x transport (pipe|fifo|sock|tcp, default %s)]\n"
+ "notes: measures write()/read() across various transports\n",
+ lookupa(DEFM, modes), DEFS, lookupa(DEFX, xports));
+
+ (void) sprintf(lm_header, "%2s %4s", "md", "xprt");
+
+ return (0);
+}
+
+int
+benchmark_optswitch(int opt, char *optarg)
+{
+ int x;
+
+ switch (opt) {
+ case 'm':
+ x = lookup(optarg, modes);
+ if (x == -1)
+ return (-1);
+ optm = x;
+ break;
+ case 's':
+ opts = sizetoll(optarg);
+ break;
+ case 'x':
+ x = lookup(optarg, xports);
+ if (x == -1)
+ return (-1);
+ optx = x;
+ break;
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+int
+benchmark_initrun()
+{
+ if (optx == XP_FIFOS) {
+ if (geteuid() != 0) {
+ (void) printf("sorry, must be root to create fifos\n");
+ exit(1);
+ }
+ }
+
+ (void) setfdlimit(4 * lm_optT + 10);
+
+ rbuf = malloc(opts);
+ wbuf = malloc(opts);
+
+ return (0);
+}
+
+int
+benchmark_initbatch(void *tsd)
+{
+ tsd_t *ts = (tsd_t *)tsd;
+ int result;
+ pid_t pid;
+ int i;
+
+ switch (optx) {
+ case XP_SOCKETPAIR:
+ result = prepare_socketpair(ts);
+ break;
+ case XP_LOCALTCP:
+ result = prepare_localtcp(ts);
+ break;
+ case XP_FIFOS:
+ result = prepare_fifos(ts);
+ break;
+ case XP_PIPES:
+ default:
+ result = prepare_pipes(ts);
+ break;
+ }
+ if (result == -1) {
+ return (1);
+ }
+
+ switch (optm) {
+ case MD_MULTITHREAD:
+ result = pthread_create(&ts->ts_thread, NULL, loopback, tsd);
+ if (result == -1) {
+ return (1);
+ }
+ break;
+ case MD_MULTIPROCESS:
+ pid = fork();
+ switch (pid) {
+ case 0:
+ (void) loopback(tsd);
+ exit(0);
+ break;
+ case -1:
+ return (-1);
+ default:
+ ts->ts_child = pid;
+ break;
+ }
+ break;
+ case MD_SINGLE:
+ default:
+ break;
+ }
+
+ /* Prime the loopback */
+ if (write(ts->ts_out, wbuf, opts) != opts) {
+ return (1);
+ }
+ if (readall(ts->ts_in, rbuf, opts) != opts) {
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+benchmark(void *tsd, result_t *res)
+{
+ tsd_t *ts = (tsd_t *)tsd;
+ int i;
+ int n;
+
+ for (i = 0; i < lm_optB; i++) {
+ if (write(ts->ts_out, wbuf, opts) != opts) {
+ res->re_errors++;
+ continue;
+ }
+
+ n = readall(ts->ts_in, rbuf, opts);
+ if (n == -1) {
+ res->re_errors++;
+ continue;
+ }
+ }
+ res->re_count = i;
+
+ return (0);
+}
+
+int
+benchmark_finibatch(void *tsd)
+{
+ tsd_t *ts = (tsd_t *)tsd;
+
+ /* Terminate the loopback */
+ (void) write(ts->ts_out, wbuf, opts);
+ (void) readall(ts->ts_in, rbuf, opts);
+
+ switch (optm) {
+ case MD_MULTITHREAD:
+ (void) close(ts->ts_in2);
+ (void) close(ts->ts_out2);
+ (void) pthread_join(ts->ts_thread, NULL);
+ break;
+ case MD_MULTIPROCESS:
+ (void) close(ts->ts_in2);
+ (void) close(ts->ts_out2);
+ (void) waitpid(ts->ts_child, NULL, 0);
+ break;
+ case MD_SINGLE:
+ default:
+ break;
+ }
+
+ (void) close(ts->ts_in);
+ (void) close(ts->ts_out);
+
+ if (optx == XP_FIFOS) {
+ (void) cleanup_fifos(ts);
+ }
+
+ return (0);
+}
+
+char *
+benchmark_result()
+{
+ static char result[256];
+
+ (void) sprintf(result, "%2s %4s",
+ lookupa(optm, modes), lookupa(optx, xports));
+
+ return (result);
+}
+
+int
+readall(int s, void *buf, size_t len)
+{
+ size_t n;
+ size_t total = 0;
+
+ for (;;) {
+ n = read(s, (void *)((long)buf + total), len - total);
+ if (n < 1) {
+ return (-1);
+ }
+ total += n;
+ if (total >= len) {
+ return (total);
+ }
+ }
+}
+
+void *
+loopback(void *arg)
+{
+ tsd_t *ts = (tsd_t *)arg;
+ int i, n, m;
+
+ /* Include priming and termination */
+ m = lm_optB + 2;
+
+ for (i = 0; i < m; i++) {
+ n = readall(ts->ts_in2, rbuf, opts);
+ if (n == -1) {
+ break;
+ }
+ if (write(ts->ts_out2, wbuf, opts) != opts) {
+ break;
+ }
+ }
+
+ return (NULL);
+}
+
+int
+prepare_localtcp_once(tsd_t *ts)
+{
+ int j;
+ int opt = 1;
+ struct hostent *host;
+
+ j = FIRSTPORT;
+
+ ts->ts_lsn = socket(AF_INET, SOCK_STREAM, 0);
+ if (ts->ts_lsn == -1) {
+ return (-1);
+ }
+
+ if (setsockopt(ts->ts_lsn, SOL_SOCKET, SO_REUSEADDR,
+ &opt, sizeof (int)) == -1) {
+ return (-1);
+ }
+
+ if ((host = gethostbyname("localhost")) == NULL) {
+ return (-1);
+ }
+
+ for (;;) {
+ (void) memset(&ts->ts_add, 0,
+ sizeof (struct sockaddr_in));
+ ts->ts_add.sin_family = AF_INET;
+ ts->ts_add.sin_port = htons(j++);
+ (void) memcpy(&ts->ts_add.sin_addr.s_addr,
+ host->h_addr_list[0], sizeof (struct in_addr));
+
+ if (bind(ts->ts_lsn,
+ (struct sockaddr *)&ts->ts_add,
+ sizeof (struct sockaddr_in)) == 0) {
+ break;
+ }
+
+ if (errno != EADDRINUSE) {
+ return (-1);
+ }
+ }
+
+ if (listen(ts->ts_lsn, 5) == -1) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+prepare_localtcp(tsd_t *ts)
+{
+ int result;
+ struct sockaddr_in addr;
+ int opt = 1;
+ socklen_t size;
+
+ if (ts->ts_once++ == 0) {
+ if (prepare_localtcp_once(ts) == -1) {
+ return (-1);
+ }
+ }
+
+ ts->ts_out = socket(AF_INET, SOCK_STREAM, 0);
+ if (ts->ts_out == -1) {
+ return (-1);
+ }
+
+ if (fcntl(ts->ts_out, F_SETFL, O_NDELAY) == -1) {
+ return (-1);
+ }
+
+ result = connect(ts->ts_out, (struct sockaddr *)&ts->ts_add,
+ sizeof (struct sockaddr_in));
+ if ((result == -1) && (errno != EINPROGRESS)) {
+ return (-1);
+ }
+
+ if (fcntl(ts->ts_out, F_SETFL, 0) == -1) {
+ return (-1);
+ }
+
+ size = sizeof (struct sockaddr);
+ result = accept(ts->ts_lsn, (struct sockaddr *)&addr, &size);
+ if (result == -1) {
+ return (-1);
+ }
+ ts->ts_out2 = result;
+
+ if (setsockopt(ts->ts_out, IPPROTO_TCP, TCP_NODELAY,
+ &opt, sizeof (int)) == -1) {
+ return (-1);
+ }
+
+ if (setsockopt(ts->ts_out2, IPPROTO_TCP, TCP_NODELAY,
+ &opt, sizeof (int)) == -1) {
+ return (-1);
+ }
+
+ if (optm == MD_SINGLE) {
+ ts->ts_in = ts->ts_out2;
+ } else {
+ ts->ts_in = ts->ts_out;
+ ts->ts_in2 = ts->ts_out2;
+ }
+
+ return (0);
+}
+
+int
+prepare_socketpair(tsd_t *ts)
+{
+ int s[2];
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) == -1) {
+ return (-1);
+ }
+
+ if (optm == MD_SINGLE) {
+ ts->ts_in = s[0];
+ ts->ts_out = s[1];
+ } else {
+ ts->ts_in = s[0];
+ ts->ts_out = s[0];
+ ts->ts_in2 = s[1];
+ ts->ts_out2 = s[1];
+ }
+
+ return (0);
+}
+
+int
+prepare_fifos(tsd_t *ts)
+{
+ char path[64];
+
+ (void) sprintf(path, "/tmp/pipe_%ld.%dA",
+ getpid(), pthread_self());
+ if (mknod(path, 0600, S_IFIFO) == -1) {
+ return (-1);
+ }
+
+ if (optm == MD_SINGLE) {
+ ts->ts_in = open(path, O_RDONLY);
+ ts->ts_out = open(path, O_WRONLY);
+ } else {
+ ts->ts_in = open(path, O_RDONLY);
+ ts->ts_out2 = open(path, O_WRONLY);
+
+ (void) sprintf(path, "/tmp/pipe_%ld.%dB",
+ getpid(), pthread_self());
+ if (mknod(path, 0600, S_IFIFO) == -1) {
+ return (-1);
+ }
+
+ ts->ts_in2 = open(path, O_RDONLY);
+ ts->ts_out = open(path, O_WRONLY);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+cleanup_fifos(tsd_t *ts)
+{
+ char path[64];
+
+ (void) sprintf(path, "/tmp/pipe_%ld.%dA", getpid(), pthread_self());
+ (void) unlink(path);
+ (void) sprintf(path, "/tmp/pipe_%ld.%dB", getpid(), pthread_self());
+ (void) unlink(path);
+
+ return (0);
+}
+
+int
+prepare_pipes(tsd_t *ts)
+{
+ int p[2];
+
+ if (optm == MD_SINGLE) {
+ if (pipe(p) == -1) {
+ return (-1);
+ }
+ ts->ts_in = p[0];
+ ts->ts_out = p[1];
+
+ } else {
+ if (pipe(p) == -1) {
+ return (-1);
+ }
+ ts->ts_in = p[0];
+ ts->ts_out2 = p[1];
+
+ if (pipe(p) == -1) {
+ return (-1);
+ }
+ ts->ts_in2 = p[0];
+ ts->ts_out = p[1];
+ }
+
+ return (0);
+}
+
+char *
+lookupa(int x, char *names[])
+{
+ int i = 0;
+
+ while (names[i] != NULL) {
+ if (x == i) {
+ return (names[i]);
+ }
+ i++;
+ }
+ return (NULL);
+}
+
+int
+lookup(char *x, char *names[])
+{
+ int i = 0;
+
+ while (names[i] != NULL) {
+ if (strcmp(names[i], x) == 0) {
+ return (i);
+ }
+ i++;
+ }
+ return (-1);
+}