[CRIU] [PATCH 05/14] crtools: dump pending signals (v4)

Andrey Vagin avagin at openvz.org
Mon Mar 25 10:37:48 EDT 2013


PTRACE_PEEKSIGINFO is used for received pending signals,
then all signal are sent back and saved in a image.

v2: rework according with the new kernel interface
v3: rework according with the newrest kernel interface
v4: fix error handling

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 cr-dump.c        | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 include/ptrace.h | 13 ++++++++++
 2 files changed, 82 insertions(+), 3 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index 08b01ac..8629676 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -28,6 +28,7 @@
 #include "protobuf/core.pb-c.h"
 #include "protobuf/file-lock.pb-c.h"
 #include "protobuf/rlimit.pb-c.h"
+#include "protobuf/siginfo.pb-c.h"
 
 #include "asm/types.h"
 #include "list.h"
@@ -1165,6 +1166,63 @@ err:
 	return ret;
 }
 
+static int dump_signal_queue(pid_t tid, int fd, bool group)
+{
+	struct ptrace_peeksiginfo_args arg;
+	siginfo_t siginfo[32]; /* One page or all non-rt signals */
+	int ret, i = 0, j, nr;
+
+	arg.nr = sizeof(siginfo) / sizeof(siginfo_t);
+	arg.flags = 0;
+	if (group)
+		arg.flags |= PTRACE_PEEKSIGINFO_SHARED;
+
+	for (; ; ) {
+		arg.off = i;
+
+		ret = ptrace(PTRACE_PEEKSIGINFO, tid, &arg, siginfo);
+		if (ret < 0) {
+			if (errno == EIO) {
+				pr_warn("ptrace doesn't support PTRACE_PEEKSIGINFO\n");
+				ret = 0;
+			} else
+				pr_perror("ptrace");
+			break;
+		}
+
+		if (ret == 0)
+			break;
+		nr = ret;
+
+		for (j = 0; j < nr; j++) {
+			SiginfoEntry sie = SIGINFO_ENTRY__INIT;
+
+			sie.siginfo.len = sizeof(siginfo_t);
+			sie.siginfo.data = (void *) (siginfo + j);
+
+			ret = pb_write_one(fd, &sie, PB_SIGINFO);
+			if (ret < 0)
+				break;
+			i++;
+		}
+	}
+
+	return ret;
+}
+
+static int dump_thread_signals(struct pid *tid)
+{
+	int fd, ret;
+
+	fd = open_image(CR_FD_PSIGNAL, O_DUMP, tid->virt);
+	if (fd < 0)
+		return -1;
+	ret = dump_signal_queue(tid->real, fd, false);
+	close(fd);
+
+	return ret;
+}
+
 static struct proc_pid_stat pps_buf;
 
 static int dump_task_threads(struct parasite_ctl *parasite_ctl,
@@ -1174,12 +1232,14 @@ static int dump_task_threads(struct parasite_ctl *parasite_ctl,
 
 	for (i = 0; i < item->nr_threads; i++) {
 		/* Leader is already dumped */
-		if (item->pid.real == item->threads[i].real) {
+		if (item->pid.real == item->threads[i].real)
 			item->threads[i].virt = item->pid.virt;
-			continue;
+		else {
+			if (dump_task_thread(parasite_ctl, &item->threads[i]))
+				return -1;
 		}
 
-		if (dump_task_thread(parasite_ctl, &item->threads[i]))
+		if (dump_thread_signals(&item->threads[i]))
 			return -1;
 	}
 
@@ -1429,6 +1489,12 @@ static int dump_one_task(struct pstree_item *item)
 		goto err;
 	}
 
+	ret = dump_signal_queue(pid, fdset_fd(cr_fdset, CR_FD_SIGNAL), true);
+	if (ret) {
+		pr_err("Can't dump pending signals (pid: %d)\n", pid);
+		goto err_cure;
+	}
+
 	close_cr_fdset(&cr_fdset);
 err:
 	close_pid_proc();
diff --git a/include/ptrace.h b/include/ptrace.h
index ea45d20..4d1bc92 100644
--- a/include/ptrace.h
+++ b/include/ptrace.h
@@ -1,6 +1,7 @@
 #ifndef __CR_SEIZE_H__
 #define __CR_SEIZE_H__
 
+#include <linux/types.h>
 #include <sys/ptrace.h>
 
 /* some constants for ptrace */
@@ -14,6 +15,18 @@
 
 #define PTRACE_LISTEN		0x4208
 
+#ifndef PTRACE_PEEKSIGINFO
+#define PTRACE_PEEKSIGINFO      0x4209
+struct ptrace_peeksiginfo_args {
+        __u64 off;	/* from which siginfo to start */
+        __u32 flags;
+        __u32 nr;	/* how may siginfos to take */
+};
+
+/* Read signals from a shared (process wide) queue */
+#define PTRACE_PEEKSIGINFO_SHARED       (1 << 0)
+#endif
+
 #define PTRACE_SEIZE_DEVEL	0x80000000
 
 #define PTRACE_EVENT_FORK	1
-- 
1.7.11.7



More information about the CRIU mailing list