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

Pavel Emelyanov xemul at parallels.com
Tue May 14 13:05:27 EDT 2013


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.

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