[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