[CRIU] [PATCH] zdtm: check one-shot posix timers

Vladimir Davydov vdavydov at parallels.com
Tue May 14 12:59:19 EDT 2013


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)

>
>>>
>>>>
>>>> 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