childs.c
author viric@llimona
Fri, 16 Jun 2006 18:45:24 +0200
changeset 62 39bf7ecd7b21
parent 51 a01abd65856a
permissions -rw-r--r--
IPV6_V6ONLY setsockopt added for the udp server.

#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <sys/wait.h> // Per wait
#include <assert.h> // Pels assert

#include "syslog.h"

/* Variables */
static int childs_alive = 0;

static int child[MAX_CHILDS];


/* Prototypes */
static void remove_child(const int pid);

/* Code */
void term_childs()
{
	int res;
	int i;

	sigset_t tmp, normal;

	/* block the child signals */
	sigemptyset(&tmp);
	sigaddset(&tmp, SIGCHLD);
	sigprocmask(SIG_BLOCK, &tmp, &normal);

	/* Send SIGTERM */
	for(i=0;i<childs_alive;i++)
	{
		res = kill(child[i], SIGTERM);
		fprintf(stderr, "Sent SIGTERM to %i\n", child[i]);
		/* Accepting the res == -1 && errno == ESRCH saves us
		 * from the race condition possible kill error */
		if (res == -1)
			assert( errno == ESRCH );
	}

	/* restore the mask */
	sigprocmask(SIG_SETMASK, &normal, NULL);

}

void wait_childs_die()
{
	/* Wait for the end */
	while(childs_alive > 0)
	{
		sleep(1);
	}
}

void child_handler(int parameter)
{
	pid_t pid;
	int status;

	do
	{
		pid = waitpid(-1, &status, WNOHANG);
		if (pid == -1)
		{
			if(errno == ECHILD)
			{
				/* We don't have more childs! */
				fprintf(stderr, "We don't have more childs.\n");
				childs_alive = 0;
				break;
			} else
			{
				fprintf(stderr, "waitpid failed. %s\n",
					strerror(errno));
				break;
			}
		}
		/* Debug */
		if (pid > 0)
		{
			fprintf(stderr, "Child %i died: 0x%08x\n",
				pid, status);
			remove_child(pid);
		}
	} while(pid > 0);
}

int child_fork()
{
	int pid;
	sigset_t tmp, normal;

	/* block the child signals */
	sigemptyset(&tmp);
	sigaddset(&tmp, SIGCHLD);
	sigprocmask(SIG_BLOCK, &tmp, &normal);


	if (childs_alive < MAX_CHILDS)
	{
		pid = fork();
	}
	else
	{
		pid = -1;
	}

	if (pid > 0)
	{
		/* Parent */

		/* MUTEX-ed actions with the SIGCHLD handler */
		child[childs_alive++] = pid;
	}

	/* restore the mask */
	sigprocmask(SIG_SETMASK, &normal, NULL);

	return pid;
}

/* This will be called only from the SIGCHLD handler */
static void remove_child(const int pid)
{
	int i;

	/* We update the child status */
	for(i=0;i<childs_alive;i++)
	{
		if(child[i] == pid)
			break;
	}

	for(i = i; i < (childs_alive-1); i++)
	{
		child[i] = child[i+1];
	}

	childs_alive--;
}

int get_childs_alive()
{
	int num;
	sigset_t tmp, normal;

	/* block the child signals */
	sigemptyset(&tmp);
	sigaddset(&tmp, SIGCHLD);
	sigprocmask(SIG_BLOCK, &tmp, &normal);

	num = childs_alive;

	/* restore the mask */
	sigprocmask(SIG_SETMASK, &normal, NULL);

	return num;
}