posix_cpu_timer: consolidate expiry time type
The posix cpu timer expiry time is stored in a union of two types: a 64 bits field if we rely on scheduler precise accounting, or a cputime_t if we rely on jiffies. This results in quite some duplicate code and special cases to handle the two types. Just unify this into a single 64 bits field. cputime_t can always fit into it. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Stanislaw Gruszka <sgruszka@redhat.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Ingo Molnar <mingo@elte.hu> Cc: Oleg Nesterov <oleg@redhat.com> Cc: KOSAKI Motohiro <kosaki.motohiro@gmail.com> Cc: Olivier Langlois <olivier@trillion01.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
8bb495e3f0
commit
55ccb616a6
|
@ -7,14 +7,20 @@
|
||||||
#include <linux/timex.h>
|
#include <linux/timex.h>
|
||||||
#include <linux/alarmtimer.h>
|
#include <linux/alarmtimer.h>
|
||||||
|
|
||||||
union cpu_time_count {
|
|
||||||
cputime_t cpu;
|
static inline unsigned long long cputime_to_expires(cputime_t expires)
|
||||||
unsigned long long sched;
|
{
|
||||||
};
|
return (__force unsigned long long)expires;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline cputime_t expires_to_cputime(unsigned long long expires)
|
||||||
|
{
|
||||||
|
return (__force cputime_t)expires;
|
||||||
|
}
|
||||||
|
|
||||||
struct cpu_timer_list {
|
struct cpu_timer_list {
|
||||||
struct list_head entry;
|
struct list_head entry;
|
||||||
union cpu_time_count expires, incr;
|
unsigned long long expires, incr;
|
||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
int firing;
|
int firing;
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,59 +51,28 @@ static int check_clock(const clockid_t which_clock)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline union cpu_time_count
|
static inline unsigned long long
|
||||||
timespec_to_sample(const clockid_t which_clock, const struct timespec *tp)
|
timespec_to_sample(const clockid_t which_clock, const struct timespec *tp)
|
||||||
{
|
{
|
||||||
union cpu_time_count ret;
|
unsigned long long ret;
|
||||||
ret.sched = 0; /* high half always zero when .cpu used */
|
|
||||||
|
ret = 0; /* high half always zero when .cpu used */
|
||||||
if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
|
if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
|
||||||
ret.sched = (unsigned long long)tp->tv_sec * NSEC_PER_SEC + tp->tv_nsec;
|
ret = (unsigned long long)tp->tv_sec * NSEC_PER_SEC + tp->tv_nsec;
|
||||||
} else {
|
} else {
|
||||||
ret.cpu = timespec_to_cputime(tp);
|
ret = cputime_to_expires(timespec_to_cputime(tp));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sample_to_timespec(const clockid_t which_clock,
|
static void sample_to_timespec(const clockid_t which_clock,
|
||||||
union cpu_time_count cpu,
|
unsigned long long expires,
|
||||||
struct timespec *tp)
|
struct timespec *tp)
|
||||||
{
|
{
|
||||||
if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED)
|
if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED)
|
||||||
*tp = ns_to_timespec(cpu.sched);
|
*tp = ns_to_timespec(expires);
|
||||||
else
|
else
|
||||||
cputime_to_timespec(cpu.cpu, tp);
|
cputime_to_timespec((__force cputime_t)expires, tp);
|
||||||
}
|
|
||||||
|
|
||||||
static inline int cpu_time_before(const clockid_t which_clock,
|
|
||||||
union cpu_time_count now,
|
|
||||||
union cpu_time_count then)
|
|
||||||
{
|
|
||||||
if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
|
|
||||||
return now.sched < then.sched;
|
|
||||||
} else {
|
|
||||||
return now.cpu < then.cpu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static inline void cpu_time_add(const clockid_t which_clock,
|
|
||||||
union cpu_time_count *acc,
|
|
||||||
union cpu_time_count val)
|
|
||||||
{
|
|
||||||
if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
|
|
||||||
acc->sched += val.sched;
|
|
||||||
} else {
|
|
||||||
acc->cpu += val.cpu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static inline union cpu_time_count cpu_time_sub(const clockid_t which_clock,
|
|
||||||
union cpu_time_count a,
|
|
||||||
union cpu_time_count b)
|
|
||||||
{
|
|
||||||
if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
|
|
||||||
a.sched -= b.sched;
|
|
||||||
} else {
|
|
||||||
a.cpu -= b.cpu;
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -111,49 +80,33 @@ static inline union cpu_time_count cpu_time_sub(const clockid_t which_clock,
|
||||||
* given the current clock sample.
|
* given the current clock sample.
|
||||||
*/
|
*/
|
||||||
static void bump_cpu_timer(struct k_itimer *timer,
|
static void bump_cpu_timer(struct k_itimer *timer,
|
||||||
union cpu_time_count now)
|
unsigned long long now)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (timer->it.cpu.incr.sched == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (CPUCLOCK_WHICH(timer->it_clock) == CPUCLOCK_SCHED) {
|
|
||||||
unsigned long long delta, incr;
|
unsigned long long delta, incr;
|
||||||
|
|
||||||
if (now.sched < timer->it.cpu.expires.sched)
|
if (timer->it.cpu.incr == 0)
|
||||||
return;
|
return;
|
||||||
incr = timer->it.cpu.incr.sched;
|
|
||||||
delta = now.sched + incr - timer->it.cpu.expires.sched;
|
if (now < timer->it.cpu.expires)
|
||||||
|
return;
|
||||||
|
|
||||||
|
incr = timer->it.cpu.incr;
|
||||||
|
delta = now + incr - timer->it.cpu.expires;
|
||||||
|
|
||||||
/* Don't use (incr*2 < delta), incr*2 might overflow. */
|
/* Don't use (incr*2 < delta), incr*2 might overflow. */
|
||||||
for (i = 0; incr < delta - incr; i++)
|
for (i = 0; incr < delta - incr; i++)
|
||||||
incr = incr << 1;
|
incr = incr << 1;
|
||||||
|
|
||||||
for (; i >= 0; incr >>= 1, i--) {
|
for (; i >= 0; incr >>= 1, i--) {
|
||||||
if (delta < incr)
|
if (delta < incr)
|
||||||
continue;
|
continue;
|
||||||
timer->it.cpu.expires.sched += incr;
|
|
||||||
timer->it_overrun += 1 << i;
|
|
||||||
delta -= incr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cputime_t delta, incr;
|
|
||||||
|
|
||||||
if (now.cpu < timer->it.cpu.expires.cpu)
|
timer->it.cpu.expires += incr;
|
||||||
return;
|
|
||||||
incr = timer->it.cpu.incr.cpu;
|
|
||||||
delta = now.cpu + incr - timer->it.cpu.expires.cpu;
|
|
||||||
/* Don't use (incr*2 < delta), incr*2 might overflow. */
|
|
||||||
for (i = 0; incr < delta - incr; i++)
|
|
||||||
incr += incr;
|
|
||||||
for (; i >= 0; incr = incr >> 1, i--) {
|
|
||||||
if (delta < incr)
|
|
||||||
continue;
|
|
||||||
timer->it.cpu.expires.cpu += incr;
|
|
||||||
timer->it_overrun += 1 << i;
|
timer->it_overrun += 1 << i;
|
||||||
delta -= incr;
|
delta -= incr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* task_cputime_zero - Check a task_cputime struct for all zero fields.
|
* task_cputime_zero - Check a task_cputime struct for all zero fields.
|
||||||
|
@ -170,21 +123,21 @@ static inline int task_cputime_zero(const struct task_cputime *cputime)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline cputime_t prof_ticks(struct task_struct *p)
|
static inline unsigned long long prof_ticks(struct task_struct *p)
|
||||||
{
|
{
|
||||||
cputime_t utime, stime;
|
cputime_t utime, stime;
|
||||||
|
|
||||||
task_cputime(p, &utime, &stime);
|
task_cputime(p, &utime, &stime);
|
||||||
|
|
||||||
return utime + stime;
|
return cputime_to_expires(utime + stime);
|
||||||
}
|
}
|
||||||
static inline cputime_t virt_ticks(struct task_struct *p)
|
static inline unsigned long long virt_ticks(struct task_struct *p)
|
||||||
{
|
{
|
||||||
cputime_t utime;
|
cputime_t utime;
|
||||||
|
|
||||||
task_cputime(p, &utime, NULL);
|
task_cputime(p, &utime, NULL);
|
||||||
|
|
||||||
return utime;
|
return cputime_to_expires(utime);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -225,19 +178,19 @@ posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *tp)
|
||||||
* Sample a per-thread clock for the given task.
|
* Sample a per-thread clock for the given task.
|
||||||
*/
|
*/
|
||||||
static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p,
|
static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p,
|
||||||
union cpu_time_count *cpu)
|
unsigned long long *sample)
|
||||||
{
|
{
|
||||||
switch (CPUCLOCK_WHICH(which_clock)) {
|
switch (CPUCLOCK_WHICH(which_clock)) {
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
case CPUCLOCK_PROF:
|
case CPUCLOCK_PROF:
|
||||||
cpu->cpu = prof_ticks(p);
|
*sample = prof_ticks(p);
|
||||||
break;
|
break;
|
||||||
case CPUCLOCK_VIRT:
|
case CPUCLOCK_VIRT:
|
||||||
cpu->cpu = virt_ticks(p);
|
*sample = virt_ticks(p);
|
||||||
break;
|
break;
|
||||||
case CPUCLOCK_SCHED:
|
case CPUCLOCK_SCHED:
|
||||||
cpu->sched = task_sched_runtime(p);
|
*sample = task_sched_runtime(p);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -284,7 +237,7 @@ void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times)
|
||||||
*/
|
*/
|
||||||
static int cpu_clock_sample_group(const clockid_t which_clock,
|
static int cpu_clock_sample_group(const clockid_t which_clock,
|
||||||
struct task_struct *p,
|
struct task_struct *p,
|
||||||
union cpu_time_count *cpu)
|
unsigned long long *sample)
|
||||||
{
|
{
|
||||||
struct task_cputime cputime;
|
struct task_cputime cputime;
|
||||||
|
|
||||||
|
@ -293,15 +246,15 @@ static int cpu_clock_sample_group(const clockid_t which_clock,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
case CPUCLOCK_PROF:
|
case CPUCLOCK_PROF:
|
||||||
thread_group_cputime(p, &cputime);
|
thread_group_cputime(p, &cputime);
|
||||||
cpu->cpu = cputime.utime + cputime.stime;
|
*sample = cputime_to_expires(cputime.utime + cputime.stime);
|
||||||
break;
|
break;
|
||||||
case CPUCLOCK_VIRT:
|
case CPUCLOCK_VIRT:
|
||||||
thread_group_cputime(p, &cputime);
|
thread_group_cputime(p, &cputime);
|
||||||
cpu->cpu = cputime.utime;
|
*sample = cputime_to_expires(cputime.utime);
|
||||||
break;
|
break;
|
||||||
case CPUCLOCK_SCHED:
|
case CPUCLOCK_SCHED:
|
||||||
thread_group_cputime(p, &cputime);
|
thread_group_cputime(p, &cputime);
|
||||||
cpu->sched = cputime.sum_exec_runtime;
|
*sample = cputime.sum_exec_runtime;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -312,7 +265,7 @@ static int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp)
|
||||||
{
|
{
|
||||||
const pid_t pid = CPUCLOCK_PID(which_clock);
|
const pid_t pid = CPUCLOCK_PID(which_clock);
|
||||||
int error = -EINVAL;
|
int error = -EINVAL;
|
||||||
union cpu_time_count rtn;
|
unsigned long long rtn;
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
/*
|
/*
|
||||||
|
@ -461,30 +414,30 @@ static void cleanup_timers(struct list_head *head,
|
||||||
|
|
||||||
list_for_each_entry_safe(timer, next, head, entry) {
|
list_for_each_entry_safe(timer, next, head, entry) {
|
||||||
list_del_init(&timer->entry);
|
list_del_init(&timer->entry);
|
||||||
if (timer->expires.cpu < ptime) {
|
if (timer->expires < cputime_to_expires(ptime)) {
|
||||||
timer->expires.cpu = 0;
|
timer->expires = 0;
|
||||||
} else {
|
} else {
|
||||||
timer->expires.cpu -= ptime;
|
timer->expires -= cputime_to_expires(ptime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++head;
|
++head;
|
||||||
list_for_each_entry_safe(timer, next, head, entry) {
|
list_for_each_entry_safe(timer, next, head, entry) {
|
||||||
list_del_init(&timer->entry);
|
list_del_init(&timer->entry);
|
||||||
if (timer->expires.cpu < utime) {
|
if (timer->expires < cputime_to_expires(utime)) {
|
||||||
timer->expires.cpu = 0;
|
timer->expires = 0;
|
||||||
} else {
|
} else {
|
||||||
timer->expires.cpu -= utime;
|
timer->expires -= cputime_to_expires(utime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++head;
|
++head;
|
||||||
list_for_each_entry_safe(timer, next, head, entry) {
|
list_for_each_entry_safe(timer, next, head, entry) {
|
||||||
list_del_init(&timer->entry);
|
list_del_init(&timer->entry);
|
||||||
if (timer->expires.sched < sum_exec_runtime) {
|
if (timer->expires < sum_exec_runtime) {
|
||||||
timer->expires.sched = 0;
|
timer->expires = 0;
|
||||||
} else {
|
} else {
|
||||||
timer->expires.sched -= sum_exec_runtime;
|
timer->expires -= sum_exec_runtime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -516,7 +469,7 @@ void posix_cpu_timers_exit_group(struct task_struct *tsk)
|
||||||
tsk->se.sum_exec_runtime + sig->sum_sched_runtime);
|
tsk->se.sum_exec_runtime + sig->sum_sched_runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_dead_task(struct k_itimer *timer, union cpu_time_count now)
|
static void clear_dead_task(struct k_itimer *timer, unsigned long long now)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* That's all for this thread or process.
|
* That's all for this thread or process.
|
||||||
|
@ -524,9 +477,7 @@ static void clear_dead_task(struct k_itimer *timer, union cpu_time_count now)
|
||||||
*/
|
*/
|
||||||
put_task_struct(timer->it.cpu.task);
|
put_task_struct(timer->it.cpu.task);
|
||||||
timer->it.cpu.task = NULL;
|
timer->it.cpu.task = NULL;
|
||||||
timer->it.cpu.expires = cpu_time_sub(timer->it_clock,
|
timer->it.cpu.expires -= now;
|
||||||
timer->it.cpu.expires,
|
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int expires_gt(cputime_t expires, cputime_t new_exp)
|
static inline int expires_gt(cputime_t expires, cputime_t new_exp)
|
||||||
|
@ -558,14 +509,14 @@ static void arm_timer(struct k_itimer *timer)
|
||||||
|
|
||||||
listpos = head;
|
listpos = head;
|
||||||
list_for_each_entry(next, head, entry) {
|
list_for_each_entry(next, head, entry) {
|
||||||
if (cpu_time_before(timer->it_clock, nt->expires, next->expires))
|
if (nt->expires < next->expires)
|
||||||
break;
|
break;
|
||||||
listpos = &next->entry;
|
listpos = &next->entry;
|
||||||
}
|
}
|
||||||
list_add(&nt->entry, listpos);
|
list_add(&nt->entry, listpos);
|
||||||
|
|
||||||
if (listpos == head) {
|
if (listpos == head) {
|
||||||
union cpu_time_count *exp = &nt->expires;
|
unsigned long long exp = nt->expires;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We are the new earliest-expiring POSIX 1.b timer, hence
|
* We are the new earliest-expiring POSIX 1.b timer, hence
|
||||||
|
@ -576,17 +527,17 @@ static void arm_timer(struct k_itimer *timer)
|
||||||
|
|
||||||
switch (CPUCLOCK_WHICH(timer->it_clock)) {
|
switch (CPUCLOCK_WHICH(timer->it_clock)) {
|
||||||
case CPUCLOCK_PROF:
|
case CPUCLOCK_PROF:
|
||||||
if (expires_gt(cputime_expires->prof_exp, exp->cpu))
|
if (expires_gt(cputime_expires->prof_exp, expires_to_cputime(exp)))
|
||||||
cputime_expires->prof_exp = exp->cpu;
|
cputime_expires->prof_exp = expires_to_cputime(exp);
|
||||||
break;
|
break;
|
||||||
case CPUCLOCK_VIRT:
|
case CPUCLOCK_VIRT:
|
||||||
if (expires_gt(cputime_expires->virt_exp, exp->cpu))
|
if (expires_gt(cputime_expires->virt_exp, expires_to_cputime(exp)))
|
||||||
cputime_expires->virt_exp = exp->cpu;
|
cputime_expires->virt_exp = expires_to_cputime(exp);
|
||||||
break;
|
break;
|
||||||
case CPUCLOCK_SCHED:
|
case CPUCLOCK_SCHED:
|
||||||
if (cputime_expires->sched_exp == 0 ||
|
if (cputime_expires->sched_exp == 0 ||
|
||||||
cputime_expires->sched_exp > exp->sched)
|
cputime_expires->sched_exp > exp)
|
||||||
cputime_expires->sched_exp = exp->sched;
|
cputime_expires->sched_exp = exp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -601,20 +552,20 @@ static void cpu_timer_fire(struct k_itimer *timer)
|
||||||
/*
|
/*
|
||||||
* User don't want any signal.
|
* User don't want any signal.
|
||||||
*/
|
*/
|
||||||
timer->it.cpu.expires.sched = 0;
|
timer->it.cpu.expires = 0;
|
||||||
} else if (unlikely(timer->sigq == NULL)) {
|
} else if (unlikely(timer->sigq == NULL)) {
|
||||||
/*
|
/*
|
||||||
* This a special case for clock_nanosleep,
|
* This a special case for clock_nanosleep,
|
||||||
* not a normal timer from sys_timer_create.
|
* not a normal timer from sys_timer_create.
|
||||||
*/
|
*/
|
||||||
wake_up_process(timer->it_process);
|
wake_up_process(timer->it_process);
|
||||||
timer->it.cpu.expires.sched = 0;
|
timer->it.cpu.expires = 0;
|
||||||
} else if (timer->it.cpu.incr.sched == 0) {
|
} else if (timer->it.cpu.incr == 0) {
|
||||||
/*
|
/*
|
||||||
* One-shot timer. Clear it as soon as it's fired.
|
* One-shot timer. Clear it as soon as it's fired.
|
||||||
*/
|
*/
|
||||||
posix_timer_event(timer, 0);
|
posix_timer_event(timer, 0);
|
||||||
timer->it.cpu.expires.sched = 0;
|
timer->it.cpu.expires = 0;
|
||||||
} else if (posix_timer_event(timer, ++timer->it_requeue_pending)) {
|
} else if (posix_timer_event(timer, ++timer->it_requeue_pending)) {
|
||||||
/*
|
/*
|
||||||
* The signal did not get queued because the signal
|
* The signal did not get queued because the signal
|
||||||
|
@ -632,7 +583,7 @@ static void cpu_timer_fire(struct k_itimer *timer)
|
||||||
*/
|
*/
|
||||||
static int cpu_timer_sample_group(const clockid_t which_clock,
|
static int cpu_timer_sample_group(const clockid_t which_clock,
|
||||||
struct task_struct *p,
|
struct task_struct *p,
|
||||||
union cpu_time_count *cpu)
|
unsigned long long *sample)
|
||||||
{
|
{
|
||||||
struct task_cputime cputime;
|
struct task_cputime cputime;
|
||||||
|
|
||||||
|
@ -641,13 +592,13 @@ static int cpu_timer_sample_group(const clockid_t which_clock,
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
case CPUCLOCK_PROF:
|
case CPUCLOCK_PROF:
|
||||||
cpu->cpu = cputime.utime + cputime.stime;
|
*sample = cputime_to_expires(cputime.utime + cputime.stime);
|
||||||
break;
|
break;
|
||||||
case CPUCLOCK_VIRT:
|
case CPUCLOCK_VIRT:
|
||||||
cpu->cpu = cputime.utime;
|
*sample = cputime_to_expires(cputime.utime);
|
||||||
break;
|
break;
|
||||||
case CPUCLOCK_SCHED:
|
case CPUCLOCK_SCHED:
|
||||||
cpu->sched = cputime.sum_exec_runtime + task_delta_exec(p);
|
*sample = cputime.sum_exec_runtime + task_delta_exec(p);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -694,7 +645,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int flags,
|
||||||
struct itimerspec *new, struct itimerspec *old)
|
struct itimerspec *new, struct itimerspec *old)
|
||||||
{
|
{
|
||||||
struct task_struct *p = timer->it.cpu.task;
|
struct task_struct *p = timer->it.cpu.task;
|
||||||
union cpu_time_count old_expires, new_expires, old_incr, val;
|
unsigned long long old_expires, new_expires, old_incr, val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (unlikely(p == NULL)) {
|
if (unlikely(p == NULL)) {
|
||||||
|
@ -749,7 +700,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old) {
|
if (old) {
|
||||||
if (old_expires.sched == 0) {
|
if (old_expires == 0) {
|
||||||
old->it_value.tv_sec = 0;
|
old->it_value.tv_sec = 0;
|
||||||
old->it_value.tv_nsec = 0;
|
old->it_value.tv_nsec = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -764,11 +715,8 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int flags,
|
||||||
* new setting.
|
* new setting.
|
||||||
*/
|
*/
|
||||||
bump_cpu_timer(timer, val);
|
bump_cpu_timer(timer, val);
|
||||||
if (cpu_time_before(timer->it_clock, val,
|
if (val < timer->it.cpu.expires) {
|
||||||
timer->it.cpu.expires)) {
|
old_expires = timer->it.cpu.expires - val;
|
||||||
old_expires = cpu_time_sub(
|
|
||||||
timer->it_clock,
|
|
||||||
timer->it.cpu.expires, val);
|
|
||||||
sample_to_timespec(timer->it_clock,
|
sample_to_timespec(timer->it_clock,
|
||||||
old_expires,
|
old_expires,
|
||||||
&old->it_value);
|
&old->it_value);
|
||||||
|
@ -791,8 +739,8 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int flags,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_expires.sched != 0 && !(flags & TIMER_ABSTIME)) {
|
if (new_expires != 0 && !(flags & TIMER_ABSTIME)) {
|
||||||
cpu_time_add(timer->it_clock, &new_expires, val);
|
new_expires += val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -801,8 +749,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int flags,
|
||||||
* arm the timer (we'll just fake it for timer_gettime).
|
* arm the timer (we'll just fake it for timer_gettime).
|
||||||
*/
|
*/
|
||||||
timer->it.cpu.expires = new_expires;
|
timer->it.cpu.expires = new_expires;
|
||||||
if (new_expires.sched != 0 &&
|
if (new_expires != 0 && val < new_expires) {
|
||||||
cpu_time_before(timer->it_clock, val, new_expires)) {
|
|
||||||
arm_timer(timer);
|
arm_timer(timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -826,8 +773,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int flags,
|
||||||
timer->it_overrun_last = 0;
|
timer->it_overrun_last = 0;
|
||||||
timer->it_overrun = -1;
|
timer->it_overrun = -1;
|
||||||
|
|
||||||
if (new_expires.sched != 0 &&
|
if (new_expires != 0 && !(val < new_expires)) {
|
||||||
!cpu_time_before(timer->it_clock, val, new_expires)) {
|
|
||||||
/*
|
/*
|
||||||
* The designated time already passed, so we notify
|
* The designated time already passed, so we notify
|
||||||
* immediately, even if the thread never runs to
|
* immediately, even if the thread never runs to
|
||||||
|
@ -849,7 +795,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int flags,
|
||||||
|
|
||||||
static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
|
static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
|
||||||
{
|
{
|
||||||
union cpu_time_count now;
|
unsigned long long now;
|
||||||
struct task_struct *p = timer->it.cpu.task;
|
struct task_struct *p = timer->it.cpu.task;
|
||||||
int clear_dead;
|
int clear_dead;
|
||||||
|
|
||||||
|
@ -859,7 +805,7 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
|
||||||
sample_to_timespec(timer->it_clock,
|
sample_to_timespec(timer->it_clock,
|
||||||
timer->it.cpu.incr, &itp->it_interval);
|
timer->it.cpu.incr, &itp->it_interval);
|
||||||
|
|
||||||
if (timer->it.cpu.expires.sched == 0) { /* Timer not armed at all. */
|
if (timer->it.cpu.expires == 0) { /* Timer not armed at all. */
|
||||||
itp->it_value.tv_sec = itp->it_value.tv_nsec = 0;
|
itp->it_value.tv_sec = itp->it_value.tv_nsec = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -891,7 +837,7 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
|
||||||
*/
|
*/
|
||||||
put_task_struct(p);
|
put_task_struct(p);
|
||||||
timer->it.cpu.task = NULL;
|
timer->it.cpu.task = NULL;
|
||||||
timer->it.cpu.expires.sched = 0;
|
timer->it.cpu.expires = 0;
|
||||||
read_unlock(&tasklist_lock);
|
read_unlock(&tasklist_lock);
|
||||||
goto dead;
|
goto dead;
|
||||||
} else {
|
} else {
|
||||||
|
@ -912,10 +858,9 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
|
||||||
goto dead;
|
goto dead;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu_time_before(timer->it_clock, now, timer->it.cpu.expires)) {
|
if (now < timer->it.cpu.expires) {
|
||||||
sample_to_timespec(timer->it_clock,
|
sample_to_timespec(timer->it_clock,
|
||||||
cpu_time_sub(timer->it_clock,
|
timer->it.cpu.expires - now,
|
||||||
timer->it.cpu.expires, now),
|
|
||||||
&itp->it_value);
|
&itp->it_value);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
|
@ -946,8 +891,8 @@ static void check_thread_timers(struct task_struct *tsk,
|
||||||
struct cpu_timer_list *t = list_first_entry(timers,
|
struct cpu_timer_list *t = list_first_entry(timers,
|
||||||
struct cpu_timer_list,
|
struct cpu_timer_list,
|
||||||
entry);
|
entry);
|
||||||
if (!--maxfire || prof_ticks(tsk) < t->expires.cpu) {
|
if (!--maxfire || prof_ticks(tsk) < t->expires) {
|
||||||
tsk->cputime_expires.prof_exp = t->expires.cpu;
|
tsk->cputime_expires.prof_exp = expires_to_cputime(t->expires);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
t->firing = 1;
|
t->firing = 1;
|
||||||
|
@ -961,8 +906,8 @@ static void check_thread_timers(struct task_struct *tsk,
|
||||||
struct cpu_timer_list *t = list_first_entry(timers,
|
struct cpu_timer_list *t = list_first_entry(timers,
|
||||||
struct cpu_timer_list,
|
struct cpu_timer_list,
|
||||||
entry);
|
entry);
|
||||||
if (!--maxfire || virt_ticks(tsk) < t->expires.cpu) {
|
if (!--maxfire || virt_ticks(tsk) < t->expires) {
|
||||||
tsk->cputime_expires.virt_exp = t->expires.cpu;
|
tsk->cputime_expires.virt_exp = expires_to_cputime(t->expires);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
t->firing = 1;
|
t->firing = 1;
|
||||||
|
@ -976,8 +921,8 @@ static void check_thread_timers(struct task_struct *tsk,
|
||||||
struct cpu_timer_list *t = list_first_entry(timers,
|
struct cpu_timer_list *t = list_first_entry(timers,
|
||||||
struct cpu_timer_list,
|
struct cpu_timer_list,
|
||||||
entry);
|
entry);
|
||||||
if (!--maxfire || tsk->se.sum_exec_runtime < t->expires.sched) {
|
if (!--maxfire || tsk->se.sum_exec_runtime < t->expires) {
|
||||||
tsk->cputime_expires.sched_exp = t->expires.sched;
|
tsk->cputime_expires.sched_exp = t->expires;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
t->firing = 1;
|
t->firing = 1;
|
||||||
|
@ -1030,7 +975,8 @@ static void stop_process_timers(struct signal_struct *sig)
|
||||||
static u32 onecputick;
|
static u32 onecputick;
|
||||||
|
|
||||||
static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it,
|
static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it,
|
||||||
cputime_t *expires, cputime_t cur_time, int signo)
|
unsigned long long *expires,
|
||||||
|
unsigned long long cur_time, int signo)
|
||||||
{
|
{
|
||||||
if (!it->expires)
|
if (!it->expires)
|
||||||
return;
|
return;
|
||||||
|
@ -1068,7 +1014,7 @@ static void check_process_timers(struct task_struct *tsk,
|
||||||
{
|
{
|
||||||
int maxfire;
|
int maxfire;
|
||||||
struct signal_struct *const sig = tsk->signal;
|
struct signal_struct *const sig = tsk->signal;
|
||||||
cputime_t utime, ptime, virt_expires, prof_expires;
|
unsigned long long utime, ptime, virt_expires, prof_expires;
|
||||||
unsigned long long sum_sched_runtime, sched_expires;
|
unsigned long long sum_sched_runtime, sched_expires;
|
||||||
struct list_head *timers = sig->cpu_timers;
|
struct list_head *timers = sig->cpu_timers;
|
||||||
struct task_cputime cputime;
|
struct task_cputime cputime;
|
||||||
|
@ -1078,8 +1024,8 @@ static void check_process_timers(struct task_struct *tsk,
|
||||||
* Collect the current process totals.
|
* Collect the current process totals.
|
||||||
*/
|
*/
|
||||||
thread_group_cputimer(tsk, &cputime);
|
thread_group_cputimer(tsk, &cputime);
|
||||||
utime = cputime.utime;
|
utime = cputime_to_expires(cputime.utime);
|
||||||
ptime = utime + cputime.stime;
|
ptime = utime + cputime_to_expires(cputime.stime);
|
||||||
sum_sched_runtime = cputime.sum_exec_runtime;
|
sum_sched_runtime = cputime.sum_exec_runtime;
|
||||||
maxfire = 20;
|
maxfire = 20;
|
||||||
prof_expires = 0;
|
prof_expires = 0;
|
||||||
|
@ -1087,8 +1033,8 @@ static void check_process_timers(struct task_struct *tsk,
|
||||||
struct cpu_timer_list *tl = list_first_entry(timers,
|
struct cpu_timer_list *tl = list_first_entry(timers,
|
||||||
struct cpu_timer_list,
|
struct cpu_timer_list,
|
||||||
entry);
|
entry);
|
||||||
if (!--maxfire || ptime < tl->expires.cpu) {
|
if (!--maxfire || ptime < tl->expires) {
|
||||||
prof_expires = tl->expires.cpu;
|
prof_expires = tl->expires;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tl->firing = 1;
|
tl->firing = 1;
|
||||||
|
@ -1102,8 +1048,8 @@ static void check_process_timers(struct task_struct *tsk,
|
||||||
struct cpu_timer_list *tl = list_first_entry(timers,
|
struct cpu_timer_list *tl = list_first_entry(timers,
|
||||||
struct cpu_timer_list,
|
struct cpu_timer_list,
|
||||||
entry);
|
entry);
|
||||||
if (!--maxfire || utime < tl->expires.cpu) {
|
if (!--maxfire || utime < tl->expires) {
|
||||||
virt_expires = tl->expires.cpu;
|
virt_expires = tl->expires;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tl->firing = 1;
|
tl->firing = 1;
|
||||||
|
@ -1117,8 +1063,8 @@ static void check_process_timers(struct task_struct *tsk,
|
||||||
struct cpu_timer_list *tl = list_first_entry(timers,
|
struct cpu_timer_list *tl = list_first_entry(timers,
|
||||||
struct cpu_timer_list,
|
struct cpu_timer_list,
|
||||||
entry);
|
entry);
|
||||||
if (!--maxfire || sum_sched_runtime < tl->expires.sched) {
|
if (!--maxfire || sum_sched_runtime < tl->expires) {
|
||||||
sched_expires = tl->expires.sched;
|
sched_expires = tl->expires;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tl->firing = 1;
|
tl->firing = 1;
|
||||||
|
@ -1162,8 +1108,8 @@ static void check_process_timers(struct task_struct *tsk,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sig->cputime_expires.prof_exp = prof_expires;
|
sig->cputime_expires.prof_exp = expires_to_cputime(prof_expires);
|
||||||
sig->cputime_expires.virt_exp = virt_expires;
|
sig->cputime_expires.virt_exp = expires_to_cputime(virt_expires);
|
||||||
sig->cputime_expires.sched_exp = sched_expires;
|
sig->cputime_expires.sched_exp = sched_expires;
|
||||||
if (task_cputime_zero(&sig->cputime_expires))
|
if (task_cputime_zero(&sig->cputime_expires))
|
||||||
stop_process_timers(sig);
|
stop_process_timers(sig);
|
||||||
|
@ -1176,7 +1122,7 @@ static void check_process_timers(struct task_struct *tsk,
|
||||||
void posix_cpu_timer_schedule(struct k_itimer *timer)
|
void posix_cpu_timer_schedule(struct k_itimer *timer)
|
||||||
{
|
{
|
||||||
struct task_struct *p = timer->it.cpu.task;
|
struct task_struct *p = timer->it.cpu.task;
|
||||||
union cpu_time_count now;
|
unsigned long long now;
|
||||||
|
|
||||||
if (unlikely(p == NULL))
|
if (unlikely(p == NULL))
|
||||||
/*
|
/*
|
||||||
|
@ -1205,7 +1151,7 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
|
||||||
*/
|
*/
|
||||||
put_task_struct(p);
|
put_task_struct(p);
|
||||||
timer->it.cpu.task = p = NULL;
|
timer->it.cpu.task = p = NULL;
|
||||||
timer->it.cpu.expires.sched = 0;
|
timer->it.cpu.expires = 0;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
} else if (unlikely(p->exit_state) && thread_group_empty(p)) {
|
} else if (unlikely(p->exit_state) && thread_group_empty(p)) {
|
||||||
/*
|
/*
|
||||||
|
@ -1387,7 +1333,7 @@ void run_posix_cpu_timers(struct task_struct *tsk)
|
||||||
void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
|
void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
|
||||||
cputime_t *newval, cputime_t *oldval)
|
cputime_t *newval, cputime_t *oldval)
|
||||||
{
|
{
|
||||||
union cpu_time_count now;
|
unsigned long long now;
|
||||||
|
|
||||||
BUG_ON(clock_idx == CPUCLOCK_SCHED);
|
BUG_ON(clock_idx == CPUCLOCK_SCHED);
|
||||||
cpu_timer_sample_group(clock_idx, tsk, &now);
|
cpu_timer_sample_group(clock_idx, tsk, &now);
|
||||||
|
@ -1399,17 +1345,17 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
|
||||||
* it to be absolute.
|
* it to be absolute.
|
||||||
*/
|
*/
|
||||||
if (*oldval) {
|
if (*oldval) {
|
||||||
if (*oldval <= now.cpu) {
|
if (*oldval <= now) {
|
||||||
/* Just about to fire. */
|
/* Just about to fire. */
|
||||||
*oldval = cputime_one_jiffy;
|
*oldval = cputime_one_jiffy;
|
||||||
} else {
|
} else {
|
||||||
*oldval -= now.cpu;
|
*oldval -= now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*newval)
|
if (!*newval)
|
||||||
goto out;
|
goto out;
|
||||||
*newval += now.cpu;
|
*newval += now;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1459,7 +1405,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!signal_pending(current)) {
|
while (!signal_pending(current)) {
|
||||||
if (timer.it.cpu.expires.sched == 0) {
|
if (timer.it.cpu.expires == 0) {
|
||||||
/*
|
/*
|
||||||
* Our timer fired and was reset, below
|
* Our timer fired and was reset, below
|
||||||
* deletion can not fail.
|
* deletion can not fail.
|
||||||
|
|
Loading…
Reference in New Issue