[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