Re: using of fork() in multithreaded application

Taylor R Campbell <[email protected]>
Newsgroups gmane.os.netbsd.devel.kernel
Message-ID <[email protected]>
> Date: Wed, 22 Jan 2025 16:47:13 +0100
> From: Peter Skvarka <[email protected]>
> 
> 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).
hack.c (text/plain, 1.2 KB)
#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;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.