1272343Sngie/* $NetBSD: h_execthr.c,v 1.3 2014/08/13 00:03:00 pooka Exp $ */ 2272343Sngie 3272343Sngie/* 4272343Sngie * Copyright (c) 2011 The NetBSD Foundation, Inc. 5272343Sngie * All rights reserved. 6272343Sngie * 7272343Sngie * Redistribution and use in source and binary forms, with or without 8272343Sngie * modification, are permitted provided that the following conditions 9272343Sngie * are met: 10272343Sngie * 1. Redistributions of source code must retain the above copyright 11272343Sngie * notice, this list of conditions and the following disclaimer. 12272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 13272343Sngie * notice, this list of conditions and the following disclaimer in the 14272343Sngie * documentation and/or other materials provided with the distribution. 15272343Sngie * 16272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17272343Sngie * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18272343Sngie * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19272343Sngie * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20272343Sngie * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21272343Sngie * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22272343Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23272343Sngie * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25272343Sngie * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26272343Sngie * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27272343Sngie * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28272343Sngie */ 29272343Sngie 30272343Sngie#include <sys/types.h> 31272343Sngie#include <sys/sysctl.h> 32272343Sngie 33272343Sngie#include <err.h> 34272343Sngie#include <errno.h> 35272343Sngie#include <fcntl.h> 36272343Sngie#include <pthread.h> 37272343Sngie#include <stdio.h> 38272343Sngie#include <stdlib.h> 39272343Sngie#include <string.h> 40272343Sngie#include <unistd.h> 41272343Sngie 42272343Sngie#include <rump/rumpclient.h> 43272343Sngie#include <rump/rump_syscalls.h> 44272343Sngie 45272343Sngiestatic int canreturn = 0; 46272343Sngie 47272343Sngie/* 48272343Sngie * Use a fairly large number of threads so that we have 49272343Sngie * a better chance catching races. XXX: this is rumpuser's 50272343Sngie * MAXWORKER-1. 51272343Sngie */ 52272343Sngie#define NTHR 63 53272343Sngie 54272343Sngie#define P1_0 3 55272343Sngie#define P1_1 4 56272343Sngie#define P2_0 5 57272343Sngie#define P2_1 6 58272343Sngie 59272343Sngiestatic void * 60272343Sngiewrk(void *arg) 61272343Sngie{ 62272343Sngie int fd = (uintptr_t)arg; 63272343Sngie 64272343Sngie rump_sys_read(fd, &fd, sizeof(fd)); 65272343Sngie if (!canreturn) 66272343Sngie errx(1, "should not have returned"); 67272343Sngie if (fd != 37) 68272343Sngie errx(1, "got invalid magic"); 69272343Sngie 70272343Sngie return NULL; 71272343Sngie} 72272343Sngie 73272343Sngiestatic int 74272343Sngiegetproc(pid_t mypid, struct kinfo_proc2 *p) 75272343Sngie{ 76272343Sngie int name[6]; 77272343Sngie size_t len = sizeof(*p); 78272343Sngie 79272343Sngie name[0] = CTL_KERN; 80272343Sngie name[1] = KERN_PROC2; 81272343Sngie name[2] = KERN_PROC_PID; 82272343Sngie name[3] = mypid; 83272343Sngie name[4] = len; 84272343Sngie name[5] = 1; 85272343Sngie 86272343Sngie return rump_sys___sysctl(name, __arraycount(name), p, &len, NULL, 0); 87272343Sngie} 88272343Sngie 89272343Sngieint 90272343Sngiemain(int argc, char *argv[], char *envp[]) 91272343Sngie{ 92272343Sngie struct kinfo_proc2 p; 93272343Sngie char *execarg[3]; 94272343Sngie int p1[2], p2[2]; 95272343Sngie pid_t mypid; 96272343Sngie pthread_t pt; 97272343Sngie ssize_t n; 98272343Sngie int i, execd; 99272343Sngie char nexec[16]; 100272343Sngie 101272343Sngie if (argc > 1) 102272343Sngie execd = atoi(argv[1]); 103272343Sngie else 104272343Sngie execd = 0; 105272343Sngie sprintf(nexec, "%d", execd+1); 106272343Sngie 107272343Sngie if (rumpclient_init() == -1) { 108272343Sngie if (execd) 109272343Sngie err(1, "init execd"); 110272343Sngie else 111272343Sngie err(1, "init"); 112272343Sngie } 113272343Sngie mypid = rump_sys_getpid(); 114272343Sngie 115272343Sngie if (execd) { 116272343Sngie canreturn = 1; 117272343Sngie if (pthread_create(&pt, NULL, 118272343Sngie wrk, (void *)(uintptr_t)P2_0) != 0) 119272343Sngie errx(1, "exec pthread_create"); 120272343Sngie 121272343Sngie i = 37; 122272343Sngie rump_sys_write(P2_1, &i, sizeof(i)); 123272343Sngie pthread_join(pt, NULL); 124272343Sngie 125272343Sngie n = rump_sys_read(P1_0, &i, sizeof(i)); 126272343Sngie if (n != -1 || errno != EBADF) 127272343Sngie errx(1, "post-exec cloexec works"); 128272343Sngie 129272343Sngie getproc(mypid, &p); 130272343Sngie if (p.p_nlwps != 2) 131272343Sngie errx(1, "invalid nlwps: %lld", (long long)p.p_nlwps); 132272343Sngie 133272343Sngie /* we passed? */ 134272343Sngie if (execd > 10) 135272343Sngie exit(0); 136272343Sngie 137272343Sngie rump_sys_close(P2_0); 138272343Sngie rump_sys_close(P2_1); 139272343Sngie } 140272343Sngie 141272343Sngie if (rump_sys_pipe(p1) == -1) 142272343Sngie err(1, "pipe1"); 143272343Sngie if (p1[0] != P1_0 || p1[1] != P1_1) 144272343Sngie errx(1, "p1 assumptions failed %d %d", p1[0], p1[1]); 145272343Sngie if (rump_sys_pipe(p2) == -1) 146272343Sngie err(1, "pipe1"); 147272343Sngie if (p2[0] != P2_0 || p2[1] != P2_1) 148272343Sngie errx(1, "p2 assumptions failed"); 149272343Sngie if (rump_sys_fcntl(p1[0], F_SETFD, FD_CLOEXEC) == -1) 150272343Sngie err(1, "cloexec"); 151272343Sngie if (rump_sys_fcntl(p1[1], F_SETFD, FD_CLOEXEC) == -1) 152272343Sngie err(1, "cloexec"); 153272343Sngie 154272343Sngie for (i = 0; i < NTHR; i++) 155272343Sngie if (pthread_create(&pt, NULL, 156272343Sngie wrk, (void *)(uintptr_t)p1[0]) != 0) 157272343Sngie errx(1, "pthread_create 1 %d", i); 158272343Sngie 159272343Sngie for (i = 0; i < NTHR; i++) 160272343Sngie if (pthread_create(&pt, NULL, 161272343Sngie wrk, (void *)(uintptr_t)p2[0]) != 0) 162272343Sngie errx(1, "pthread_create 2 %d", i); 163272343Sngie 164272343Sngie /* wait for all the threads to be enjoying themselves */ 165272343Sngie for (;;) { 166272343Sngie getproc(mypid, &p); 167272343Sngie if (p.p_nlwps == 2*NTHR + 2) 168272343Sngie break; 169272343Sngie usleep(10000); 170272343Sngie } 171272343Sngie 172272343Sngie /* 173272343Sngie * load up one more (big) set. these won't start executing, though, 174272343Sngie * but we're interested in if they create blockage 175272343Sngie */ 176272343Sngie for (i = 0; i < 3*NTHR; i++) 177272343Sngie if (pthread_create(&pt, NULL, 178272343Sngie wrk, (void *)(uintptr_t)p1[0]) != 0) 179272343Sngie errx(1, "pthread_create 1 %d", i); 180272343Sngie 181272343Sngie /* then, we exec! */ 182272343Sngie execarg[0] = argv[0]; 183272343Sngie execarg[1] = nexec; 184272343Sngie execarg[2] = NULL; 185272343Sngie if (rumpclient_exec(argv[0], execarg, envp) == -1) 186272343Sngie err(1, "exec"); 187272343Sngie} 188