💾 Archived View for thrig.me › blog › 2024 › 02 › 14 › child.c captured on 2024-12-17 at 11:55:11.

View Raw

More Information

⬅️ Previous capture (2024-03-21)

-=-=-=-=-=-=-

// child.c - ZOMBIES!! or various tests for how SIGCHILD handling
// behaves. there are things to TWEAK

#include <sys/wait.h>

#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void
handle_child(int unused)
{
	// just because there is a child handler does not mean it will
	// do anything sensible, or there could be bugs, etc
	printf("SIGCHLD %d\n", getpid());
}

void
default_case(void)
{
	int status;
	pid_t pid, ret;
	// TWEAK either the default or with a handler
	signal(SIGCHLD, SIG_DFL);
	//signal(SIGCHLD, handle_child);
	pid = fork();
	if (pid < 0) err(1, "fork");
	if (pid == 0) {
		sleep(1);
		_exit(42); // make the exit status more distinctive
	} else {
		sleep(5);
		raise(SIGCHLD);
		errno = 0;
		ret   = waitpid(WAIT_ANY, &status, WNOHANG);
		printf("WAITPID %d ret=%d status=%d errno=%d\n", pid, ret,
		       status, errno);
	}
}

// ignoring SIGCHILD will cause zombies not to accumulate, at least on
// modern unix systems that follow the SUSv3 specification
void
ignore_child(void)
{
	int status;
	pid_t pid, ret;
	// TWEAK with this commented out the child should become a
	// zombie for about 10 seconds
	signal(SIGCHLD, SIG_IGN);
	pid = fork();
	if (pid < 0) err(1, "fork");
	if (pid == 0) {
		sleep(1);
		_exit(42); // make the exit status more distinctive
	} else {
		sleep(10); // allow time to run process tools elsewhere
		//abort();
		errno = 0;
		ret   = waitpid(WAIT_ANY, &status, WNOHANG);
		printf("WAITPID %d ret=%d status=%d errno=%d\n", pid, ret,
		       status, errno);
	}
}

void
inherit_the_signals(void)
{
	int status;
	pid_t pid, ret, another_pid;
	// TWEAK SIG_IGN is probably not enough
	sigset_t block;
	sigemptyset(&block);
	sigaddset(&block, SIGCHLD);
	sigprocmask(SIG_BLOCK, &block, NULL);
	//signal(SIGCHLD, SIG_IGN);
	pid = fork();
	if (pid < 0) err(1, "fork");
	if (pid == 0) {
		signal(SIGCHLD, handle_child);
		another_pid = fork();
		if (another_pid < 0) err(1, "fork");
		if (another_pid == 0) {
			sleep(1);
			_exit(42); // make the exit status more distinctive
		} else {
			sleep(5);
			errno = 0;
			ret   = waitpid(WAIT_ANY, &status, WNOHANG);
			printf("WAITPID %d ret=%d status=%d errno=%d\n",
			       another_pid, ret, status, errno);
		}
	} else {
		wait(NULL);
	}
}

int
main(int argc, char *argv[])
{
	// TWEAK call one of these and fiddle with the function in
	// question as need be
	//default_case();
	//ignore_child();
	//inherit_the_signals();
}