1272343Sngie/* $NetBSD: h_stresscli.c,v 1.9 2011/06/26 13:17:36 christos Exp $ */ 2272343Sngie 3272343Sngie#include <sys/types.h> 4272343Sngie#include <sys/atomic.h> 5272343Sngie#include <sys/sysctl.h> 6272343Sngie#include <sys/wait.h> 7272343Sngie#include <sys/socket.h> 8272343Sngie 9272343Sngie#include <netinet/in.h> 10272343Sngie 11272343Sngie#include <err.h> 12272343Sngie#include <fcntl.h> 13272343Sngie#include <pthread.h> 14272343Sngie#include <stdio.h> 15272343Sngie#include <stdlib.h> 16272343Sngie#include <string.h> 17272343Sngie#include <unistd.h> 18272343Sngie#include <signal.h> 19272343Sngie 20272343Sngie#include <rump/rump_syscalls.h> 21272343Sngie#include <rump/rumpclient.h> 22272343Sngie 23272343Sngiestatic unsigned int syscalls, bindcalls; 24272343Sngiestatic pid_t mypid; 25272343Sngiestatic volatile sig_atomic_t doquit; 26272343Sngie 27272343Sngiestatic void 28272343Sngiesignaali(int sig) 29272343Sngie{ 30272343Sngie 31272343Sngie doquit = 1; 32272343Sngie} 33272343Sngie 34272343Sngiestatic const int hostnamemib[] = { CTL_KERN, KERN_HOSTNAME }; 35272343Sngiestatic char hostnamebuf[128]; 36272343Sngie#define HOSTNAMEBASE "rumpclient" 37272343Sngie 38272343Sngiestatic int iskiller; 39272343Sngie 40272343Sngiestatic void * 41272343Sngieclient(void *arg) 42272343Sngie{ 43272343Sngie char buf[256]; 44272343Sngie struct sockaddr_in sin; 45272343Sngie size_t blen; 46272343Sngie int port = (int)(uintptr_t)arg; 47272343Sngie int s, fd, x; 48272343Sngie 49272343Sngie memset(&sin, 0, sizeof(sin)); 50272343Sngie sin.sin_family = AF_INET; 51272343Sngie sin.sin_len = sizeof(sin); 52272343Sngie sin.sin_port = htons(port); 53272343Sngie 54272343Sngie while (!doquit) { 55272343Sngie pid_t pidi; 56272343Sngie blen = sizeof(buf); 57272343Sngie s = rump_sys_socket(PF_INET, SOCK_STREAM, 0); 58272343Sngie if (s == -1) 59272343Sngie err(1, "socket"); 60272343Sngie atomic_inc_uint(&syscalls); 61272343Sngie 62272343Sngie fd = rump_sys_open("/dev/null", O_RDWR); 63272343Sngie atomic_inc_uint(&syscalls); 64272343Sngie 65272343Sngie if (doquit) 66272343Sngie goto out; 67272343Sngie 68272343Sngie x = 1; 69272343Sngie if (rump_sys_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 70272343Sngie &x, sizeof(x)) == -1) 71272343Sngie err(1, "reuseaddr"); 72272343Sngie 73272343Sngie /* 74272343Sngie * we don't really know when the kernel handles our disconnect, 75272343Sngie * so be soft about about the failure in case of a killer client 76272343Sngie */ 77272343Sngie if (rump_sys_bind(s, (struct sockaddr*)&sin, sizeof(sin))==-1) { 78272343Sngie if (!iskiller) 79272343Sngie err(1, "bind to port %d failed", 80272343Sngie ntohs(sin.sin_port)); 81272343Sngie } else { 82272343Sngie atomic_inc_uint(&bindcalls); 83272343Sngie } 84272343Sngie atomic_inc_uint(&syscalls); 85272343Sngie 86272343Sngie if (doquit) 87272343Sngie goto out; 88272343Sngie 89272343Sngie if (rump_sys___sysctl(hostnamemib, __arraycount(hostnamemib), 90272343Sngie buf, &blen, NULL, 0) == -1) 91272343Sngie err(1, "sysctl"); 92272343Sngie if (strncmp(buf, hostnamebuf, sizeof(HOSTNAMEBASE)-1) != 0) 93272343Sngie errx(1, "hostname (%s/%s) mismatch", buf, hostnamebuf); 94272343Sngie atomic_inc_uint(&syscalls); 95272343Sngie 96272343Sngie if (doquit) 97272343Sngie goto out; 98272343Sngie 99272343Sngie pidi = rump_sys_getpid(); 100272343Sngie if (pidi == -1) 101272343Sngie err(1, "getpid"); 102272343Sngie if (pidi != mypid) 103272343Sngie errx(1, "mypid mismatch"); 104272343Sngie atomic_inc_uint(&syscalls); 105272343Sngie 106272343Sngie if (doquit) 107272343Sngie goto out; 108272343Sngie 109272343Sngie if (rump_sys_write(fd, buf, 16) != 16) 110272343Sngie err(1, "write /dev/null"); 111272343Sngie atomic_inc_uint(&syscalls); 112272343Sngie 113272343Sngie out: 114272343Sngie rump_sys_close(fd); 115272343Sngie atomic_inc_uint(&syscalls); 116272343Sngie rump_sys_close(s); 117272343Sngie atomic_inc_uint(&syscalls); 118272343Sngie } 119272343Sngie 120272343Sngie return NULL; 121272343Sngie} 122272343Sngie 123272343Sngie/* Stress with max 32 clients, 8 threads each (256 concurrent threads) */ 124272343Sngie#define NCLI 32 125272343Sngie#define NTHR 8 126272343Sngie 127272343Sngieint 128272343Sngiemain(int argc, char *argv[]) 129272343Sngie{ 130272343Sngie pthread_t pt[NTHR-1]; 131272343Sngie pid_t clis[NCLI]; 132272343Sngie pid_t apid; 133272343Sngie int ncli = 0; 134272343Sngie int i = 0, j; 135272343Sngie int status, thesig; 136272343Sngie int rounds, myport; 137272343Sngie 138272343Sngie if (argc != 2 && argc != 3) 139272343Sngie errx(1, "need roundcount"); 140272343Sngie 141272343Sngie if (argc == 3) { 142272343Sngie if (strcmp(argv[2], "kill") != 0) 143272343Sngie errx(1, "optional 3rd param must be kill"); 144272343Sngie thesig = SIGKILL; 145272343Sngie iskiller = 1; 146272343Sngie } else { 147272343Sngie thesig = SIGUSR1; 148272343Sngie } 149272343Sngie 150272343Sngie signal(SIGUSR1, signaali); 151272343Sngie 152272343Sngie memset(clis, 0, sizeof(clis)); 153272343Sngie for (rounds = 1; rounds < atoi(argv[1])*10; rounds++) { 154272343Sngie while (ncli < NCLI) { 155272343Sngie switch ((apid = fork())) { 156272343Sngie case -1: 157272343Sngie err(1, "fork failed"); 158272343Sngie case 0: 159272343Sngie if (rumpclient_init() == -1) 160272343Sngie err(1, "rumpclient init"); 161272343Sngie 162272343Sngie mypid = rump_sys_getpid(); 163272343Sngie sprintf(hostnamebuf, HOSTNAMEBASE "%d", mypid); 164272343Sngie if (rump_sys___sysctl(hostnamemib, 165272343Sngie __arraycount(hostnamemib), NULL, NULL, 166272343Sngie hostnamebuf, strlen(hostnamebuf)+1) == -1) 167272343Sngie err(1, "sethostname"); 168272343Sngie 169272343Sngie for (j = 0; j < NTHR-1; j++) { 170272343Sngie myport = i*NCLI + j+2; 171272343Sngie if (pthread_create(&pt[j], NULL, 172272343Sngie client, 173272343Sngie (void*)(uintptr_t)myport) !=0 ) 174272343Sngie err(1, "pthread create"); 175272343Sngie } 176272343Sngie myport = i*NCLI+1; 177272343Sngie client((void *)(uintptr_t)myport); 178272343Sngie for (j = 0; j < NTHR-1; j++) 179272343Sngie pthread_join(pt[j], NULL); 180272343Sngie membar_consumer(); 181272343Sngie fprintf(stderr, "done %d\n", syscalls); 182272343Sngie exit(0); 183272343Sngie /* NOTREACHED */ 184272343Sngie default: 185272343Sngie ncli++; 186272343Sngie clis[i] = apid; 187272343Sngie break; 188272343Sngie } 189272343Sngie 190272343Sngie i = (i + 1) % NCLI; 191272343Sngie } 192272343Sngie 193272343Sngie usleep(100000); 194272343Sngie kill(clis[i], thesig); 195272343Sngie 196272343Sngie apid = wait(&status); 197272343Sngie if (apid != clis[i]) 198272343Sngie errx(1, "wanted pid %d, got %d\n", clis[i], apid); 199272343Sngie clis[i] = 0; 200272343Sngie ncli--; 201272343Sngie if (thesig == SIGUSR1) { 202272343Sngie if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 203272343Sngie fprintf(stderr, "child died with 0x%x\n", 204272343Sngie status); 205272343Sngie exit(1); 206272343Sngie } 207272343Sngie } else { 208272343Sngie if (!WIFSIGNALED(status) || WTERMSIG(status) != thesig){ 209272343Sngie fprintf(stderr, "child died with 0x%x\n", 210272343Sngie status); 211272343Sngie exit(1); 212272343Sngie } 213272343Sngie } 214272343Sngie } 215272343Sngie 216272343Sngie for (i = 0; i < NCLI; i++) 217272343Sngie if (clis[i]) 218272343Sngie kill(clis[i], SIGKILL); 219272343Sngie} 220