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