[CRIU] [PATCH 13/13] restore: collect signals from zombies

Andrey Vagin avagin at openvz.org
Thu Dec 20 06:54:21 EST 2012


Each zombie sends SIGCHLD to parent. crtools restores all pending
signals, so all other signals should be collected.

Here is a problems, that signals SIGCHLD can be merged, but crtools
should be sure, that all signals are collected.

For that crtools enumerate all tasks and waits an answer. A parent
answers for its dead children from a signal handler.

This operation should be done between CR_STATE_RESTORE and
CR_STATE_RESTORE_SIGCHLD. Two new states CR_STATE_RESTORE_ZOMBIES
and CR_STATE_RESTORE_PREP_ZOMBIES were added.

CR_STATE_RESTORE_PREP_ZOMBIES is used for waiting when all tasks
installes a special sighandler.

CR_STATE_RESTORE_ZOMBIES is used for waiting all zombies.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 cr-restore.c       | 38 ++++++++++++++++++++++++++++++++++++--
 include/crtools.h  |  3 +++
 include/restorer.h |  4 ++++
 pie/restorer.c     | 10 ++++++++++
 pstree.c           | 10 ++++++++++
 5 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index 127164d..1d5224e 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -684,7 +684,8 @@ static int restore_one_zombie(int pid, int exit_code)
 	if (task_entries != NULL) {
 		restore_finish_stage(CR_STATE_RESTORE);
 		zombie_prepare_signals();
-		restore_finish_stage(CR_STATE_RESTORE_SIGCHLD);
+		restore_finish_stage(CR_STATE_RESTORE_PREP_ZOMBIES);
+		futex_wait_until(&task_entries->pid, pid);
 	}
 
 	if (exit_code & 0x7f) {
@@ -1119,8 +1120,11 @@ static inline int stage_participants(int next_stage)
 	case CR_STATE_RESTORE_PGID:
 		return task_entries->nr_tasks;
 	case CR_STATE_RESTORE:
-	case CR_STATE_RESTORE_SIGCHLD:
+	case CR_STATE_RESTORE_ZOMBIES:
+	case CR_STATE_RESTORE_PREP_ZOMBIES:
 		return task_entries->nr_threads;
+	case CR_STATE_RESTORE_SIGCHLD:
+		return task_entries->nr_threads - atomic_get(&task_entries->nr_zombies);
 	}
 
 	BUG();
