This patch adds support for real/virt/prof itimers. Expiry and the interval values are both saved in nanoseconds. Signed-off-by: Oren Laadan <orenl@xxxxxxxxxxxxxxx> --- checkpoint/signal.c | 72 ++++++++++++++++++++++++++++++++++++++++ include/linux/checkpoint_hdr.h | 6 +++ 2 files changed, 78 insertions(+), 0 deletions(-) diff --git a/checkpoint/signal.c b/checkpoint/signal.c index c9da06b..18b3e2d 100644 --- a/checkpoint/signal.c +++ b/checkpoint/signal.c @@ -15,6 +15,7 @@ #include <linux/signal.h> #include <linux/errno.h> #include <linux/resource.h> +#include <linux/timer.h> #include <linux/checkpoint.h> #include <linux/checkpoint_hdr.h> @@ -264,6 +265,7 @@ static int checkpoint_signal(struct ckpt_ctx *ctx, struct task_struct *t) struct signal_struct *signal; struct sigpending shared_pending; struct rlimit *rlim; + struct timeval tval; unsigned long flags; int i, ret; @@ -299,6 +301,49 @@ static int checkpoint_signal(struct ckpt_ctx *ctx, struct task_struct *t) h->rlim[i].rlim_cur = rlim[i].rlim_cur; h->rlim[i].rlim_max = rlim[i].rlim_max; } + + /* real/virt/prof itimers */ + h->it_real_incr = ktime_to_ns(signal->it_real_incr); + /* + * (a) If the timer is now active (did not expire), compute + * the time delta. + * (b) If the timer expired, and delivered the signal already, + * then set the expire (value) to the interval + * (c) If the timer expired but did not yet deliver the + * signal, then set the expire to the minimum possible, so it + * will expire immediately after restart succeeds. + */ + if (hrtimer_active(&signal->real_timer)) { + ktime_t delta = hrtimer_get_remaining(&signal->real_timer); + /* + * If the timer expired after the the test above, then + * set the expire to the minimum possible (because by + * now the pending signals have been saved already, but + * without the signal from this very expiry). + */ + ckpt_debug("active ! %lld\n", delta.tv64); + if (delta.tv64 <= 0) + delta.tv64 = NSEC_PER_USEC; + h->it_real_value = ktime_to_ns(delta); + } else if (sigismember(&signal->shared_pending.signal, SIGALRM)) { + /* case (b) */ + h->it_real_value = h->it_real_incr; + } else { + /* case (c) */ + h->it_real_value = + ktime_to_ns((ktime_t) { .tv64 = NSEC_PER_USEC }); + } + + cputime_to_timeval(signal->it_virt_expires, &tval); + h->it_virt_value = timeval_to_ns(&tval); + cputime_to_timeval(signal->it_virt_incr, &tval); + h->it_virt_incr = timeval_to_ns(&tval); + + cputime_to_timeval(signal->it_prof_expires, &tval); + h->it_prof_value = timeval_to_ns(&tval); + cputime_to_timeval(signal->it_prof_incr, &tval); + h->it_prof_incr = timeval_to_ns(&tval); + unlock_task_sighand(t, &flags); ret = ckpt_write_obj(ctx, &h->h); @@ -416,6 +461,7 @@ static int restore_signal(struct ckpt_ctx *ctx) struct ckpt_hdr_signal *h; struct sigpending new_pending; struct sigpending *pending; + struct itimerval itimer; struct rlimit rlim; int i, ret; @@ -436,12 +482,38 @@ static int restore_signal(struct ckpt_ctx *ctx) if (ret < 0) goto out; + /* + * Reset real/virt/prof itimer (in case they were set), to + * prevent unwanted signals after flushing current signals + * and before restoring original real/virt/prof itimer. + */ + itimer.it_value = (struct timeval) { .tv_sec = 0, .tv_usec = 0 }; + itimer.it_interval = (struct timeval) { .tv_sec = 0, .tv_usec = 0 }; + do_setitimer(ITIMER_REAL, &itimer, NULL); + do_setitimer(ITIMER_VIRTUAL, &itimer, NULL); + do_setitimer(ITIMER_PROF, &itimer, NULL); + spin_lock_irq(¤t->sighand->siglock); pending = ¤t->signal->shared_pending; flush_sigqueue(pending); pending->signal = new_pending.signal; list_splice_init(&new_pending.list, &pending->list); spin_unlock_irq(¤t->sighand->siglock); + + /* real/virt/prof itimers */ + itimer.it_value = ns_to_timeval(h->it_real_value); + itimer.it_interval = ns_to_timeval(h->it_real_incr); + ret = do_setitimer(ITIMER_REAL, &itimer, NULL); + if (ret < 0) + goto out; + itimer.it_value = ns_to_timeval(h->it_virt_value); + itimer.it_interval = ns_to_timeval(h->it_virt_incr); + ret = do_setitimer(ITIMER_VIRTUAL, &itimer, NULL); + if (ret < 0) + goto out; + itimer.it_value = ns_to_timeval(h->it_prof_value); + itimer.it_interval = ns_to_timeval(h->it_prof_incr); + ret = do_setitimer(ITIMER_PROF, &itimer, NULL); out: ckpt_hdr_put(ctx, h); return ret; diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h index 9dcb160..a0ec25f 100644 --- a/include/linux/checkpoint_hdr.h +++ b/include/linux/checkpoint_hdr.h @@ -472,6 +472,12 @@ struct ckpt_hdr_rlimit { struct ckpt_hdr_signal { struct ckpt_hdr h; struct ckpt_hdr_rlimit rlim[CKPT_RLIM_NLIMITS]; + __u64 it_real_value; + __u64 it_real_incr; + __u64 it_virt_value; + __u64 it_virt_incr; + __u64 it_prof_value; + __u64 it_prof_incr; } __attribute__((aligned(8))); struct ckpt_hdr_signal_task { -- 1.6.0.4 _______________________________________________ Containers mailing list Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/containers