<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">2016-05-20 16:50 GMT+03:00 Pavel Emelyanov <span dir="ltr"><<a href="mailto:xemul@virtuozzo.com" target="_blank">xemul@virtuozzo.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">On 05/20/2016 04:31 PM, Batalov Eugene wrote:<br>
><br>
> 2016-05-20 16:12 GMT+03:00 Pavel Emelyanov <<a href="mailto:xemul@virtuozzo.com">xemul@virtuozzo.com</a> <mailto:<a href="mailto:xemul@virtuozzo.com">xemul@virtuozzo.com</a>>>:<br>
<span class="">><br>
> On 05/20/2016 02:31 PM, Batalov Eugene wrote:<br>
> ><br>
> ><br>
</span>> > 2016-05-20 14:23 GMT+03:00 Pavel Emelyanov <<a href="mailto:xemul@virtuozzo.com">xemul@virtuozzo.com</a> <mailto:<a href="mailto:xemul@virtuozzo.com">xemul@virtuozzo.com</a>> <mailto:<a href="mailto:xemul@virtuozzo.com">xemul@virtuozzo.com</a> <mailto:<a href="mailto:xemul@virtuozzo.com">xemul@virtuozzo.com</a>>>>:<br>
<span class="">> ><br>
> > On 05/02/2016 06:46 PM, Eugene Batalov wrote:<br>
</span>> > > From: Kravchenko Dmitrii <<a href="mailto:equivalence1@gmail.com">equivalence1@gmail.com</a> <mailto:<a href="mailto:equivalence1@gmail.com">equivalence1@gmail.com</a>> <mailto:<a href="mailto:equivalence1@gmail.com">equivalence1@gmail.com</a> <mailto:<a href="mailto:equivalence1@gmail.com">equivalence1@gmail.com</a>>>><br>
<span class="">> > ><br>
> > > This patch implements a simple autotest for new --leave-stopped CRIU<br>
> > > restorer option. Test creates ps tree then checkpoints it.<br>
> > > Then test restores ps tree with --leave-stopped option.<br>
> > > Then test checks that every process in restored ps tree is in<br>
> > > stopped state.<br>
> > ><br>
</span>> > > Signed-off-by: Kravchenko Dmitrii <<a href="mailto:equivalence1@gmail.com">equivalence1@gmail.com</a> <mailto:<a href="mailto:equivalence1@gmail.com">equivalence1@gmail.com</a>> <mailto:<a href="mailto:equivalence1@gmail.com">equivalence1@gmail.com</a> <mailto:<a href="mailto:equivalence1@gmail.com">equivalence1@gmail.com</a>>>><br>
> > > Signed-off-by: Eugene Batalov <<a href="mailto:eabatalov89@gmail.com">eabatalov89@gmail.com</a> <mailto:<a href="mailto:eabatalov89@gmail.com">eabatalov89@gmail.com</a>> <mailto:<a href="mailto:eabatalov89@gmail.com">eabatalov89@gmail.com</a> <mailto:<a href="mailto:eabatalov89@gmail.com">eabatalov89@gmail.com</a>>>><br>
<span class="">> > > ---<br>
> > > test/others/leave-stopped/.gitignore | 3 ++<br>
> > > test/others/leave-stopped/Makefile | 7 +++++<br>
> > > test/others/leave-stopped/pstree.c | 39 +++++++++++++++++++++++++<br>
> > > test/others/leave-stopped/run.sh | 31 ++++++++++++++++++++<br>
> > > test/others/leave-stopped/tree_checker.py | 47 +++++++++++++++++++++++++++++++<br>
> ><br>
> > Oh :( Is there any chance to have this as a part of zdtm.py suite?<br>
> ><br>
> ><br>
> > We need to restore the whole ps tree in stopped state so ps tree can't validate itself after restore.<br>
><br>
> Of course. This should be a mode when zdtm.py passes --leave-stopped to criu restore (and<br>
> criu dump actually too :) ) and before checking the results SIGCONTs the tree.<br>
><br>
> We should check state of all the restored processes in ps tree before we SIGCONT them.<br>
> Please read my comment below for continuation of my point.<br>
><br>
><br>
><br>
> > 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.<br>
> > But we haven't found such a file.<br>
> > Do you have such a shell script? Should we implement such a file?<br>
><br>
> Nope :( But this can be solved by calling "crit x ps" -- it will show all the pids<br>
> from the image file.<br>
><br>
> In our test we traverse restored ps tree from root to children and check each process state to be stopped.<br>
> So I don't see a big need to use additional component such as crit in our test (but crit ps based check is more strict).<br>
><br>
> The question is how would we integrate our test/others/leave-stopped script into zdtm test suite?<br>
<br>
</span>I thought that you don't :) Instead, you can take the zdtm/transition/fork test, C/R it<br>
with --leave-stopped, check that it is stopped, SIGCONT the tree and check the result.<br>
<br>
The same can be done with any zdtm/ micro-test, but presumably it only makes sense to<br>
regularly test only the fork one.</blockquote><div>So will we need some special logic in zdtm.py for running and sigcont of zdtm/transition/fork test with --leave-stopped flag?</div><div>If yes, do you have a similar test with special running logic in zdtm.py already?</div><div><br></div><div>Also is this really needed to use zdtm/transition/fork and integrate special logic into zdtm.py?</div><div>Is there a big deal in it? :) Because it doesn't look like a problem for me but it would take some extra time.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"> </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class=""><div class="h5"><br>
> The cleanest way is to just call our test script from zdtm and let our test script do all the work.<br>
> I mean it looks like there is no need to add more code into zdtm.py.<br>
> It is complicated thing already so I prefer not to add more functionality inside it (we have another<br>
> isolated test and can just run it from zdtm.py).<br>
><br>
><br>
><br>
> ><br>
> ><br>
> > > 5 files changed, 127 insertions(+)<br>
> > > create mode 100644 test/others/leave-stopped/.gitignore<br>
> > > create mode 100644 test/others/leave-stopped/Makefile<br>
> > > create mode 100644 test/others/leave-stopped/pstree.c<br>
> > > create mode 100755 test/others/leave-stopped/run.sh<br>
> > > create mode 100755 test/others/leave-stopped/tree_checker.py<br>
> > ><br>
> > > diff --git a/test/others/leave-stopped/.gitignore b/test/others/leave-stopped/.gitignore<br>
> > > new file mode 100644<br>
> > > index 0000000..f0f7d9e<br>
> > > --- /dev/null<br>
> > > +++ b/test/others/leave-stopped/.gitignore<br>
> > > @@ -0,0 +1,3 @@<br>
> > > +dump/*<br>
> > > +nohup.out<br>
> > > +pstree<br>
> > > diff --git a/test/others/leave-stopped/Makefile b/test/others/leave-stopped/Makefile<br>
> > > new file mode 100644<br>
> > > index 0000000..83e91cc<br>
> > > --- /dev/null<br>
> > > +++ b/test/others/leave-stopped/Makefile<br>
> > > @@ -0,0 +1,7 @@<br>
> > > +pstree: pstree.c<br>
> > > + gcc -pthread -std=c99 $< -o $@<br>
> > > +<br>
> > > +clean:<br>
> > > + rm -f pstree<br>
> > > +<br>
> > > +.PHONY: clean<br>
> > > diff --git a/test/others/leave-stopped/pstree.c b/test/others/leave-stopped/pstree.c<br>
> > > new file mode 100644<br>
> > > index 0000000..a6e437c<br>
> > > --- /dev/null<br>
> > > +++ b/test/others/leave-stopped/pstree.c<br>
> > > @@ -0,0 +1,39 @@<br>
> > > +#include <stdlib.h><br>
> > > +#include <unistd.h><br>
> > > +#include <limits.h><br>
> > > +#include <pthread.h><br>
> > > +<br>
> > > +const size_t THREADS_N = 3;<br>
> > > +const size_t TREE_HEIGHT = 3;<br>
> > > +<br>
> > > +static void *hang(void *arg)<br>
> > > +{<br>
> > > + (void)arg;<br>
> > > + while (1)<br>
> > > + sleep(UINT_MAX);<br>
> > > +}<br>
> > > +<br>
> > > +static void create_threads(void)<br>
> > > +{<br>
> > > + pthread_t thread;<br>
> > > +<br>
> > > + for (size_t i = 1; i < THREADS_N; i++)<br>
> > > + pthread_create(&thread, NULL, hang, NULL);<br>
> > > +}<br>
> > > +<br>
> > > +int main(void)<br>
> > > +{<br>
> > > + /**<br>
> > > + * just building full binary tree of processes<br>
> > > + */<br>
> > > + for (size_t i = 1; i < TREE_HEIGHT; i++) {<br>
> > > + if (fork()) {<br>
> > > + if (fork())<br>
> > > + break;<br>
> > > + }<br>
> > > + }<br>
> > > +<br>
> > > + create_threads();<br>
> > > +<br>
> > > + hang(NULL);<br>
> > > +}<br>
> > > diff --git a/test/others/leave-stopped/run.sh b/test/others/leave-stopped/run.sh<br>
> > > new file mode 100755<br>
> > > index 0000000..d2f2ec6<br>
> > > --- /dev/null<br>
> > > +++ b/test/others/leave-stopped/run.sh<br>
> > > @@ -0,0 +1,31 @@<br>
> > > +#!/bin/bash<br>
> > > +<br>
> > > +source ../env.sh || exit 1<br>
> > > +<br>
> > > +make || { echo "Failed to build"; exit 1; }<br>
> > > +<br>
> > > +DDIR="dump"<br>
> > > +<br>
> > > +rm -f nohup.out<br>
> > > +rm -rf ${DDIR}<br>
> > > +<br>
> > > +mkdir ${DDIR}<br>
> > > +<br>
> > > +setsid nohup ./pstree &<br>
> > > +root_pid=$!<br>
> > > +<br>
> > > +${CRIU} dump -D ${DDIR} -t ${root_pid} || \<br>
> > > + { echo "Failed to dump"; kill -9 -${root_pid}; exit 1; }<br>
> > > +${CRIU} restore -D ${DDIR} --leave-stopped -d || \<br>
> > > + { echo "Failed to restore"; exit 1; }<br>
> > > +<br>
> > > +./tree_checker.py ${root_pid}<br>
> > > +<br>
> > > +if [ $? -eq 0 ]; then<br>
> > > + echo "PASS"<br>
> > > + kill -9 -${root_pid}<br>
> > > +else<br>
> > > + echo "FAIL"<br>
> > > + kill -9 -${root_pid}<br>
> > > + exit 1<br>
> > > +fi<br>
> > > diff --git a/test/others/leave-stopped/tree_checker.py b/test/others/leave-stopped/tree_checker.py<br>
> > > new file mode 100755<br>
> > > index 0000000..87d45e2<br>
> > > --- /dev/null<br>
> > > +++ b/test/others/leave-stopped/tree_checker.py<br>
> > > @@ -0,0 +1,47 @@<br>
> > > +#!/usr/bin/python2<br>
> > > +<br>
> > > +import os<br>
> > > +import sys<br>
> > > +<br>
> > > +<br>
> > > +def get_thread_status(thread_dir):<br>
> > > + for line in open(os.path.join(thread_dir, "status")).readlines():<br>
> > > + if line.startswith("State:"):<br>
> > > + return line.split(":", 1)[1].strip().split(' ')[0]<br>
> > > + return None<br>
> > > +<br>
> > > +<br>
> > > +def is_process_stopped(pid):<br>
> > > + tasks_dir = "/proc/{}/task".format(pid)<br>
> > > +<br>
> > > + for thread_dir in os.listdir(tasks_dir):<br>
> > > + thread_status = get_thread_status(os.path.join(tasks_dir, thread_dir))<br>
> > > + if not thread_status == "T":<br>
> > > + return False<br>
> > > +<br>
> > > + thread_status = get_thread_status("/proc/{}".format(pid))<br>
> > > + if not thread_status == "T":<br>
> > > + return False<br>
> > > +<br>
> > > + return True<br>
> > > +<br>
> > > +<br>
> > > +def check_tree(root_pid):<br>
> > > + if not is_process_stopped(root_pid):<br>
> > > + print "Process with pid {} is not stopped.".format(root_pid)<br>
> > > + return False<br>
> > > +<br>
> > > + f_children_path = "/proc/{0}/task/{0}/children".format(root_pid)<br>
> > > +<br>
> > > + with open(f_children_path, "r") as f_children:<br>
> > > + for line in f_children:<br>
> > > + for child_pid in line.strip().split(" "):<br>
> > > + if not check_tree(int(child_pid)):<br>
> > > + return False<br>
> > > +<br>
> > > + return True<br>
> > > +<br>
> > > +<br>
> > > +if __name__ == "__main__":<br>
> > > + if not check_tree(sys.argv[1]):<br>
> > > + sys.exit(1)<br>
> > ><br>
> ><br>
> ><br>
> ><br>
> ><br>
> > --<br>
> > Best regards,<br>
> > Eugene Batalov.<br>
><br>
><br>
><br>
><br>
> --<br>
> Best regards,<br>
> Eugene Batalov.<br>
<br>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature">Best regards,<br>Eugene Batalov.</div>
</div></div>