@@ -1146,6 +1150,7 @@ static int restore_root_task(struct pstree_item *init, struct cr_options *opts)
 {
 	int ret;
 	struct sigaction act, old_act;
+	struct pstree_item *pi;
 
 	ret = sigaction(SIGCHLD, NULL, &act);
 	if (ret < 0) {
@@ -1201,6 +1206,33 @@ static int restore_root_task(struct pstree_item *init, struct cr_options *opts)
 	if (ret < 0)
 		goto out;
 
+	pr_info("Prepare for restoring zombies\n");
+	ret = restore_switch_stage(CR_STATE_RESTORE_PREP_ZOMBIES);
+	if (ret < 0)
+		goto out;
+
+	pr_info("Prepare for restoring zombies\n");
+	ret = restore_switch_stage(CR_STATE_RESTORE_ZOMBIES);
+	if (ret < 0)
+		goto out;
+
+	pr_info("Wait threads %d %d\n", task_entries->nr_threads, task_entries->nr_tasks);
+	futex_wait_while_gt(&task_entries->nr_in_progress, task_entries->nr_tasks);
+	ret = (int) futex_get(&task_entries->nr_in_progress);
+	if(ret < 0)
+		goto out;
+
+	for_each_pstree_item(pi) {
+		if (pi->state == TASK_HELPER)
+			continue;
+		ret = (int) futex_get(&task_entries->nr_in_progress);
+		if (ret < 0)
+			goto out;
+		futex_set_and_wake(&task_entries->pid, pi->pid.virt);
+		pr_info("Wait %d\n", pi->pid.virt);
+		futex_wait_while(&task_entries->nr_in_progress, ret);
+	}
+
 	pr_info("Wait until all tasks are restored\n");
 	ret = restore_switch_stage(CR_STATE_RESTORE_SIGCHLD);
 	if (ret < 0)
@@ -1252,6 +1284,8 @@ static int prepare_task_entries()
 	task_entries->nr_tasks = 0;
 	task_entries->nr_helpers = 0;
 	futex_set(&task_entries->start, CR_STATE_FORKING);
+	atomic_set(&task_entries->nr_zombies, 0);
+	futex_set(&task_entries->pid, 0);
 
 	return 0;
 }
diff --git a/include/crtools.h b/include/crtools.h
index 702c59e..1681110 100644
--- a/include/crtools.h
+++ b/include/crtools.h
@@ -8,6 +8,7 @@
 #include "list.h"
 #include "util.h"
 #include "image.h"
+#include "lock.h"
 
 #include "../protobuf/vma.pb-c.h"
 
@@ -233,6 +234,8 @@ struct rst_info {
 
 	void			*premmapped_addr;
 	unsigned long		premmapped_len;
+
+	futex_t			*nr_zombies;
 };
 
 static inline int in_vma_area(struct vma_area *vma, unsigned long addr)
diff --git a/include/restorer.h b/include/restorer.h
index f7a762d..d1d75c9 100644
--- a/include/restorer.h
+++ b/include/restorer.h
@@ -254,14 +254,18 @@ enum {
 	CR_STATE_FORKING,
 	CR_STATE_RESTORE_PGID,
 	CR_STATE_RESTORE,
+	CR_STATE_RESTORE_PREP_ZOMBIES,
+	CR_STATE_RESTORE_ZOMBIES,
 	CR_STATE_RESTORE_SIGCHLD,
 	CR_STATE_COMPLETE
 };
 
 struct task_entries {
 	int nr_threads, nr_tasks, nr_helpers;
+	atomic_t nr_zombies;
 	futex_t nr_in_progress;
 	futex_t start;
+	futex_t pid;
 };
 
 static always_inline struct shmem_info *
diff --git a/pie/restorer.c b/pie/restorer.c
index df96416..02ef2f1 100644
--- a/pie/restorer.c
+++ b/pie/restorer.c
@@ -51,6 +51,10 @@ extern void cr_restore_rt (void) asm ("__cr_restore_rt")
 
 static void sigzombie_handler(int signal, siginfo_t *siginfo, void *data)
 {
+	pr_debug("%ld: Collect a zombie with (pid %d, %d)\n",
+		sys_getpid(), siginfo->si_pid, (int) futex_get(&task_entries->pid));
+	BUG_ON(siginfo->si_pid != futex_get(&task_entries->pid));
+	futex_dec_and_wake(&task_entries->nr_in_progress);
 }
 
 static void sigchld_handler(int signal, siginfo_t *siginfo, void *data)
@@ -252,6 +256,8 @@ long __export_restore_thread(struct thread_restore_args *args)
 	pr_info("%ld: Restored\n", sys_gettid());
 
 	restore_finish_stage(CR_STATE_RESTORE);
+	restore_finish_stage(CR_STATE_RESTORE_PREP_ZOMBIES);
+	restore_finish_stage(CR_STATE_RESTORE_ZOMBIES);
 
 	if (restore_signals(args->siginfo, args->siginfo_nr, 0))
 		goto core_restore_end;
@@ -803,6 +809,10 @@ long __export_restore_task(struct task_restore_core_args *args)
 	act.rt_sa_restorer = cr_restore_rt;
 	sys_sigaction(SIGCHLD, &act, NULL, sizeof(rt_sigset_t));
 
+	restore_finish_stage(CR_STATE_RESTORE_PREP_ZOMBIES);
+	futex_wait_until(&task_entries->pid, my_pid);
+	restore_finish_stage(CR_STATE_RESTORE_ZOMBIES);
+
 	sys_sigaction(SIGCHLD, &args->sigchld_act, NULL, sizeof(rt_sigset_t));
 
 	ret = restore_signals(args->siginfo, args->siginfo_nr, 1);
diff --git a/pstree.c b/pstree.c
index 3ba645e..30e4074 100644
--- a/pstree.c
+++ b/pstree.c
@@ -37,6 +37,16 @@ struct pstree_item *__alloc_pstree_item(bool rst)
 	if (!item)
 		return NULL;
 
+	if (rst) {
+		item->rst->nr_zombies = shmalloc(sizeof(*item->rst->nr_zombies));
+		if (item->rst->nr_zombies == NULL) {
+			xfree(item);
+			return NULL;
+		}
+
+		futex_init(item->rst->nr_zombies);
+	}
+
 	INIT_LIST_HEAD(&item->children);
 	INIT_LIST_HEAD(&item->sibling);
 
-- 
1.7.11.7



More information about the CRIU mailing list