Home | History | Annotate | Line # | Download | only in h_client
      1 /*	$NetBSD: h_stresscli.c,v 1.9 2011/06/26 13:17:36 christos Exp $	*/
      2 
      3 #include <sys/types.h>
      4 #include <sys/atomic.h>
      5 #include <sys/sysctl.h>
      6 #include <sys/wait.h>
      7 #include <sys/socket.h>
      8 
      9 #include <netinet/in.h>
     10 
     11 #include <err.h>
     12 #include <fcntl.h>
     13 #include <pthread.h>
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 #include <unistd.h>
     18 #include <signal.h>
     19 
     20 #include <rump/rump_syscalls.h>
     21 #include <rump/rumpclient.h>
     22 
     23 static unsigned int syscalls, bindcalls;
     24 static pid_t mypid;
     25 static volatile sig_atomic_t doquit;
     26 
     27 static void
     28 signaali(int sig)
     29 {
     30 
     31 	doquit = 1;
     32 }
     33 
     34 static const int hostnamemib[] = { CTL_KERN, KERN_HOSTNAME };
     35 static char hostnamebuf[128];
     36 #define HOSTNAMEBASE "rumpclient"
     37 
     38 static int iskiller;
     39 
     40 static void *
     41 client(void *arg)
     42 {
     43 	char buf[256];
     44 	struct sockaddr_in sin;
     45 	size_t blen;
     46 	int port = (int)(uintptr_t)arg;
     47 	int s, fd, x;
     48 
     49 	memset(&sin, 0, sizeof(sin));
     50 	sin.sin_family = AF_INET;
     51 	sin.sin_len = sizeof(sin);
     52 	sin.sin_port = htons(port);
     53 
     54 	while (!doquit) {
     55 		pid_t pidi;
     56 		blen = sizeof(buf);
     57 		s = rump_sys_socket(PF_INET, SOCK_STREAM, 0);
     58 		if (s == -1)
     59 			err(1, "socket");
     60 		atomic_inc_uint(&syscalls);
     61 
     62 		fd = rump_sys_open("/dev/null", O_RDWR);
     63 		atomic_inc_uint(&syscalls);
     64 
     65 		if (doquit)
     66 			goto out;
     67 
     68 		x = 1;
     69 		if (rump_sys_setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
     70 		    &x, sizeof(x)) == -1)
     71 			err(1, "reuseaddr");
     72 
     73 		/*
     74 		 * we don't really know when the kernel handles our disconnect,
     75 		 * so be soft about about the failure in case of a killer client
     76 		 */
     77 		if (rump_sys_bind(s, (struct sockaddr*)&sin, sizeof(sin))==-1) {
     78 			if (!iskiller)
     79 				err(1, "bind to port %d failed",
     80 				    ntohs(sin.sin_port));
     81 		} else {
     82 			atomic_inc_uint(&bindcalls);
     83 		}
     84 		atomic_inc_uint(&syscalls);
     85 
     86 		if (doquit)
     87 			goto out;
     88 
     89 		if (rump_sys___sysctl(hostnamemib, __arraycount(hostnamemib),
     90 		    buf, &blen, NULL, 0) == -1)
     91 			err(1, "sysctl");
     92 		if (strncmp(buf, hostnamebuf, sizeof(HOSTNAMEBASE)-1) != 0)
     93 			errx(1, "hostname (%s/%s) mismatch", buf, hostnamebuf);
     94 		atomic_inc_uint(&syscalls);
     95 
     96 		if (doquit)
     97 			goto out;
     98 
     99 		pidi = rump_sys_getpid();
    100 		if (pidi == -1)
    101 			err(1, "getpid");
    102 		if (pidi != mypid)
    103 			errx(1, "mypid mismatch");
    104 		atomic_inc_uint(&syscalls);
    105 
    106 		if (doquit)
    107 			goto out;
    108 
    109 		if (rump_sys_write(fd, buf, 16) != 16)
    110 			err(1, "write /dev/null");
    111 		atomic_inc_uint(&syscalls);
    112 
    113  out:
    114 		rump_sys_close(fd);
    115 		atomic_inc_uint(&syscalls);
    116 		rump_sys_close(s);
    117 		atomic_inc_uint(&syscalls);
    118 	}
    119 
    120 	return NULL;
    121 }
    122 
    123 /* Stress with max 32 clients, 8 threads each (256 concurrent threads) */
    124 #define NCLI 32
    125 #define NTHR 8
    126 
    127 int
    128 main(int argc, char *argv[])
    129 {
    130 	pthread_t pt[NTHR-1];
    131 	pid_t clis[NCLI];
    132 	pid_t apid;
    133 	int ncli = 0;
    134 	int i = 0, j;
    135 	int status, thesig;
    136 	int rounds, myport;
    137 
    138 	if (argc != 2 && argc != 3)
    139 		errx(1, "need roundcount");
    140 
    141 	if (argc == 3) {
    142 		if (strcmp(argv[2], "kill") != 0)
    143 			errx(1, "optional 3rd param must be kill");
    144 		thesig = SIGKILL;
    145 		iskiller = 1;
    146 	} else {
    147 		thesig = SIGUSR1;
    148 	}
    149 
    150 	signal(SIGUSR1, signaali);
    151 
    152 	memset(clis, 0, sizeof(clis));
    153 	for (rounds = 1; rounds < atoi(argv[1])*10; rounds++) {
    154 		while (ncli < NCLI) {
    155 			switch ((apid = fork())) {
    156 			case -1:
    157 				err(1, "fork failed");
    158 			case 0:
    159 				if (rumpclient_init() == -1)
    160 					err(1, "rumpclient init");
    161 
    162 				mypid = rump_sys_getpid();
    163 				sprintf(hostnamebuf, HOSTNAMEBASE "%d", mypid);
    164 				if (rump_sys___sysctl(hostnamemib,
    165 				    __arraycount(hostnamemib), NULL, NULL,
    166 				    hostnamebuf, strlen(hostnamebuf)+1) == -1)
    167 					err(1, "sethostname");
    168 
    169 				for (j = 0; j < NTHR-1; j++) {
    170 					myport = i*NCLI + j+2;
    171 					if (pthread_create(&pt[j], NULL,
    172 					    client,
    173 					    (void*)(uintptr_t)myport) !=0 )
    174 						err(1, "pthread create");
    175 				}
    176 				myport = i*NCLI+1;
    177 				client((void *)(uintptr_t)myport);
    178 				for (j = 0; j < NTHR-1; j++)
    179 					pthread_join(pt[j], NULL);
    180 				membar_consumer();
    181 				fprintf(stderr, "done %d\n", syscalls);
    182 				exit(0);
    183 				/* NOTREACHED */
    184 			default:
    185 				ncli++;
    186 				clis[i] = apid;
    187 				break;
    188 			}
    189 
    190 			i = (i + 1) % NCLI;
    191 		}
    192 
    193 		usleep(100000);
    194 		kill(clis[i], thesig);
    195 
    196 		apid = wait(&status);
    197 		if (apid != clis[i])
    198 			errx(1, "wanted pid %d, got %d\n", clis[i], apid);
    199 		clis[i] = 0;
    200 		ncli--;
    201 		if (thesig == SIGUSR1) {
    202 			if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
    203 				fprintf(stderr, "child died with 0x%x\n",
    204 				    status);
    205 				exit(1);
    206 			}
    207 		} else {
    208 			if (!WIFSIGNALED(status) || WTERMSIG(status) != thesig){
    209 				fprintf(stderr, "child died with 0x%x\n",
    210 				    status);
    211 				exit(1);
    212 			}
    213 		}
    214 	}
    215 
    216 	for (i = 0; i < NCLI; i++)
    217 		if (clis[i])
    218 			kill(clis[i], SIGKILL);
    219 }
    220