[CRIU] [PATCH]v2 service: SIGCHLD handler

Pavel Emelyanov xemul at parallels.com
Thu Oct 31 09:06:48 PDT 2013


On 10/31/2013 04:44 AM, Ruslan Kuprieiev wrote:
> Hi!
> 
> Now we're ignoring SIGCHLD from forked children.
> This patch provides SIGCHLD handler, that will wait for child and write some
> information about it's exit status to logfile.
> 
> P.S. This is my first signal handler, so please take a good look at this patch.
> 
> v2: fixed few mistakes. Thanks Andrew Vagin <avagin at parallels.com> for help.
> 
> Signed-off-by: Ruslan Kuprieiev <kupruser at gmail.com>
> ---
>  cr-service.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 75 insertions(+), 2 deletions(-)
> 
> diff --git a/cr-service.c b/cr-service.c
> index a79ebc7..a920824 100644
> --- a/cr-service.c
> +++ b/cr-service.c
> @@ -253,6 +253,53 @@ err:
>  	return -1;
>  }
>  
> +static void reap_worker(int signo)
> +{
> +	int saved_errno;
> +	int status;
> +	pid_t pid;
> +
> +	saved_errno = errno;
> +
> +	/*
> +	 * Accordingly to signal(7):
> +	 *   Multiple instances of real-time signals can be queued.  By
> +	 *   contrast, if multiple instances of a standard signal are
> +	 *   delivered while that signal is currently blocked, then only one
> +	 *   instance is queued.

No need in citing man page in code.

> +	 * So, as we block SIGCHLD, lets wait for every child that has
> +	 * changed state.
> +	 */
> +	while (1) {
> +		pid = waitpid(-1, &status, WNOHANG|WUNTRACED|WCONTINUED);

Why just WNOHANG is not enough?

> +
> +		if (pid <= 0) {
> +			errno = saved_errno;
> +			return;
> +		}
> +
> +		if (WIFEXITED(status))
> +			pr_info("Worker(pid %d) exited with %d\n",
> +				pid, WEXITSTATUS(status));
> +
> +		else if (WIFSIGNALED(status)) {
> +			pr_info("Worker(pid %d) ", pid);
> +#ifdef WCOREDUMP
> +			if (WCOREDUMP(status))
> +				pr_info("prodused a core dump and ");
> +#endif
> +			pr_info("was killed by %d\n", WTERMSIG(status));
> +
> +		} else if (WIFSTOPPED(status))
> +			pr_info("Worker(pid %d) was stopped by %d\n",
> +				pid, WSTOPSIG(status));
> +
> +		else if (WIFCONTINUED(status))
> +			pr_info("Worker(pid %d) was continued\n", pid);

I'm not sure we need all the events. Exited and killed is more than enough.

> +
> +	}
> +}
> +
>  int cr_service(bool daemon_mode)
>  {
>  	int server_fd = -1;
> @@ -264,6 +311,9 @@ int cr_service(bool daemon_mode)
>  	socklen_t server_addr_len;
>  	socklen_t client_addr_len;
>  
> +	struct sigaction new_action, old_action;
> +	sigset_t block_mask;

No need in dedicated block_mask, you can fill the mask
right on sigaction.

> +
>  	server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
>  	if (server_fd == -1) {
>  		pr_perror("Can't initialize service socket.");
> @@ -323,8 +373,25 @@ int cr_service(bool daemon_mode)
>  		}
>  	}
>  
> -	/* FIXME Do not ignore children's return values */
> -	signal(SIGCHLD, SIG_IGN);
> +	/* Set SIGCHLD handler */
> +	sigemptyset(&block_mask);
> +
> +	/* FIXME May need to block some other signals too */
> +	sigaddset(&block_mask, SIGCHLD);
> +	sigaddset(&block_mask, SIGINT);
> +	sigaddset(&block_mask, SIGQUIT);
> +	sigaddset(&block_mask, SIGHUP);
> +	sigaddset(&block_mask, SIGTERM);
> +	sigaddset(&block_mask, SIGTSTP);

Any explanation to this choice?

> +
> +	new_action.sa_handler = reap_worker;
> +	new_action.sa_mask	= block_mask;
> +	new_action.sa_flags	= SA_RESTART;
> +
> +	if (sigaction(SIGCHLD, &new_action, &old_action)) {
> +		pr_perror("Can't setup SIGCHLD handler");
> +		return -1;
> +	}
>  
>  	while (1) {
>  		int sk;
> @@ -342,6 +409,12 @@ int cr_service(bool daemon_mode)
>  		if (child_pid == 0) {
>  			int ret;
>  
> +			/* Set default SIGCHLD handler back */
> +			if (sigaction(SIGCHLD, &old_action, NULL)) {
> +				pr_perror("Can't setup default SIGCHLD handler back");
> +				exit(1);
> +			}
> +
>  			close(server_fd);
>  			ret = cr_service_work(sk);
>  			close(sk);
> 




More information about the CRIU mailing list