/* $NetBSD: h_execthr.c,v 1.3 2014/08/13 00:03:00 pooka Exp $ */ /* * Copyright (c) 2011 The NetBSD Foundation, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include static int canreturn = 0; /* * Use a fairly large number of threads so that we have * a better chance catching races. XXX: this is rumpuser's * MAXWORKER-1. */ #define NTHR 63 #define P1_0 3 #define P1_1 4 #define P2_0 5 #define P2_1 6 static void * wrk(void *arg) { int fd = (uintptr_t)arg; rump_sys_read(fd, &fd, sizeof(fd)); if (!canreturn) errx(1, "should not have returned"); if (fd != 37) errx(1, "got invalid magic"); return NULL; } static int getproc(pid_t mypid, struct kinfo_proc2 *p) { int name[6]; size_t len = sizeof(*p); name[0] = CTL_KERN; name[1] = KERN_PROC2; name[2] = KERN_PROC_PID; name[3] = mypid; name[4] = len; name[5] = 1; return rump_sys___sysctl(name, __arraycount(name), p, &len, NULL, 0); } int main(int argc, char *argv[], char *envp[]) { struct kinfo_proc2 p; char *execarg[3]; int p1[2], p2[2]; pid_t mypid; pthread_t pt; ssize_t n; int i, execd; char nexec[16]; if (argc > 1) execd = atoi(argv[1]); else execd = 0; sprintf(nexec, "%d", execd+1); if (rumpclient_init() == -1) { if (execd) err(1, "init execd"); else err(1, "init"); } mypid = rump_sys_getpid(); if (execd) { canreturn = 1; if (pthread_create(&pt, NULL, wrk, (void *)(uintptr_t)P2_0) != 0) errx(1, "exec pthread_create"); i = 37; rump_sys_write(P2_1, &i, sizeof(i)); pthread_join(pt, NULL); n = rump_sys_read(P1_0, &i, sizeof(i)); if (n != -1 || errno != EBADF) errx(1, "post-exec cloexec works"); getproc(mypid, &p); if (p.p_nlwps != 2) errx(1, "invalid nlwps: %lld", (long long)p.p_nlwps); /* we passed? */ if (execd > 10) exit(0); rump_sys_close(P2_0); rump_sys_close(P2_1); } if (rump_sys_pipe(p1) == -1) err(1, "pipe1"); if (p1[0] != P1_0 || p1[1] != P1_1) errx(1, "p1 assumptions failed %d %d", p1[0], p1[1]); if (rump_sys_pipe(p2) == -1) err(1, "pipe1"); if (p2[0] != P2_0 || p2[1] != P2_1) errx(1, "p2 assumptions failed"); if (rump_sys_fcntl(p1[0], F_SETFD, FD_CLOEXEC) == -1) err(1, "cloexec"); if (rump_sys_fcntl(p1[1], F_SETFD, FD_CLOEXEC) == -1) err(1, "cloexec"); for (i = 0; i < NTHR; i++) if (pthread_create(&pt, NULL, wrk, (void *)(uintptr_t)p1[0]) != 0) errx(1, "pthread_create 1 %d", i); for (i = 0; i < NTHR; i++) if (pthread_create(&pt, NULL, wrk, (void *)(uintptr_t)p2[0]) != 0) errx(1, "pthread_create 2 %d", i); /* wait for all the threads to be enjoying themselves */ for (;;) { getproc(mypid, &p); if (p.p_nlwps == 2*NTHR + 2) break; usleep(10000); } /* * load up one more (big) set. these won't start executing, though, * but we're interested in if they create blockage */ for (i = 0; i < 3*NTHR; i++) if (pthread_create(&pt, NULL, wrk, (void *)(uintptr_t)p1[0]) != 0) errx(1, "pthread_create 1 %d", i); /* then, we exec! */ execarg[0] = argv[0]; execarg[1] = nexec; execarg[2] = NULL; if (rumpclient_exec(argv[0], execarg, envp) == -1) err(1, "exec"); }