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