[CRIU] [PATCH 1/2] zdtm: Add task_waiter_ helpers v3

Cyrill Gorcunov gorcunov at openvz.org
Tue Jun 19 11:05:30 EDT 2012


Sometime we need sync points in testee program flow,
for this reason task_waiter_ introduced.

The call semantics is the following

        Parent                  Child
        ------                  -----
        task_waiter_init
                                task_waiter_wait4
        task_waiter_complete
                                task_waiter_wait4
        task_waiter_complete

                ...

Thus initially task_waiter_init should be called
to initialize all internals guts needed.

Then one become waitee and calls for task_waiter_wait4,
where lockid should be provided as an argument. Since
it should be unique values the best option might be
gettid().

The same applies to a waiter side -- it should call
for task_waiter_complete and provide a lockid.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 test/zdtm/lib/Makefile  |    2 +-
 test/zdtm/lib/lock.c    |   94 +++++++++++++++++++++++++++++++++++++++++++++++
 test/zdtm/lib/zdtmtst.h |   11 +++++
 3 files changed, 106 insertions(+), 1 deletions(-)
 create mode 100644 test/zdtm/lib/lock.c

diff --git a/test/zdtm/lib/Makefile b/test/zdtm/lib/Makefile
index a4ab681..f09e71f 100644
--- a/test/zdtm/lib/Makefile
+++ b/test/zdtm/lib/Makefile
@@ -2,7 +2,7 @@ CFLAGS	= -g -O2 -Wall -Werror -Wno-unused-result
 
 LIB	= libzdtmtst.a
 
-LIBSRC	= datagen.c msg.c parseargs.c test.c streamutil.c
+LIBSRC	= datagen.c msg.c parseargs.c test.c streamutil.c lock.c
 LIBOBJ	= $(LIBSRC:%.c=%.o)
 LIBDEP	= $(LIBSRC:%.c=%.d)
 
diff --git a/test/zdtm/lib/lock.c b/test/zdtm/lib/lock.c
new file mode 100644
index 0000000..7f8f522
--- /dev/null
+++ b/test/zdtm/lib/lock.c
@@ -0,0 +1,94 @@
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "zdtmtst.h"
+
+#define TASK_WAITER_INITIAL		0x0fffff
+
+static long sys_gettid(void)
+{
+	long ret;
+
+	asm volatile("movl $186, %%eax	\n"
+		     "syscall		\n"
+		     "movq %%rax, %0	\n"
+		     : "=r"(ret)
+		     :
+		     : "rax", "memory");
+	return ret;
+}
+
+void task_waiter_init(task_waiter_t *t)
+{
+	datagen((void *)&t->seed, sizeof(t->seed), NULL);
+	t->seed = t->seed % TASK_WAITER_INITIAL;
+
+	if (pipe(t->pipes)) {
+		err("task_waiter_init failed: %m");
+		exit(1);
+	}
+}
+
+void task_waiter_fini(task_waiter_t *t)
+{
+	close(t->pipes[0]);
+	close(t->pipes[1]);
+}
+
+void task_waiter_wait4(task_waiter_t *t, unsigned int lockid)
+{
+	struct timespec req = { .tv_nsec = TASK_WAITER_INITIAL, };
+	struct timespec rem = { };
+	unsigned int v;
+
+	for (;;) {
+		if (read(t->pipes[0], &v, sizeof(v)) != sizeof(v))
+			goto err;
+
+		/*
+		 * If we read a value not intended for us, say parent
+		 * waits for specified child to complete among set of
+		 * children, or we just have completed and wait for
+		 * another lockid from a parent -- we need to write
+		 * the value back and wait for some time before
+		 * next attempt.
+		 */
+		if (v != lockid) {
+			if (write(t->pipes[1], &v, sizeof(v)) != sizeof(v))
+				goto err;
+			/*
+			 * If we get a collision in access, lets sleep
+			 * semi-random time magnitude to decrease probability
+			 * of a new collision.
+			 */
+			nanosleep(&req, &rem);
+			req.tv_nsec += t->seed;
+		} else
+			break;
+	}
+
+	return;
+
+err:
+	err("task_waiter_wait4 failed: %m");
+	exit(errno);
+}
+
+void task_waiter_complete(task_waiter_t *t, unsigned int lockid)
+{
+	if (write(t->pipes[1], &lockid, sizeof(lockid)) != sizeof(lockid)) {
+		err("task_waiter_complete failed: %m");
+		exit(1);
+	}
+}
+
+void task_waiter_complete_current(task_waiter_t *t)
+{
+	return task_waiter_complete(t, (int)sys_gettid());
+}
diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h
index 6ef7804..1f12d41 100644
--- a/test/zdtm/lib/zdtmtst.h
+++ b/test/zdtm/lib/zdtmtst.h
@@ -89,4 +89,15 @@ extern int parse_opt_string(char *param, void *arg);
 		 __FILE__, __LINE__, ## arg)
 #define pass()	test_msg("PASS\n")
 
+typedef struct {
+	unsigned long	seed;
+	int		pipes[2];
+} task_waiter_t;
+
+extern void task_waiter_init(task_waiter_t *t);
+extern void task_waiter_fini(task_waiter_t *t);
+extern void task_waiter_wait4(task_waiter_t *t, unsigned int lockid);
+extern void task_waiter_complete(task_waiter_t *t, unsigned int lockid);
+extern void task_waiter_complete_current(task_waiter_t *t);
+
 #endif /* _VIMITESU_H_ */
-- 
1.7.7.6



More information about the CRIU mailing list