[CRIU] [PATCHv2 2/2] test/others/leave-stopped: implement test for new --leave-stopped option

Pavel Emelyanov xemul at virtuozzo.com
Fri May 20 06:12:58 PDT 2016


On 05/20/2016 02:31 PM, Batalov Eugene wrote:
> 
> 
> 2016-05-20 14:23 GMT+03:00 Pavel Emelyanov <xemul at virtuozzo.com <mailto:xemul at virtuozzo.com>>:
> 
>     On 05/02/2016 06:46 PM, Eugene Batalov wrote:
>     > From: Kravchenko Dmitrii <equivalence1 at gmail.com <mailto:equivalence1 at gmail.com>>
>     >
>     > This patch implements a simple autotest for new --leave-stopped CRIU
>     > restorer option. Test creates ps tree then checkpoints it.
>     > Then test restores ps tree with --leave-stopped option.
>     > Then test checks that every process in restored ps tree is in
>     > stopped state.
>     >
>     > Signed-off-by: Kravchenko Dmitrii <equivalence1 at gmail.com <mailto:equivalence1 at gmail.com>>
>     > Signed-off-by: Eugene Batalov <eabatalov89 at gmail.com <mailto:eabatalov89 at gmail.com>>
>     > ---
>     >  test/others/leave-stopped/.gitignore      |  3 ++
>     >  test/others/leave-stopped/Makefile        |  7 +++++
>     >  test/others/leave-stopped/pstree.c        | 39 +++++++++++++++++++++++++
>     >  test/others/leave-stopped/run.sh          | 31 ++++++++++++++++++++
>     >  test/others/leave-stopped/tree_checker.py | 47 +++++++++++++++++++++++++++++++
> 
>     Oh :( Is there any chance to have this as a part of zdtm.py suite?
> 
> 
> We need to restore the whole ps tree in stopped state so ps tree can't validate itself after restore.

Of course. This should be a mode when zdtm.py passes --leave-stopped to criu restore (and
criu dump actually too :) ) and before checking the results SIGCONTs the tree.

> I think there should be some file in CRIU test suite where we can add new shell command to run our non-zdtm style test.
> But we haven't found such a file.
> Do you have such a shell script? Should we implement such a file?

