1/*	$NetBSD: h_execthr.c,v 1.7 2016/11/24 00:37:29 dholland Exp $	*/
2
3/*
4 * Copyright (c) 2011 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/types.h>
31#include <sys/sysctl.h>
32
33#include <err.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <pthread.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include <rump/rumpclient.h>
43#include <rump/rump_syscalls.h>
44
45//#define VERBOSE
46
47#ifdef VERBOSE
48#define SAY(...) printf(__VA_ARGS__)
49#else
50#define SAY(...)
51#endif
52
53static int canreturn = 0;
54
55/*
56 * Use a fairly large number of threads so that we have
57 * a better chance catching races.  XXX: this is rumpuser's
58 * MAXWORKER-1.
59 */
60#define NTHR 63
61
62#define P1_0 3
63#define P1_1 4
64#define P2_0 5
65#define P2_1 6
66
67static void *
68wrk(void *arg)
69{
70	int fd = (uintptr_t)arg;
71
72	rump_sys_read(fd, &fd, sizeof(fd));
73	if (!canreturn)
74		errx(1, "should not have returned");
75	if (fd != 37)
76		errx(1, "got invalid magic");
77
78	return NULL;
79}
80
81static int
82getproc(pid_t mypid, struct kinfo_proc2 *p)
83{
84	int name[6];
85	size_t len = sizeof(*p);
86
87	name[0] = CTL_KERN;
88	name[1] = KERN_PROC2;
89	name[2] = KERN_PROC_PID;
90	name[3] = mypid;
91	name[4] = len;
92	name[5] = 1;
93
94	return rump_sys___sysctl(name, __arraycount(name), p, &len, NULL, 0);
95}
96
97int
98main(int argc, char *argv[], char *envp[])
99{
100	struct kinfo_proc2 p;
101	char *execarg[3];
102	int p1[2], p2[2];
103	pid_t mypid;
104	pthread_t pt;
105	ssize_t n;
106	int i, execd;
107	char nexec[16];
108
109	if (argc > 1)
110		execd = atoi(argv[1]);
111	else
112		execd = 0;
113	sprintf(nexec, "%d", execd+1);
114	SAY("execd: %d\n", execd);
115
116	if (rumpclient_init() == -1) {
117		if (execd)
118			err(1, "init execd");
119		else
120			err(1, "init");
121	}
122	mypid = rump_sys_getpid();
123	SAY("rumpclient_init finished.\n");
124
125	if (execd) {
126		canreturn = 1;
127		errno = pthread_create(&pt, NULL,
128		    wrk, (void *)(uintptr_t)P2_0);
129		if (errno != 0)
130			err(1, "exec pthread_create");
131		SAY("startup pthread_create finished.\n");
132
133		i = 37;
134		rump_sys_write(P2_1, &i, sizeof(i));
135		pthread_join(pt, NULL);
136		SAY("startup pthread_join finished.\n");
137
138		n = rump_sys_read(P1_0, &i, sizeof(i));
139		if (n != -1 || errno != EBADF)
140			errx(1, "post-exec cloexec works");
141		SAY("startup rump_sys_read finished.\n");
142
143		getproc(mypid, &p);
144		SAY("startup getproc finished.\n");
145		if (p.p_nlwps != 2)
146			errx(1, "invalid nlwps: %lld", (long long)p.p_nlwps);
147
148		/* we passed? */
149		if (execd > 10) {
150			SAY("done.\n");
151			exit(0);
152		}
153
154		rump_sys_close(P2_0);
155		rump_sys_close(P2_1);
156	}
157
158	SAY("making pipes...\n");
159
160	if (rump_sys_pipe(p1) == -1)
161		err(1, "pipe1");
162	if (p1[0] != P1_0 || p1[1] != P1_1)
163		errx(1, "p1 assumptions failed %d %d", p1[0], p1[1]);
164	if (rump_sys_pipe(p2) == -1)
165		err(1, "pipe1");
166	if (p2[0] != P2_0 || p2[1] != P2_1)
167		errx(1, "p2 assumptions failed");
168	if (rump_sys_fcntl(p1[0], F_SETFD, FD_CLOEXEC) == -1)
169		err(1, "cloexec");
170	if (rump_sys_fcntl(p1[1], F_SETFD, FD_CLOEXEC) == -1)
171		err(1, "cloexec");
172
173	SAY("making threads...\n");
174
175	for (i = 0; i < NTHR; i++) {
176		errno = pthread_create(&pt, NULL,
177		    wrk, (void *)(uintptr_t)p1[0]);
178		if (errno != 0)
179			err(1, "pthread_create 1 %d", i);
180	}
181
182	for (i = 0; i < NTHR; i++) {
183		errno = pthread_create(&pt, NULL,
184		    wrk, (void *)(uintptr_t)p2[0]);
185		if (errno != 0)
186			err(1, "pthread_create 2 %d", i);
187	}
188
189	SAY("waiting for threads to start...\n");
190
191	/* wait for all the threads to be enjoying themselves */
192	for (;;) {
193		getproc(mypid, &p);
194		SAY("getproc finished.\n");
195		if (p.p_nlwps == 2*NTHR + 2)
196			break;
197		usleep(10000);
198	}
199
200	SAY("making some more threads start...\n");
201
202	/*
203	 * load up one more (big) set.  these won't start executing, though,
204	 * but we're interested in if they create blockage
205	 */
206	for (i = 0; i < 3*NTHR; i++) {
207		errno = pthread_create(&pt, NULL,
208		    wrk, (void *)(uintptr_t)p1[0]);
209		if (errno != 0)
210			err(1, "pthread_create 3 %d", i);
211	}
212
213	SAY("calling exec...\n");
214
215	/* then, we exec! */
216	execarg[0] = argv[0];
217	execarg[1] = nexec;
218	execarg[2] = NULL;
219	if (rumpclient_exec(argv[0], execarg, envp) == -1)
220		err(1, "exec");
221}
222