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