[CRIU] [PATCH 3/8] parasite: allow to wait more than one process on the exit from syscall

Andrey Vagin avagin at openvz.org
Fri Sep 13 05:53:40 EDT 2013


All processes must be started by PTRACE_SYSCALL. The function calls wait
in a loop and if a process on the exit from the required syscall, it
is stopped, otherwise it will be reexecuted by PTRACE_SYSCALL.

The function doesn't know, which processes should be trapped, so
you should care, that wait() will not catch someone else.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/parasite-syscall.h |  2 +-
 parasite-syscall.c         | 57 ++++++++++++++++++++++++++++------------------
 2 files changed, 36 insertions(+), 23 deletions(-)

diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h
index 1ae819a..3515a30 100644
--- a/include/parasite-syscall.h
+++ b/include/parasite-syscall.h
@@ -114,5 +114,5 @@ extern bool arch_can_dump_task(pid_t pid);
 extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 			       struct vm_area_list *vma_area_list);
 
-extern int parasite_stop_on_syscall(pid_t pid, int sys_nr);
+extern int parasite_stop_on_syscall(int tasks, int sys_nr);
 #endif /* __CR_PARASITE_SYSCALL_H__ */
diff --git a/parasite-syscall.c b/parasite-syscall.c
index 52b2f02..a8ef03d 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -759,20 +759,28 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
 	if (ret)
 		return -1;
 
-	if (parasite_stop_on_syscall(pid, __NR_rt_sigreturn))
+	if (parasite_stop_on_syscall(1, __NR_rt_sigreturn))
 		return -1;
 
 	return 0;
 }
 
-int parasite_stop_on_syscall(pid_t pid, const int sys_nr)
+/*
+ * Trap tasks on the exit from the specified syscall
+ *
+ * tasks - number of processes, which should be trapped
+ * sys_nr - the required syscall number
+ */
+int parasite_stop_on_syscall(int tasks, const int sys_nr)
 {
 	user_regs_struct_t regs;
 	int status, ret;
+	pid_t pid;
 
 	/* Stop all threads on the enter point in sys_rt_sigreturn */
-	while (1) {
-		if (wait4(pid, &status, __WALL, NULL) < 0) {
+	while (tasks) {
+		pid = wait4(-1, &status, __WALL, NULL);
+		if (pid == -1) {
 			pr_perror("wait4 failed");
 			return -1;
 		}
@@ -791,8 +799,30 @@ int parasite_stop_on_syscall(pid_t pid, const int sys_nr)
 
 		pr_debug("%d is going to execute the syscall %lx\n", pid, REG_SYSCALL_NR(regs));
 		if (REG_SYSCALL_NR(regs) == sys_nr) {
+			/*
+			 * The process is going to execute the required syscall,
+			 * the next stop will be on the exit from this syscall
+			 */
+			ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
+			if (ret) {
+				pr_perror("ptrace");
+				return -1;
+			}
+
+			pid = wait4(pid, &status, __WALL, NULL);
+			if (pid == -1) {
+				pr_perror("wait4 failed");
+				return -1;
+			}
+
+			if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) {
+				pr_err("Task is in unexpected state: %x\n", status);
+				return -1;
+			}
+
 			pr_debug("%d was stopped\n", pid);
-			break;
+			tasks--;
+			continue;
 		}
 
 		ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
@@ -802,23 +832,6 @@ int parasite_stop_on_syscall(pid_t pid, const int sys_nr)
 		}
 	}
 
-	ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
-	if (ret) {
-		pr_perror("ptrace");
-		return -1;
-	}
-
-	if (wait4(pid, &status, __WALL, NULL) != pid) {
-		pr_perror("wait4 failed");
-		return -1;
-	}
-
-	pr_debug("Trap %d\n", pid);
-	if (!WIFSTOPPED(status)) {
-		pr_err("%d\n", status);
-		return -1;
-	}
-
 	return 0;
 }
 
-- 
1.8.3.1



More information about the CRIU mailing list