[CRIU] Re: [RFC] zdtm: Add task waiters

Cyrill Gorcunov gorcunov at openvz.org
Fri Jun 1 04:30:28 EDT 2012


On Thu, May 31, 2012 at 07:01:27PM +0400, Cyrill Gorcunov wrote:
> In some test cases I need to make sure the parent process has
> reached some point before child to continue. This patch adds
> sync points (based on Pavel's idea syncing via pipes blocking
> i/o).
> 
> Take a look please.

An updated version ;)

	Cyrill
-------------- next part --------------
>From 7edb2e6a4d6cb1d615c31abd42e8cb9debd8f019 Mon Sep 17 00:00:00 2001
From: Cyrill Gorcunov <gorcunov at openvz.org>
Date: Fri, 1 Jun 2012 12:29:41 +0400
Subject: [PATCH] zdtm: Add task_waiter_ helpers v2

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

The call semantics is the following

a) The fork() is used so both parent and child do not
   share memory referenced by task waiter. Thus the calling
   sequence should be

        Parent                  Child
        ------                  -----
        task_waiter_init
                                task_waiter_wait
        task_waiter_complete
        task_waiter_update
                                task_waiter_wait
        task_waiter_complete
        task_waiter_update

                ...

b) If shared memory is used then no need to call
   for task_waiter_update.

Still it's not well designed for use with more than
two processes, since contention resolving might simply
kill process to break a tie.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 test/zdtm/lib/Makefile  |    2 +-
 test/zdtm/lib/lock.c    |   81 +++++++++++++++++++++++++++++++++++++++++++++++
 test/zdtm/lib/zdtmtst.h |   12 +++++++
 3 files changed, 94 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..1959fc8
--- /dev/null
+++ b/test/zdtm/lib/lock.c
@@ -0,0 +1,81 @@
+#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
+
+void task_waiter_init(task_waiter_t *t)
+{
+	t->raw = 1;
+	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_wait(task_waiter_t *t)
+{
+	struct timespec req = { .tv_nsec = TASK_WAITER_INITIAL, };
+	struct timespec rem = { };
+	int v, attempts = 5;
+
+	for (;;) {
+		if (!attempts--) {
+			errno = EAGAIN;
+			goto err;
+		}
+		if (read(t->pipes[0], &v, sizeof(v)) !=  sizeof(v))
+			goto err;
+		if (v != t->raw + 1) {
+			if (write(t->pipes[1], &v, sizeof(v)) !=  sizeof(v))
+				goto err;
+			nanosleep(&req, &rem);
+			req.tv_nsec += t->seed;
+		} else {
+			t->raw++;
+			break;
+		}
+	}
+
+	return;
+
+err:
+	err("task_waiter_wait failed: %m");
+	exit(errno);
+}
+
+void task_waiter_complete(task_waiter_t *t)
+{
+	int v = t->raw + 1;
+	if (write(t->pipes[1], &v, sizeof(v)) !=  sizeof(v)) {
+		err("task_waiter_complete failed: %m");
+		exit(1);
+	}
+}
+
+/*
+ * If waiter and watee do not share memory to task_waiter_t (ie
+ * the fork() was used), then once task_waiter_complete called
+ * the task_waiter_update should be invoked as well.
+ */
+void task_waiter_update(task_waiter_t *t)
+{
+	t->raw++;
+}
diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h
index 6ef7804..2a77a21 100644
--- a/test/zdtm/lib/zdtmtst.h
+++ b/test/zdtm/lib/zdtmtst.h
@@ -89,4 +89,16 @@ extern int parse_opt_string(char *param, void *arg);
 		 __FILE__, __LINE__, ## arg)
 #define pass()	test_msg("PASS\n")
 
+typedef struct {
+	unsigned int	raw;
+	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_wait(task_waiter_t *t);
+extern void task_waiter_complete(task_waiter_t *t);
+extern void task_waiter_update(task_waiter_t *t);
+
 #endif /* _VIMITESU_H_ */
-- 
1.7.7.6



More information about the CRIU mailing list