Nope :( But this can be solved by calling "crit x ps" -- it will show all the pids
from the image file.

> 
> 
>     >  5 files changed, 127 insertions(+)
>     >  create mode 100644 test/others/leave-stopped/.gitignore
>     >  create mode 100644 test/others/leave-stopped/Makefile
>     >  create mode 100644 test/others/leave-stopped/pstree.c
>     >  create mode 100755 test/others/leave-stopped/run.sh
>     >  create mode 100755 test/others/leave-stopped/tree_checker.py
>     >
>     > diff --git a/test/others/leave-stopped/.gitignore b/test/others/leave-stopped/.gitignore
>     > new file mode 100644
>     > index 0000000..f0f7d9e
>     > --- /dev/null
>     > +++ b/test/others/leave-stopped/.gitignore
>     > @@ -0,0 +1,3 @@
>     > +dump/*
>     > +nohup.out
>     > +pstree
>     > diff --git a/test/others/leave-stopped/Makefile b/test/others/leave-stopped/Makefile
>     > new file mode 100644
>     > index 0000000..83e91cc
>     > --- /dev/null
>     > +++ b/test/others/leave-stopped/Makefile
>     > @@ -0,0 +1,7 @@
>     > +pstree: pstree.c
>     > +     gcc -pthread -std=c99 $< -o $@
>     > +
>     > +clean:
>     > +     rm -f pstree
>     > +
>     > +.PHONY: clean
>     > diff --git a/test/others/leave-stopped/pstree.c b/test/others/leave-stopped/pstree.c
>     > new file mode 100644
>     > index 0000000..a6e437c
>     > --- /dev/null
>     > +++ b/test/others/leave-stopped/pstree.c
>     > @@ -0,0 +1,39 @@
>     > +#include <stdlib.h>
>     > +#include <unistd.h>
>     > +#include <limits.h>
>     > +#include <pthread.h>
>     > +
>     > +const size_t THREADS_N = 3;
>     > +const size_t TREE_HEIGHT = 3;
>     > +
>     > +static void *hang(void *arg)
>     > +{
>     > +     (void)arg;
>     > +     while (1)
>     > +             sleep(UINT_MAX);
>     > +}
>     > +
>     > +static void create_threads(void)
>     > +{
>     > +     pthread_t thread;
>     > +
>     > +     for (size_t i = 1; i < THREADS_N; i++)
>     > +             pthread_create(&thread, NULL, hang, NULL);
>     > +}
>     > +
>     > +int main(void)
>     > +{
>     > +     /**
>     > +      * just building full binary tree of processes
>     > +      */
>     > +     for (size_t i = 1; i < TREE_HEIGHT; i++) {
>     > +             if (fork()) {
>     > +                     if (fork())
>     > +                             break;
>     > +             }
>     > +     }
>     > +
>     > +     create_threads();
>     > +
>     > +     hang(NULL);
>     > +}
>     > diff --git a/test/others/leave-stopped/run.sh b/test/others/leave-stopped/run.sh
>     > new file mode 100755
>     > index 0000000..d2f2ec6
>     > --- /dev/null
>     > +++ b/test/others/leave-stopped/run.sh
>     > @@ -0,0 +1,31 @@
>     > +#!/bin/bash
>     > +
>     > +source ../env.sh || exit 1
>     > +
>     > +make || { echo "Failed to build"; exit 1; }
>     > +
>     > +DDIR="dump"
>     > +
>     > +rm -f nohup.out
>     > +rm -rf ${DDIR}
>     > +
>     > +mkdir ${DDIR}
>     > +
>     > +setsid nohup ./pstree &
>     > +root_pid=$!
>     > +
>     > +${CRIU} dump -D ${DDIR} -t ${root_pid} || \
>     > +     { echo "Failed to dump"; kill -9 -${root_pid}; exit 1; }
>     > +${CRIU} restore -D ${DDIR} --leave-stopped -d || \
>     > +     { echo "Failed to restore"; exit 1; }
>     > +
>     > +./tree_checker.py ${root_pid}
>     > +
>     > +if [ $? -eq 0 ]; then
>     > +     echo "PASS"
>     > +     kill -9 -${root_pid}
>     > +else
>     > +     echo "FAIL"
>     > +     kill -9 -${root_pid}
>     > +     exit 1
>     > +fi
>     > diff --git a/test/others/leave-stopped/tree_checker.py b/test/others/leave-stopped/tree_checker.py
>     > new file mode 100755
>     > index 0000000..87d45e2
>     > --- /dev/null
>     > +++ b/test/others/leave-stopped/tree_checker.py
>     > @@ -0,0 +1,47 @@
>     > +#!/usr/bin/python2
>     > +
>     > +import os
>     > +import sys
>     > +
>     > +
>     > +def get_thread_status(thread_dir):
>     > +     for line in open(os.path.join(thread_dir, "status")).readlines():
>     > +             if line.startswith("State:"):
>     > +                     return line.split(":", 1)[1].strip().split(' ')[0]
>     > +     return None
>     > +
>     > +
>     > +def is_process_stopped(pid):
>     > +     tasks_dir = "/proc/{}/task".format(pid)
>     > +
>     > +     for thread_dir in os.listdir(tasks_dir):
>     > +             thread_status = get_thread_status(os.path.join(tasks_dir, thread_dir))
>     > +             if not thread_status == "T":
>     > +                     return False
>     > +
>     > +     thread_status = get_thread_status("/proc/{}".format(pid))
>     > +     if not thread_status == "T":
>     > +             return False
>     > +
>     > +     return True
>     > +
>     > +
>     > +def check_tree(root_pid):
>     > +     if not is_process_stopped(root_pid):
>     > +             print "Process with pid {} is not stopped.".format(root_pid)
>     > +             return False
>     > +
>     > +     f_children_path = "/proc/{0}/task/{0}/children".format(root_pid)
>     > +
>     > +     with open(f_children_path, "r") as f_children:
>     > +             for line in f_children:
>     > +                     for child_pid in line.strip().split(" "):
>     > +                             if not check_tree(int(child_pid)):
>     > +                                     return False
>     > +
>     > +     return True
>     > +
>     > +
>     > +if __name__ == "__main__":
>     > +     if not check_tree(sys.argv[1]):
>     > +             sys.exit(1)
>     >
> 
> 
> 
> 
> -- 
> Best regards,
> Eugene Batalov.



More information about the CRIU mailing list