[CRIU] [PATCH v1] zdtm: implement testing of --leave-stopped criu option

Eugene Batalov eabatalov89 at gmail.com
Fri Aug 12 07:49:10 PDT 2016


Test does its checking both after dump and after restore.
Checking is done in the following way:
1. Check that every ps tree process is stopped or dead
2a. SIGKILL every ps tree process if checking after dump
2b. SIGCONT every ps tree process if checking after restore

Signed-off-by: Eugene Batalov <eabatalov89 at gmail.com>
---
 test/zdtm.py                   | 72 ++++++++++++++++++++++++++++++++++++++++++
 test/zdtm/transition/fork.desc |  1 +
 2 files changed, 73 insertions(+)
 create mode 100644 test/zdtm/transition/fork.desc

diff --git a/test/zdtm.py b/test/zdtm.py
index d5e91d2..d970d8c 100755
--- a/test/zdtm.py
+++ b/test/zdtm.py
@@ -751,6 +751,9 @@ class criu_cli:
 			else:
 				raise test_fail_exc("CRIU %s" % action)
 
+		if '--leave-stopped' in s_args:
+			pstree_check_stopped(self.__test.getpid())
+
 	def dump(self, action, opts = []):
 		self.__iter += 1
 		os.mkdir(self.__ddir())
@@ -788,6 +791,9 @@ class criu_cli:
 		if self.__page_server:
 			wait_pid_die(int(rpidfile(self.__ddir() + "/ps.pid")), "page server")
 
+		if '--leave-stopped' in a_opts:
+			pstree_signal(self.__test.getpid(), signal.SIGKILL)
+
 	def restore(self):
 		r_opts = []
 		if self.__restore_sibling:
@@ -818,6 +824,9 @@ class criu_cli:
 		if lazy_pages_p and lazy_pages_p.wait():
 			raise test_fail_exc("CRIU lazy-pages")
 
+		if '--leave-stopped' in r_opts:
+			pstree_signal(self.__test.getpid(), signal.SIGCONT)
+
 	@staticmethod
 	def check(feature):
 		return criu_cli.__criu("check", ["-v0", "--feature", feature]) == 0
@@ -1063,6 +1072,69 @@ def check_unshare_state(t):
 	cmp_ns("/proc/%s/ns/net" % t.getpid(), '!=', "/proc/self/ns/net", "unshare net")
 
 
+def pstree_each_pid(root_pid):
+	f_children_path = "/proc/{0}/task/{0}/children".format(root_pid)
+	child_pids = []
+	try:
+		with open(f_children_path, "r") as f_children:
+			pid_line = f_children.readline().strip(" \n")
+			if pid_line:
+				child_pids += pid_line.split(" ")
+	except:
+		return  # process is dead
+
+	yield root_pid
+	for child_pid in child_pids:
+		for pid in pstree_each_pid(child_pid):
+			yield pid
+
+
+def is_proc_stopped(pid):
+	def get_thread_status(thread_dir):
+		try:
+			with open(os.path.join(thread_dir, "status")) as f_status:
+				for line in f_status.readlines():
+					if line.startswith("State:"):
+						return line.split(":", 1)[1].strip().split(" ")[0]
+		except:
+			pass  # process is dead
+		return None
+
+	def is_thread_stopped(status):
+		return (status is None) or (status == "T") or (status == "Z")
+
+	tasks_dir = "/proc/%s/task" % pid
+	thread_dirs = []
+	try:
+		thread_dirs = os.listdir(tasks_dir)
+	except:
+		pass  # process is dead
+
+	for thread_dir in thread_dirs:
+		thread_status = get_thread_status(os.path.join(tasks_dir, thread_dir))
+		if not is_thread_stopped(thread_status):
+			return False
+
+	if not is_thread_stopped(get_thread_status("/proc/%s" % pid)):
+		return False
+
+	return True
+
+
+def pstree_check_stopped(root_pid):
+	for pid in pstree_each_pid(root_pid):
+		if not is_proc_stopped(pid):
+			raise test_fail_exc("CRIU --leave-stopped %s" % pid)
+
+
+def pstree_signal(root_pid, signal):
+	for pid in pstree_each_pid(root_pid):
+		try:
+			os.kill(int(pid), signal)
+		except:
+			pass  # process is dead
+
+
 def do_run_test(tname, tdesc, flavs, opts):
 	tcname = tname.split('/')[0]
 	tclass = test_classes.get(tcname, None)
diff --git a/test/zdtm/transition/fork.desc b/test/zdtm/transition/fork.desc
new file mode 100644
index 0000000..843347e
--- /dev/null
+++ b/test/zdtm/transition/fork.desc
@@ -0,0 +1 @@
+{'opts': '--leave-stopped'}
-- 
1.9.1



More information about the CRIU mailing list