NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/59175: posix_spawn hang, hanging other process too
The attached program appears to reproduce the issue.
make waitrace
./waitraice &
while :; do kill -INFO %1; sleep 1; done
At some point, it will stop printing numbers because it is stuck.
This is probably some deadlock between some combination of p_reflock,
exec_lock, proc_lock, and who knows what other horrible lock
shenanigans posix_spawn gets itself into.
#include <sys/sysctl.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <spawn.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
unsigned long long n;
static void
info(int signo)
{
	char buf[32];
	snprintf_ss(buf, sizeof(buf), "%llu\n", n);
	(void)write(STDOUT_FILENO, buf, strlen(buf));
}
int
main(int argc, char **argv)
{
	static char buf[65536];
	int mib[] = {CTL_KERN, KERN_PROC_ARGS, /*pid*/-1, KERN_PROC_NARGV};
	sigset_t mask, omask;
	if (argc == 2) {
		ssize_t nread;
		nread = read(STDIN_FILENO, (char[]){0}, 1);
		if (nread == -1)
			err(1, "read");
		if (nread == 0)
			errx(1, "premature eof");
		return 0;
	}
	if (sigemptyset(&mask) == -1)
		err(1, "sigemptyset");
	if (sigaddset(&mask, SIGINFO) == -1)
		err(1, "sigaddset");
	if (signal(SIGINFO, &info) == SIG_ERR)
		err(1, "signal(SIGINFO)");
	for (;;) {
		char *const nargv[] = {argv[0], "stuff", NULL};
		int waitpipe[2];
		posix_spawn_file_actions_t fa;
		pid_t pid;
		size_t buflen;
		int status, error;
		if (pipe2(waitpipe, O_CLOEXEC) == -1)
			err(1, "pipe2");
		error = posix_spawn_file_actions_init(&fa);
		if (error)
			err(1, "posix_spawn_file_actions_init");
		error = posix_spawn_file_actions_adddup2(&fa, waitpipe[0],
		    STDIN_FILENO);
		if (error)
			err(1, "posix_spawn_file_actions_adddup2");
		error = posix_spawn(&pid, nargv[0], &fa, NULL, nargv, NULL);
		if (error)
			err(1, "posix_spawn");
		mib[2] = (int)pid;
		buflen = sizeof(buf);
		while (sysctl(mib, __arraycount(mib), buf, &buflen, NULL, 0)
		    == -1) {
			if (errno == EBUSY)
				continue;
			err(1, "sysctl kern.proc_args.%d.nargv", mib[2]);
		}
		if (close(waitpipe[0]) == -1)
			err(1, "close");
		if (write(waitpipe[1], (char[]){0}, 1) == -1)
			err(1, "write");
		if (close(waitpipe[1]))
			err(1, "write");
		error = posix_spawn_file_actions_destroy(&fa);
		if (error)
			err(1, "posix_spawn_file_actions_destroy");
		if (waitpid(pid, &status, 0) == -1)
			err(1, "waitpid");
		if (status != 0)
			errx(1, "status=0x%x", status);
		if (sigprocmask(SIG_BLOCK, &mask, &omask) == -1)
			err(1, "sigprocmask(SIG_BLOCK)");
		n++;
		if (sigprocmask(SIG_SETMASK, &omask, NULL) == -1)
			err(1, "sigprocmask(SIG_SETMASK)");
	}
	printf("%llu\n", n);
	fflush(stdout);
	return ferror(stdout);
}
Home |
Main Index |
Thread Index |
Old Index