[CRIU] [PATCH v2] zdtm: POSIX timers migration test
Kinsbursky Stanislav
skinsbursky at openvz.org
Thu Oct 11 07:44:43 EDT 2012
From: Stanislav Kinsbursky <skinsbursky at openvz.org>
This test set up two posix timers with different clocks: REALTIME and
MONOTONIC.
Both send signals.
Signals are disabled before suspend. This makes overrun counters increasing.
After restore tests enables signals, and make sure, that:
1) signal handler for both timers was called with proper arguments
2) time displacement for both timers is not greater than specified (10% by
default).
Signed-off-by: Stanislav Kinsbursky <skinsbursky at openvz.org>
---
test/zdtm/live/static/Makefile | 2
test/zdtm/live/static/posix_timers.c | 216 ++++++++++++++++++++++++++++++++++
2 files changed, 218 insertions(+), 0 deletions(-)
create mode 100644 test/zdtm/live/static/posix_timers.c
-------------- next part --------------
diff --git a/test/zdtm/live/static/Makefile b/test/zdtm/live/static/Makefile
index f23c4cd..2c5d352 100644
--- a/test/zdtm/live/static/Makefile
+++ b/test/zdtm/live/static/Makefile
@@ -64,6 +64,7 @@ TST_NOFILE = \
session01 \
socket-ext \
unhashed_proc \
+ posix_timers \
# jobctl00 \
TST_FILE = \
@@ -191,6 +192,7 @@ pthread00: override LDLIBS += -pthread
shm: override CFLAGS += -DNEW_IPC_NS
msgque: override CFLAGS += -DNEW_IPC_NS
sem: override CFLAGS += -DNEW_IPC_NS
+posix_timers: override LDLIBS += -lrt
$(LIB): force
$(MAKE) -C $(LIBDIR)
diff --git a/test/zdtm/live/static/posix_timers.c b/test/zdtm/live/static/posix_timers.c
new file mode 100644
index 0000000..f1dd94d
--- /dev/null
+++ b/test/zdtm/live/static/posix_timers.c
@@ -0,0 +1,216 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "zdtmtst.h"
+
+const char *test_doc ="Posix timers migration check";
+const char *test_author = "Kinsbursky Stanislav <skinsbursky at parallels.com>";
+
+struct timespec start;
+sigset_t mask;
+
+#define WRONG_SIGNAL 1
+#define WRONG_SI_PTR 2
+#define FAIL_OVERRUN 4
+
+#define MAX_TIMER_DISPLACEMENT 10
+
+static void realtime_handler(int sig, siginfo_t *si, void *uc);
+static void monotonic_handler(int sig, siginfo_t *si, void *uc);
+
+static struct posix_timers_info {
+ char clock;
+ char *name;
+ void (*handler)(int sig, siginfo_t *si, void *uc);
+ int sig;
+ int ms_int;
+ struct sigaction sa;
+ int handler_status;
+ int handler_cnt;
+ timer_t timerid;
+ int overrun;
+} posix_timers[] = {
+ [CLOCK_REALTIME] = {CLOCK_REALTIME, "REALTIME", realtime_handler, SIGALRM, 1},
+ [CLOCK_MONOTONIC] = {CLOCK_MONOTONIC, "MONOTONIC", monotonic_handler, SIGINT, 3},
+ { }
+};
+
+static int check_handler_status(struct posix_timers_info *info, int ms_passed)
+{
+ int displacement;
+ int timer_ms;
+
+ if (!info->handler_cnt) {
+ fail("%s: Signal handler wasn't called\n", info->name);
+ return -EINVAL;
+ }
+
+ if (info->handler_status) {
+ if (info->handler_status & WRONG_SIGNAL)
+ fail("%s: Handler: wrong signal received\n", info->name);
+ if (info->handler_status & WRONG_SI_PTR)
+ fail("%s: Handler: wrong timer address\n", info->name);
+ if (info->handler_status & FAIL_OVERRUN)
+ fail("%s: Handler: failed to get overrun count\n", info->name);
+ return -1;
+ }
+
+ if (info->overrun + info->handler_cnt > ms_passed) {
+ fail("%s: Overrun (%d) is greater than time passed (%d). "
+ "Timers problems?\n", info->name, info->overrun + info->handler_cnt,
+ ms_passed);
+ return -E2BIG;
+ }
+
+ timer_ms = (info->overrun + info->handler_cnt) * info->ms_int;
+ displacement = (ms_passed - timer_ms) * 100 / ms_passed;
+
+ if (displacement > MAX_TIMER_DISPLACEMENT) {
+ test_msg("%s: Time passed (ms) : %d msec\n", info->name, ms_passed);
+ test_msg("%s: Timer results : %d msec\n", info->name, timer_ms);
+ test_msg("%s: Handler count : %d\n", info->name, info->handler_cnt);
+ fail("%s: Time displacement: %d%% (max alloved: %d%%)\n", info->name, displacement, MAX_TIMER_DISPLACEMENT);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int check_timers(void)
+{
+ struct posix_timers_info *info = posix_timers;
+ struct timespec end;
+ int ms_passed;
+ int status = 0;
+
+ if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) {
+ fail("Failed to unlock signal\n");
+ return -errno;
+ }
+
+ if (clock_gettime(CLOCK_REALTIME, &end) == -1) {
+ fail("Can't get end time\n");
+ return -errno;
+ }
+
+ ms_passed = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / (1000 * 1000);
+
+ while (info->handler) {
+ if (timer_delete(info->timerid) == -1) {
+ fail("%s: Failed to delete timer\n", info->name);
+ return -errno;
+ }
+ if (check_handler_status(info, ms_passed))
+ status--;
+ info++;
+ }
+ return status;
+}
+
+static void generic_handler(struct posix_timers_info *info,
+ struct posix_timers_info *real, int sig)
+{
+ if (info != real) {
+ real->handler_status |= WRONG_SI_PTR;
+ return;
+ }
+
+ if (sig != info->sig)
+ info->handler_status |= WRONG_SIGNAL;
+
+ info->overrun += timer_getoverrun(info->timerid);
+ if (info->overrun == -1)
+ info->handler_status |= FAIL_OVERRUN;
+ info->handler_cnt++;
+}
+
+static void monotonic_handler(int sig, siginfo_t *si, void *uc)
+{
+ generic_handler(si->si_value.sival_ptr, &posix_timers[CLOCK_MONOTONIC], sig);
+}
+
+static void realtime_handler(int sig, siginfo_t *si, void *uc)
+{
+ generic_handler(si->si_value.sival_ptr, &posix_timers[CLOCK_REALTIME], sig);
+}
+
+static int setup_timers(void)
+{
+ struct posix_timers_info *info = posix_timers;
+ struct sigevent sev;
+ struct itimerspec its;
+
+ if (clock_gettime(CLOCK_REALTIME, &start) == -1) {
+ err("Can't get start time\n");
+ return -errno;
+ }
+
+ sigemptyset(&mask);
+ while(info->handler) {
+ sigaddset(&mask, info->sig);
+ info++;
+ }
+
+ if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) {
+ err("Failed to unlock signal\n");
+ return -errno;
+ }
+
+ info = posix_timers;
+ while(info->handler) {
+ info->sa.sa_flags = SA_SIGINFO;
+ info->sa.sa_sigaction = info->handler;
+ sigemptyset(&info->sa.sa_mask);
+
+ if (sigaction(info->sig, &info->sa, NULL) == -1) {
+ err("Failed to set SIGALRM handler\n");
+ return -errno;
+ }
+
+ sev.sigev_notify = SIGEV_SIGNAL;
+ sev.sigev_signo = info->sig;
+ sev.sigev_value.sival_ptr = info;
+
+ if (timer_create(info->clock, &sev, &info->timerid) == -1) {
+ err("Can't create timer\n");
+ return -errno;
+ }
+
+ its.it_value.tv_sec = 0;
+ its.it_value.tv_nsec = info->ms_int * 1000 * 1000;
+ its.it_interval.tv_sec = its.it_value.tv_sec;
+ its.it_interval.tv_nsec = its.it_value.tv_nsec;
+
+ if (timer_settime(info->timerid, 0, &its, NULL) == -1) {
+ err("Can't set timer\n");
+ return -errno;
+ }
+ info++;
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+
+ test_init(argc, argv);
+
+ err = setup_timers();
+ if (err)
+ return err;
+
+ usleep(500 * 1000);
+
+ test_daemon();
+ test_waitsig();
+
+ err = check_timers();
+ if (err)
+ return err;
+
+ pass();
+ return 0;
+}
More information about the CRIU
mailing list