tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: using of fork() in multithreaded application



> Date: Wed, 22 Jan 2025 16:47:13 +0100
> From: Peter Skvarka <ps%softinengines.com@localhost>
> 
> On my NetBSD 10.1 I am trying to run multithreaded application where 
> first are created several threads and then is called fork() from main 
> thread.
> Forked child then calls execvp() .
> Passed command line (in argv argument) is "gcc", "-dumpversion".
> 
> Application freezes because it waits for finishing child and ps -auxd 
> shows child process "(gcc)"
> with flag zombie.
> 
> I have two questions:
> Is safe using of fork() in NetBSD 10.1 in mutlithreaded application ?

Generally yes, with the caveat that it is difficult for applications
to use correctly.

For example, if you have any application-specific locks, you usually
have to take them carefully in a pthread_atfork handler to avoid
deadlock in the child.

Do you have a minimal reproducer for the unexpected behaviour you're
seeing?  I just tried with the attached program and it worked fine.

$ ./hack
10.5.0
thread ran
$ 

> Does NetBSD 10.1 support "set follow-fork-mode child" when used 
> /usr/bin/gdb ? I can step through source code of forked child only 
> on-two lines not more.

Not sure offhand if it works, but if it doesn't work it's probably a
bug that should be reported separately (https://gnats.NetBSD.org).
#include <sys/wait.h>

#include <err.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

pthread_mutex_t m;

void *
runthread(void *cookie)
{
	int error;

	if ((error = pthread_mutex_lock(&m)) != 0)
		errc(1, error, "pthread_mutex_lock");
	printf("thread ran\n");
	if ((error = pthread_mutex_unlock(&m)) != 0)
		errc(1, error, "pthread_mutex_lock");

	return NULL;
}

int
main(void)
{
	pthread_t t;
	pid_t pid, child;
	int error;

	if ((error = pthread_mutex_init(&m, NULL)) != 0)
		errc(1, error, "pthread_mutex_init");
	if ((error = pthread_mutex_lock(&m)) != 0)
		errc(1, error, "pthread_mutex_lock");
	if ((error = pthread_create(&t, NULL, &runthread, NULL)) != 0)
		errc(1, error, "pthread_create");

	pid = fork();
	switch (pid) {
	case -1:
		err(1, "fork");
	case 0:
		execvp("gcc", (char *[]){"gcc", "-dumpversion", NULL});
		err(1, "execvp");
	default:
		break;
	}
	if ((child = waitpid(pid, NULL, 0)) == -1)
		err(1, "waitpid");
	if (child != pid) {
		errx(1, "waitpid returned %ld, expected %ld",
		    (long)child, (long)pid);
	}
	if ((error = pthread_mutex_unlock(&m)) != 0)
		errc(1, error, "pthread_mutex_lock");
	if ((error = pthread_join(t, NULL)) != 0)
		errc(1, error, "pthread_join");
	return 0;
}


Home | Main Index | Thread Index | Old Index