mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 06:15:24 +00:00
zdtm: POSIX timers migration test
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@openvz.org> Acked-by: Vladimir Davydov <VDavydov@parallels.com> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
committed by
Pavel Emelyanov
parent
208292fd21
commit
74ee5df924
@@ -66,6 +66,7 @@ TST_NOFILE = \
|
||||
socket-ext \
|
||||
unhashed_proc \
|
||||
cow00 \
|
||||
posix_timers \
|
||||
# jobctl00 \
|
||||
|
||||
TST_FILE = \
|
||||
@@ -193,6 +194,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)
|
||||
|
220
test/zdtm/live/static/posix_timers.c
Normal file
220
test/zdtm/live/static/posix_timers.c
Normal file
@@ -0,0 +1,220 @@
|
||||
#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@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)
|
||||
{
|
||||
int overrun;
|
||||
|
||||
if (info != real) {
|
||||
real->handler_status |= WRONG_SI_PTR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig != info->sig)
|
||||
info->handler_status |= WRONG_SIGNAL;
|
||||
|
||||
overrun = timer_getoverrun(info->timerid);
|
||||
if (overrun == -1)
|
||||
info->handler_status |= FAIL_OVERRUN;
|
||||
else
|
||||
info->overrun += 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;
|
||||
}
|
Reference in New Issue
Block a user