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