[CRIU] [PATCH] zdtm: check one-shot posix timers
Vladimir Davydov
vdavydov at parallels.com
Tue May 14 13:13:29 EDT 2013
On 5/14/13 9:05 PM, Pavel Emelyanov wrote:
> On 05/14/2013 08:59 PM, Vladimir Davydov wrote:
>> On 5/14/13 8:49 PM, Pavel Emelyanov wrote:
>>> On 05/14/2013 06:25 PM, Vladimir Davydov wrote:
>>>> On 5/14/13 6:19 PM, Andrew Vagin wrote:
>>>>> On Tue, May 14, 2013 at 05:41:22PM +0400, Vladimir Davydov wrote:
>>>>>>
>>>>>> With the patch zdtm will check not only periodic timers, but also
>>>>>> one-shot ones.
>>>>>
>>>>> How?
>>>>
>>>> Set one-shot timer to expire in a very long interval (INT_MAX in the
>>>> test), and check its remaining value after checkpoint/restore. The
>>>> following relationship must hold:
>>>>
>>>> initial_value - remaining_value = time_passed
>>>
>>> It will not be true, as dump/restore will spoil timings.
>>
>> Hmm... For calculating time passed we use corresponding clock -
>> monotonic or realtime - depending on the timer. If realtime clock is
>> synced between source and destination and CT's monotonic clock freezes
>> when CT is checkpointed, the relationship must hold provided the timer
>> is checkpointed/restored correctly.
>>
>> The test passes on OpenVZ.
>>
>> BTW, for periodic timers we use approx the same relationship and it
>> works fine:
>>
>> time_passed = timer_period * (expiration_count + overrun_count)
>
> I'd understand if it worked in "a - delta < b < a + delta" form, but
> exact match looks really wrong.
If delta stands for maximal error then the check works exactly as you
described - I just omitted it in the relationship for the sake of
simplicity. Here's the code:
// ms_passed - time passed according to clock_gettime
// timer_ms - time passed according to timer
displacement = abs(ms_passed - timer_ms) * 100 / ms_passed;
if (displacement > MAX_TIMER_DISPLACEMENT)
// print error
>
>>>
>>>>>
>>>>>>
>>>>>> Signed-off-by: Vladimir Davydov <vdavydov at parallels.com>
>>>>>> ---
>>>>>> test/zdtm/live/static/posix_timers.c | 108 ++++++++++++++++++++++++++++------
>>>>>> 1 files changed, 90 insertions(+), 18 deletions(-)
>>>>>>
>>>>>
>>>>>> diff --git a/test/zdtm/live/static/posix_timers.c b/test/zdtm/live/static/posix_timers.c
>>>>>> index 587a6be..ae9a882 100644
>>>>>> --- a/test/zdtm/live/static/posix_timers.c
>>>>>> +++ b/test/zdtm/live/static/posix_timers.c
>>>>>> @@ -3,6 +3,8 @@
>>>>>> #include <signal.h>
>>>>>> #include <time.h>
>>>>>> #include <sys/time.h>
>>>>>> +#include <limits.h>
>>>>>> +#include <string.h>
>>>>>>
>>>>>> #include "zdtmtst.h"
>>>>>>
>>>>>> @@ -17,14 +19,24 @@ sigset_t mask;
>>>>>>
>>>>>> #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 void realtime_periodic_handler(int sig, siginfo_t *si, void *uc);
>>>>>> +static void monotonic_periodic_handler(int sig, siginfo_t *si, void *uc);
>>>>>> +static void realtime_oneshot_handler(int sig, siginfo_t *si, void *uc);
>>>>>> +static void monotonic_oneshot_handler(int sig, siginfo_t *si, void *uc);
>>>>>> +
>>>>>> +enum {
>>>>>> + REALTIME_PERIODIC_INFO,
>>>>>> + MONOTONIC_PERIODIC_INFO,
>>>>>> + REALTIME_ONESHOT_INFO,
>>>>>> + MONOTONIC_ONESHOT_INFO,
>>>>>> +};
>>>>>>
>>>>>> static struct posix_timers_info {
>>>>>> char clock;
>>>>>> char *name;
>>>>>> void (*handler)(int sig, siginfo_t *si, void *uc);
>>>>>> int sig;
>>>>>> + int oneshot;
>>>>>> int ms_int;
>>>>>> struct sigaction sa;
>>>>>> int handler_status;
>>>>>> @@ -33,17 +45,24 @@ static struct posix_timers_info {
>>>>>> int overrun;
>>>>>> struct timespec start, end;
>>>>>> } posix_timers[] = {
>>>>>> - [CLOCK_REALTIME] = {CLOCK_REALTIME, "REALTIME", realtime_handler, SIGALRM, 1},
>>>>>> - [CLOCK_MONOTONIC] = {CLOCK_MONOTONIC, "MONOTONIC", monotonic_handler, SIGINT, 3},
>>>>>> + [REALTIME_PERIODIC_INFO] = {CLOCK_REALTIME, "REALTIME (periodic)",
>>>>>> + realtime_periodic_handler, SIGALRM, 0, 1},
>>>>>> + [MONOTONIC_PERIODIC_INFO] = {CLOCK_MONOTONIC, "MONOTONIC (periodic)",
>>>>>> + monotonic_periodic_handler, SIGINT, 0, 3},
>>>>>> + [REALTIME_ONESHOT_INFO] = {CLOCK_REALTIME, "REALTIME (oneshot)",
>>>>>> + realtime_oneshot_handler, SIGUSR1, 1, INT_MAX},
>>>>>> + [MONOTONIC_ONESHOT_INFO] = {CLOCK_MONOTONIC, "MONOTONIC (oneshot)",
>>>>>> + monotonic_oneshot_handler, SIGUSR2, 1, INT_MAX},
>>>>>> { }
>>>>>> };
>>>>>>
>>>>>> -static int check_handler_status(struct posix_timers_info *info, int ms_passed)
>>>>>> +static int check_handler_status(struct posix_timers_info *info,
>>>>>> + struct itimerspec *its, int ms_passed)
>>>>>> {
>>>>>> int displacement;
>>>>>> int timer_ms;
>>>>>>
>>>>>> - if (!info->handler_cnt) {
>>>>>> + if (!info->handler_cnt && !info->oneshot) {
>>>>>> fail("%s: Signal handler wasn't called\n", info->name);
>>>>>> return -EINVAL;
>>>>>> }
>>>>>> @@ -58,7 +77,41 @@ static int check_handler_status(struct posix_timers_info *info, int ms_passed)
>>>>>> return -1;
>>>>>> }
>>>>>>
>>>>>> - timer_ms = (info->overrun + info->handler_cnt) * info->ms_int;
>>>>>> + if (!info->oneshot && !its->it_value.tv_sec && !its->it_value.tv_nsec) {
>>>>>> + fail("%s: timer became unset\n", info->name);
>>>>>> + return -EFAULT;
>>>>>> + }
>>>>>> +
>>>>>> + if (info->oneshot && (its->it_interval.tv_sec || its->it_interval.tv_nsec)) {
>>>>>> + fail("%s: timer became periodic\n", info->name);
>>>>>> + return -EFAULT;
>>>>>> + }
>>>>>> +
>>>>>> + if (!info->oneshot && !its->it_interval.tv_sec && !its->it_interval.tv_nsec) {
>>>>>> + fail("%s: timer became oneshot\n", info->name);
>>>>>> + return -EFAULT;
>>>>>> + }
>>>>>> +
>>>>>> + if (info->oneshot) {
>>>>>> + int val = its->it_value.tv_sec * 1000 + its->it_value.tv_nsec / 1000 / 1000;
>>>>>> + if (info->handler_cnt) {
>>>>>> + if (val != 0) {
>>>>>> + fail("%s: timer continues ticking after expiration\n", info->name);
>>>>>> + return -EFAULT;
>>>>>> + }
>>>>>> + if (info->handler_cnt > 1) {
>>>>>> + fail("%s: timer expired %d times\n", info->name, info->handler_cnt);
>>>>>> + return -EFAULT;
>>>>>> + }
>>>>>> + if (info->ms_int > ms_passed) {
>>>>>> + fail("%s: timer expired too early\n", info->name);
>>>>>> + return -EFAULT;
>>>>>> + }
>>>>>> + return 0;
>>>>>> + }
>>>>>> + timer_ms = info->ms_int - val;
>>>>>> + } else
>>>>>> + timer_ms = (info->overrun + info->handler_cnt) * info->ms_int;
>>>>>> displacement = abs(ms_passed - timer_ms) * 100 / ms_passed;
>>>>>>
>>>>>> if (displacement > MAX_TIMER_DISPLACEMENT) {
>>>>>> @@ -76,6 +129,7 @@ static int check_timers(void)
>>>>>> struct posix_timers_info *info = posix_timers;
>>>>>> int ms_passed;
>>>>>> int status = 0;
>>>>>> + struct itimerspec val, oldval;
>>>>>>
>>>>>> if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) {
>>>>>> fail("Failed to unlock signal\n");
>>>>>> @@ -83,8 +137,9 @@ static int check_timers(void)
>>>>>> }
>>>>>>
>>>>>> while (info->handler) {
>>>>>> - if (timer_delete(info->timerid) == -1) {
>>>>>> - fail("%s: Failed to delete timer\n", info->name);
>>>>>> + memset(&val, 0, sizeof(val));
>>>>>> + if (timer_settime(info->timerid, 0, &val, &oldval) == -1) {
>>>>>> + fail("%s: failed to reset timer\n", info->name);
>>>>>> return -errno;
>>>>>> }
>>>>>>
>>>>>> @@ -96,7 +151,7 @@ static int check_timers(void)
>>>>>> ms_passed = (info->end.tv_sec - info->start.tv_sec) * 1000 +
>>>>>> (info->end.tv_nsec - info->start.tv_nsec) / (1000 * 1000);
>>>>>>
>>>>>> - if (check_handler_status(info, ms_passed))
>>>>>> + if (check_handler_status(info, &oldval, ms_passed))
>>>>>> status--;
>>>>>> info++;
>>>>>> }
>>>>>> @@ -124,14 +179,28 @@ static void generic_handler(struct posix_timers_info *info,
>>>>>> info->handler_cnt++;
>>>>>> }
>>>>>>
>>>>>> -static void monotonic_handler(int sig, siginfo_t *si, void *uc)
>>>>>> +static void monotonic_periodic_handler(int sig, siginfo_t *si, void *uc)
>>>>>> +{
>>>>>> + generic_handler(si->si_value.sival_ptr,
>>>>>> + &posix_timers[MONOTONIC_PERIODIC_INFO], sig);
>>>>>> +}
>>>>>> +
>>>>>> +static void monotonic_oneshot_handler(int sig, siginfo_t *si, void *uc)
>>>>>> +{
>>>>>> + generic_handler(si->si_value.sival_ptr,
>>>>>> + &posix_timers[MONOTONIC_ONESHOT_INFO], sig);
>>>>>> +}
>>>>>> +
>>>>>> +static void realtime_periodic_handler(int sig, siginfo_t *si, void *uc)
>>>>>> {
>>>>>> - generic_handler(si->si_value.sival_ptr, &posix_timers[CLOCK_MONOTONIC], sig);
>>>>>> + generic_handler(si->si_value.sival_ptr,
>>>>>> + &posix_timers[REALTIME_PERIODIC_INFO], sig);
>>>>>> }
>>>>>>
>>>>>> -static void realtime_handler(int sig, siginfo_t *si, void *uc)
>>>>>> +static void realtime_oneshot_handler(int sig, siginfo_t *si, void *uc)
>>>>>> {
>>>>>> - generic_handler(si->si_value.sival_ptr, &posix_timers[CLOCK_REALTIME], sig);
>>>>>> + generic_handler(si->si_value.sival_ptr,
>>>>>> + &posix_timers[REALTIME_ONESHOT_INFO], sig);
>>>>>> }
>>>>>>
>>>>>> static int setup_timers(void)
>>>>>> @@ -171,10 +240,13 @@ static int setup_timers(void)
>>>>>> 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;
>>>>>> + its.it_value.tv_sec = info->ms_int / 1000;
>>>>>> + its.it_value.tv_nsec = info->ms_int % 1000 * 1000 * 1000;
>>>>>> + if (!info->oneshot) {
>>>>>> + its.it_interval.tv_sec = its.it_value.tv_sec;
>>>>>> + its.it_interval.tv_nsec = its.it_value.tv_nsec;
>>>>>> + } else
>>>>>> + its.it_interval.tv_sec = its.it_interval.tv_nsec = 0;
>>>>>>
>>>>>> if (clock_gettime(info->clock, &info->start) == -1) {
>>>>>> err("Can't get %s start time\n", info->name);
>>>>>
>>>>>> _______________________________________________
>>>>>> CRIU mailing list
>>>>>> CRIU at openvz.org
>>>>>> https://lists.openvz.org/mailman/listinfo/criu
>>>>>
>>>>
>>>> .
>>>>
>>>
>>>
>>
>> .
>>
>
>
More information about the CRIU
mailing list