2005-01-23 23:42:53

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 4/7] posix-timers: CPU clock support for POSIX timers

POSIX requires that when you claim _POSIX_CPUTIME and _POSIX_THREAD_CPUTIME,
not only the clock_* calls but also timer_* calls must support the thread
and process CPU time clocks. This patch provides that support, building on
my recent additions to support these clocks in the POSIX clock_* interfaces.
This patch will not work without those changes, as well as the patch fixing
the timer lock-siglock deadlock problem.

The apparent pervasive changes to posix-timers.c are simply that some
fields of struct k_itimer have changed name and moved into a union.
This was appropriate since the data structures required for the existing
real-time timer support and for the new thread/process CPU-time timers are
quite different.

The glibc patches to support CPU time clocks using the new kernel support
is in http://people.redhat.com/roland/glibc/kernel-cpuclocks.patch, and
that includes tests for the timer support (if you build glibc with NPTL).


Signed-off-by: Roland McGrath <[email protected]>

--- linux-2.6/include/linux/init_task.h
+++ linux-2.6/include/linux/init_task.h
@@ -51,6 +51,7 @@
.list = LIST_HEAD_INIT(sig.shared_pending.list), \
.signal = {{0}}}, \
.posix_timers = LIST_HEAD_INIT(sig.posix_timers), \
+ .cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \
.rlim = INIT_RLIMITS, \
}

@@ -112,8 +113,16 @@ extern struct group_info init_groups;
.proc_lock = SPIN_LOCK_UNLOCKED, \
.switch_lock = SPIN_LOCK_UNLOCKED, \
.journal_info = NULL, \
+ .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \
}


+#define INIT_CPU_TIMERS(cpu_timers) \
+{ \
+ LIST_HEAD_INIT(cpu_timers[0]), \
+ LIST_HEAD_INIT(cpu_timers[1]), \
+ LIST_HEAD_INIT(cpu_timers[2]), \
+}
+

#endif
--- linux-2.6/include/linux/posix-timers.h
+++ linux-2.6/include/linux/posix-timers.h
@@ -3,8 +3,21 @@

#include <linux/spinlock.h>
#include <linux/list.h>
+#include <linux/sched.h>

-#define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3))
+union cpu_time_count {
+ cputime_t cpu;
+ unsigned long long sched;
+};
+
+struct cpu_timer_list {
+ struct list_head entry;
+ union cpu_time_count expires, incr;
+ struct task_struct *task;
+ int firing;
+};
+
+#define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3))
#define CPUCLOCK_PERTHREAD(clock) \
(((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0)
#define CPUCLOCK_PID_MASK 7
@@ -30,15 +43,21 @@ struct k_itimer {
int it_overrun; /* overrun on pending signal */
int it_overrun_last; /* overrun on last delivered signal */
int it_requeue_pending; /* waiting to requeue this timer */
+#define REQUEUE_PENDING 1
int it_sigev_notify; /* notify word of sigevent struct */
int it_sigev_signo; /* signo word of sigevent struct */
sigval_t it_sigev_value; /* value word of sigevent struct */
- unsigned long it_incr; /* interval specified in jiffies */
struct task_struct *it_process; /* process to send signal to */
- struct timer_list it_timer;
struct sigqueue *sigq; /* signal queue entry. */
- struct list_head abs_timer_entry; /* clock abs_timer_list */
- struct timespec wall_to_prev; /* wall_to_monotonic used when set */
+ union {
+ struct {
+ struct timer_list timer;
+ struct list_head abs_timer_entry; /* clock abs_timer_list */
+ struct timespec wall_to_prev; /* wall_to_monotonic used when set */
+ unsigned long incr; /* interval in jiffies */
+ } real;
+ struct cpu_timer_list cpu;
+ } it;
};

struct k_clock_abs {
@@ -57,6 +76,7 @@ struct k_clock {
struct itimerspec * new_setting,
struct itimerspec * old_setting);
int (*timer_del) (struct k_itimer * timr);
+#define TIMER_RETRY 1
void (*timer_get) (struct k_itimer * timr,
struct itimerspec * cur_setting);
};
@@ -82,10 +102,11 @@ struct now_struct {
#define posix_bump_timer(timr, now) \
do { \
long delta, orun; \
- delta = now.jiffies - (timr)->it_timer.expires; \
+ delta = now.jiffies - (timr)->it.real.timer.expires; \
if (delta >= 0) { \
- orun = 1 + (delta / (timr)->it_incr); \
- (timr)->it_timer.expires += orun * (timr)->it_incr; \
+ orun = 1 + (delta / (timr)->it.real.incr); \
+ (timr)->it.real.timer.expires += \
+ orun * (timr)->it.real.incr; \
(timr)->it_overrun += orun; \
} \
}while (0)
@@ -95,12 +116,16 @@ int posix_cpu_clock_get(clockid_t which_
int posix_cpu_clock_set(clockid_t which_clock, const struct timespec *tp);
int posix_cpu_timer_create(struct k_itimer *);
int posix_cpu_nsleep(clockid_t, int, struct timespec *);
-#define posix_cpu_timer_create do_posix_clock_notimer_create
-#define posix_cpu_nsleep do_posix_clock_nonanosleep
int posix_cpu_timer_set(struct k_itimer *, int,
struct itimerspec *, struct itimerspec *);
int posix_cpu_timer_del(struct k_itimer *);
void posix_cpu_timer_get(struct k_itimer *, struct itimerspec *);

+void posix_cpu_timer_schedule(struct k_itimer *);
+
+void run_posix_cpu_timers(struct task_struct *);
+void posix_cpu_timers_exit(struct task_struct *);
+void posix_cpu_timers_exit_group(struct task_struct *);
+

#endif
--- linux-2.6/include/linux/sched.h
+++ linux-2.6/include/linux/sched.h
@@ -337,6 +337,8 @@ struct signal_struct {
* have no need to disable irqs.
*/
struct rlimit rlim[RLIM_NLIMITS];
+
+ struct list_head cpu_timers[3];
};

/*
@@ -611,6 +613,11 @@ struct task_struct {
struct timespec start_time;
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt;
+
+ cputime_t it_prof_expires, it_virt_expires;
+ unsigned long long it_sched_expires;
+ struct list_head cpu_timers[3];
+
/* process credentials */
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
--- linux-2.6/kernel/exit.c
+++ linux-2.6/kernel/exit.c
@@ -759,6 +759,9 @@ static void exit_notify(struct task_stru
*/
tsk->it_virt_value = cputime_zero;
tsk->it_prof_value = cputime_zero;
+ tsk->it_virt_expires = cputime_zero;
+ tsk->it_prof_expires = cputime_zero;
+ tsk->it_sched_expires = 0;

write_unlock_irq(&tasklist_lock);

--- linux-2.6/kernel/fork.c
+++ linux-2.6/kernel/fork.c
@@ -753,6 +753,9 @@ static inline int copy_signal(unsigned l
sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
sig->sched_time = 0;
+ INIT_LIST_HEAD(&sig->cpu_timers[0]);
+ INIT_LIST_HEAD(&sig->cpu_timers[1]);
+ INIT_LIST_HEAD(&sig->cpu_timers[2]);

task_lock(current->group_leader);
memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim);
@@ -888,6 +891,13 @@ static task_t *copy_process(unsigned lon
p->syscw = 0; /* I/O counter: write syscalls */
acct_clear_integrals(p);

+ p->it_virt_expires = cputime_zero;
+ p->it_prof_expires = cputime_zero;
+ p->it_sched_expires = 0;
+ INIT_LIST_HEAD(&p->cpu_timers[0]);
+ INIT_LIST_HEAD(&p->cpu_timers[1]);
+ INIT_LIST_HEAD(&p->cpu_timers[2]);
+
p->lock_depth = -1; /* -1 = no lock */
do_posix_clock_monotonic_gettime(&p->start_time);
p->security = NULL;
@@ -1020,6 +1030,16 @@ static task_t *copy_process(unsigned lon
set_tsk_thread_flag(p, TIF_SIGPENDING);
}

+ if (!list_empty(&current->signal->cpu_timers[0]) ||
+ !list_empty(&current->signal->cpu_timers[1]) ||
+ !list_empty(&current->signal->cpu_timers[2])) {
+ /*
+ * Have child wake up on its first tick to check
+ * for process CPU timers.
+ */
+ p->it_prof_expires = jiffies_to_cputime(1);
+ }
+
spin_unlock(&current->sighand->siglock);
}

--- linux-2.6/kernel/posix-cpu-timers.c
+++ linux-2.6/kernel/posix-cpu-timers.c
@@ -7,11 +7,6 @@
#include <asm/uaccess.h>
#include <linux/errno.h>

-union cpu_time_count {
- cputime_t cpu;
- unsigned long long sched;
-};
-
static int check_clock(clockid_t which_clock)
{
int error = 0;
@@ -35,6 +30,19 @@ static int check_clock(clockid_t which_c
return error;
}

+static inline union cpu_time_count
+timespec_to_sample(clockid_t which_clock, const struct timespec *tp)
+{
+ union cpu_time_count ret;
+ ret.sched = 0; /* high half always zero when .cpu used */
+ if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
+ ret.sched = tp->tv_sec * NSEC_PER_SEC + tp->tv_nsec;
+ } else {
+ ret.cpu = timespec_to_jiffies(tp);
+ }
+ return ret;
+}
+
static void sample_to_timespec(clockid_t which_clock,
union cpu_time_count cpu,
struct timespec *tp)
@@ -47,6 +55,71 @@ static void sample_to_timespec(clockid_t
}
}

+static inline int cpu_time_before(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 cputime_lt(now.cpu, then.cpu);
+ }
+}
+static inline void cpu_time_add(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 = cputime_add(acc->cpu, val.cpu);
+ }
+}
+static inline union cpu_time_count cpu_time_sub(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 = cputime_sub(a.cpu, b.cpu);
+ }
+ return a;
+}
+
+/*
+ * Update expiry time from increment, and increase overrun count,
+ * given the current clock sample.
+ */
+static inline void bump_cpu_timer(struct k_itimer *timer,
+ union cpu_time_count now)
+{
+ if (timer->it.cpu.incr.sched == 0)
+ return;
+
+ if (CPUCLOCK_WHICH(timer->it_clock) == CPUCLOCK_SCHED) {
+ long long delta;
+ delta = now.sched - timer->it.cpu.expires.sched;
+ if (delta >= 0) {
+ do_div(delta, timer->it.cpu.incr.sched);
+ delta++;
+ timer->it.cpu.expires.sched +=
+ delta * timer->it.cpu.incr.sched;
+ timer->it_overrun += (int) delta;
+ }
+ } else if (cputime_le(now.cpu, timer->it.cpu.expires.cpu)) {
+ cputime_t delta = cputime_sub(now.cpu,
+ timer->it.cpu.expires.cpu);
+ if (cputime_ge(delta, cputime_zero)) {
+ long orun = 1 + (delta / timer->it.cpu.incr.cpu);
+ timer->it.cpu.expires.cpu =
+ cputime_add(timer->it.cpu.expires.cpu,
+ orun * timer->it.cpu.incr.cpu);
+ timer->it_overrun += orun;
+ }
+ }
+}
+
static inline cputime_t prof_ticks(struct task_struct *p)
{
return cputime_add(p->utime, p->stime);
@@ -222,23 +295,1008 @@ int posix_cpu_clock_get(clockid_t which_
return 0;
}

+
/*
- * These can't be called, since timer_create never works.
+ * Validate the clockid_t for a new CPU-clock timer, and initialize the timer.
+ * This is called from sys_timer_create with the new timer already locked.
*/
-int posix_cpu_timer_set(struct k_itimer *timer, int flags,
- struct itimerspec *old, struct itimerspec *new)
+int posix_cpu_timer_create(struct k_itimer *new_timer)
{
- BUG();
- return -EINVAL;
+ int ret = 0;
+ const pid_t pid = CPUCLOCK_PID(new_timer->it_clock);
+ struct task_struct *p;
+
+ if (CPUCLOCK_WHICH(new_timer->it_clock) >= CPUCLOCK_MAX)
+ return -EINVAL;
+
+ INIT_LIST_HEAD(&new_timer->it.cpu.entry);
+ new_timer->it.cpu.incr.sched = 0;
+ new_timer->it.cpu.expires.sched = 0;
+
+ read_lock(&tasklist_lock);
+ if (CPUCLOCK_PERTHREAD(new_timer->it_clock)) {
+ if (pid == 0) {
+ p = current;
+ } else {
+ p = find_task_by_pid(pid);
+ if (p && p->tgid != current->tgid)
+ p = NULL;
+ }
+ } else {
+ if (pid == 0) {
+ p = current->group_leader;
+ } else {
+ p = find_task_by_pid(pid);
+ if (p && p->tgid != pid)
+ p = NULL;
+ }
+ }
+ new_timer->it.cpu.task = p;
+ if (p) {
+ get_task_struct(p);
+ } else {
+ ret = -EINVAL;
+ }
+ read_unlock(&tasklist_lock);
+
+ return ret;
}
+
+/*
+ * Clean up a CPU-clock timer that is about to be destroyed.
+ * This is called from timer deletion with the timer already locked.
+ * If we return TIMER_RETRY, it's necessary to release the timer's lock
+ * and try again. (This happens when the timer is in the middle of firing.)
+ */
int posix_cpu_timer_del(struct k_itimer *timer)
{
- BUG();
- return -EINVAL;
+ struct task_struct *p = timer->it.cpu.task;
+
+ if (timer->it.cpu.firing)
+ return TIMER_RETRY;
+
+ if (unlikely(p == NULL))
+ return 0;
+
+ if (!list_empty(&timer->it.cpu.entry)) {
+ read_lock(&tasklist_lock);
+ if (unlikely(p->signal == NULL)) {
+ /*
+ * We raced with the reaping of the task.
+ * The deletion should have cleared us off the list.
+ */
+ BUG_ON(!list_empty(&timer->it.cpu.entry));
+ } else {
+ /*
+ * Take us off the task's timer list.
+ */
+ spin_lock(&p->sighand->siglock);
+ list_del(&timer->it.cpu.entry);
+ spin_unlock(&p->sighand->siglock);
+ }
+ read_unlock(&tasklist_lock);
+ }
+ put_task_struct(p);
+
+ return 0;
+}
+
+/*
+ * Clean out CPU timers still ticking when a thread exited. The task
+ * pointer is cleared, and the expiry time is replaced with the residual
+ * time for later timer_gettime calls to return.
+ * This must be called with the siglock held.
+ */
+static void cleanup_timers(struct list_head *head,
+ cputime_t utime, cputime_t stime,
+ unsigned long long sched_time)
+{
+ struct cpu_timer_list *timer, *next;
+ cputime_t ptime = cputime_add(utime, stime);
+
+ list_for_each_entry_safe(timer, next, head, entry) {
+ timer->task = NULL;
+ list_del_init(&timer->entry);
+ if (cputime_lt(timer->expires.cpu, ptime)) {
+ timer->expires.cpu = cputime_zero;
+ } else {
+ timer->expires.cpu = cputime_sub(timer->expires.cpu,
+ ptime);
+ }
+ }
+
+ ++head;
+ list_for_each_entry_safe(timer, next, head, entry) {
+ timer->task = NULL;
+ list_del_init(&timer->entry);
+ if (cputime_lt(timer->expires.cpu, utime)) {
+ timer->expires.cpu = cputime_zero;
+ } else {
+ timer->expires.cpu = cputime_sub(timer->expires.cpu,
+ utime);
+ }
+ }
+
+ ++head;
+ list_for_each_entry_safe(timer, next, head, entry) {
+ timer->task = NULL;
+ list_del_init(&timer->entry);
+ if (timer->expires.sched < sched_time) {
+ timer->expires.sched = 0;
+ } else {
+ timer->expires.sched -= sched_time;
+ }
+ }
+}
+
+/*
+ * These are both called with the siglock held, when the current thread
+ * is being reaped. When the final (leader) thread in the group is reaped,
+ * posix_cpu_timers_exit_group will be called after posix_cpu_timers_exit.
+ */
+void posix_cpu_timers_exit(struct task_struct *tsk)
+{
+ cleanup_timers(tsk->cpu_timers,
+ tsk->utime, tsk->stime, tsk->sched_time);
+
+}
+void posix_cpu_timers_exit_group(struct task_struct *tsk)
+{
+ cleanup_timers(tsk->signal->cpu_timers,
+ cputime_add(tsk->utime, tsk->signal->utime),
+ cputime_add(tsk->stime, tsk->signal->stime),
+ tsk->sched_time + tsk->signal->sched_time);
+}
+
+
+/*
+ * Set the expiry times of all the threads in the process so one of them
+ * will go off before the process cumulative expiry total is reached.
+ */
+static void
+process_timer_rebalance(struct k_itimer *timer, union cpu_time_count val)
+{
+ cputime_t ticks, left;
+ unsigned long long ns, nsleft;
+ struct task_struct *const p = timer->it.cpu.task, *t = p;
+ unsigned int nthreads = atomic_read(&p->signal->live);
+
+ switch (CPUCLOCK_WHICH(timer->it_clock)) {
+ default:
+ BUG();
+ break;
+ case CPUCLOCK_PROF:
+ left = cputime_sub(timer->it.cpu.expires.cpu, val.cpu)
+ / nthreads;
+ do {
+ if (!unlikely(t->exit_state)) {
+ ticks = cputime_add(prof_ticks(t), left);
+ if (cputime_eq(t->it_prof_expires,
+ cputime_zero) ||
+ cputime_gt(t->it_prof_expires, ticks)) {
+ t->it_prof_expires = ticks;
+ }
+ }
+ t = next_thread(t);
+ } while (t != p);
+ break;
+ case CPUCLOCK_VIRT:
+ left = cputime_sub(timer->it.cpu.expires.cpu, val.cpu)
+ / nthreads;
+ do {
+ if (!unlikely(t->exit_state)) {
+ ticks = cputime_add(virt_ticks(t), left);
+ if (cputime_eq(t->it_virt_expires,
+ cputime_zero) ||
+ cputime_gt(t->it_virt_expires, ticks)) {
+ t->it_virt_expires = ticks;
+ }
+ }
+ t = next_thread(t);
+ } while (t != p);
+ break;
+ case CPUCLOCK_SCHED:
+ nsleft = timer->it.cpu.expires.sched - val.sched;
+ do_div(nsleft, nthreads);
+ do {
+ if (!unlikely(t->exit_state)) {
+ ns = t->sched_time + nsleft;
+ if (t->it_sched_expires == 0 ||
+ t->it_sched_expires > ns) {
+ t->it_sched_expires = ns;
+ }
+ }
+ t = next_thread(t);
+ } while (t != p);
+ break;
+ }
+}
+
+static void clear_dead_task(struct k_itimer *timer, union cpu_time_count now)
+{
+ /*
+ * That's all for this thread or process.
+ * We leave our residual in expires to be reported.
+ */
+ put_task_struct(timer->it.cpu.task);
+ timer->it.cpu.task = NULL;
+ timer->it.cpu.expires = cpu_time_sub(timer->it_clock,
+ timer->it.cpu.expires,
+ now);
+}
+
+/*
+ * Insert the timer on the appropriate list before any timers that
+ * expire later. This must be called with the tasklist_lock held
+ * for reading, and interrupts disabled.
+ */
+static void arm_timer(struct k_itimer *timer, union cpu_time_count now)
+{
+ struct task_struct *p = timer->it.cpu.task;
+ struct list_head *head, *listpos;
+ struct cpu_timer_list *const nt = &timer->it.cpu;
+ struct cpu_timer_list *next;
+
+ head = (CPUCLOCK_PERTHREAD(timer->it_clock) ?
+ p->cpu_timers : p->signal->cpu_timers);
+ head += CPUCLOCK_WHICH(timer->it_clock);
+
+ BUG_ON(!irqs_disabled());
+ spin_lock(&p->sighand->siglock);
+
+ listpos = head;
+ if (CPUCLOCK_WHICH(timer->it_clock) == CPUCLOCK_SCHED) {
+ list_for_each_entry(next, head, entry) {
+ if (next->expires.sched > nt->expires.sched) {
+ listpos = &next->entry;
+ break;
+ }
+ }
+ } else {
+ list_for_each_entry(next, head, entry) {
+ if (cputime_gt(next->expires.cpu, nt->expires.cpu)) {
+ listpos = &next->entry;
+ break;
+ }
+ }
+ }
+ list_add(&nt->entry, listpos);
+
+ if (listpos == head) {
+ /*
+ * We are the new earliest-expiring timer.
+ * If we are a thread timer, there can always
+ * be a process timer telling us to stop earlier.
+ */
+
+ if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
+ switch (CPUCLOCK_WHICH(timer->it_clock)) {
+ default:
+ BUG();
+#define UPDATE_CLOCK(WHICH, c, n) \
+ case CPUCLOCK_##WHICH: \
+ if (p->it_##c##_expires == 0 || \
+ p->it_##c##_expires > nt->expires.n) { \
+ p->it_##c##_expires = nt->expires.n; \
+ } \
+ break
+ UPDATE_CLOCK(PROF, prof, cpu);
+ UPDATE_CLOCK(VIRT, virt, cpu);
+ UPDATE_CLOCK(SCHED, sched, sched);
+#undef UPDATE_CLOCK
+ }
+ } else {
+ /*
+ * For a process timer, we must balance
+ * all the live threads' expirations.
+ */
+ process_timer_rebalance(timer, now);
+ }
+ }
+
+ spin_unlock(&p->sighand->siglock);
+}
+
+/*
+ * The timer is locked, fire it and arrange for its reload.
+ */
+static void cpu_timer_fire(struct k_itimer *timer)
+{
+ if (unlikely(timer->sigq == NULL)) {
+ /*
+ * This a special case for clock_nanosleep,
+ * not a normal timer from sys_timer_create.
+ */
+ wake_up_process(timer->it_process);
+ timer->it.cpu.expires.sched = 0;
+ } else if (timer->it.cpu.incr.sched == 0) {
+ /*
+ * One-shot timer. Clear it as soon as it's fired.
+ */
+ posix_timer_event(timer, 0);
+ timer->it.cpu.expires.sched = 0;
+ } else if (posix_timer_event(timer, ++timer->it_requeue_pending)) {
+ /*
+ * The signal did not get queued because the signal
+ * was ignored, so we won't get any callback to
+ * reload the timer. But we need to keep it
+ * ticking in case the signal is deliverable next time.
+ */
+ posix_cpu_timer_schedule(timer);
+ }
+}
+
+/*
+ * Guts of sys_timer_settime for CPU timers.
+ * This is called with the timer locked and interrupts disabled.
+ * If we return TIMER_RETRY, it's necessary to release the timer's lock
+ * and try again. (This happens when the timer is in the middle of firing.)
+ */
+int posix_cpu_timer_set(struct k_itimer *timer, int flags,
+ struct itimerspec *new, struct itimerspec *old)
+{
+ struct task_struct *p = timer->it.cpu.task;
+ union cpu_time_count old_expires, new_expires, val;
+ int ret;
+
+ if (unlikely(p == NULL)) {
+ /*
+ * Timer refers to a dead task's clock.
+ */
+ return -ESRCH;
+ }
+
+ new_expires = timespec_to_sample(timer->it_clock, &new->it_value);
+
+ read_lock(&tasklist_lock);
+ /*
+ * We need the tasklist_lock to protect against reaping that
+ * clears p->signal. If p has just been reaped, we can no
+ * longer get any information about it at all.
+ */
+ if (unlikely(p->signal == NULL)) {
+ read_unlock(&tasklist_lock);
+ put_task_struct(p);
+ timer->it.cpu.task = NULL;
+ return -ESRCH;
+ }
+
+ /*
+ * Disarm any old timer after extracting its expiry time.
+ */
+ BUG_ON(!irqs_disabled());
+ spin_lock(&p->sighand->siglock);
+ old_expires = timer->it.cpu.expires;
+ list_del_init(&timer->it.cpu.entry);
+ spin_unlock(&p->sighand->siglock);
+
+ /*
+ * We need to sample the current value to convert the new
+ * value from to relative and absolute, and to convert the
+ * old value from absolute to relative. To set a process
+ * timer, we need a sample to balance the thread expiry
+ * times (in arm_timer). With an absolute time, we must
+ * check if it's already passed. In short, we need a sample.
+ */
+ if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
+ cpu_clock_sample(timer->it_clock, p, &val);
+ } else {
+ cpu_clock_sample_group(timer->it_clock, p, &val);
+ }
+
+ if (old) {
+ if (old_expires.sched == 0) {
+ old->it_value.tv_sec = 0;
+ old->it_value.tv_nsec = 0;
+ } else {
+ /*
+ * Update the timer in case it has
+ * overrun already. If it has,
+ * we'll report it as having overrun
+ * and with the next reloaded timer
+ * already ticking, though we are
+ * swallowing that pending
+ * notification here to install the
+ * new setting.
+ */
+ bump_cpu_timer(timer, val);
+ if (cpu_time_before(timer->it_clock, val,
+ timer->it.cpu.expires)) {
+ old_expires = cpu_time_sub(
+ timer->it_clock,
+ timer->it.cpu.expires, val);
+ sample_to_timespec(timer->it_clock,
+ old_expires,
+ &old->it_value);
+ } else {
+ old->it_value.tv_nsec = 1;
+ old->it_value.tv_sec = 0;
+ }
+ }
+ }
+
+ if (unlikely(timer->it.cpu.firing)) {
+ /*
+ * We are colliding with the timer actually firing.
+ * Punt after filling in the timer's old value, and
+ * disable this firing since we are already reporting
+ * it as an overrun (thanks to bump_cpu_timer above).
+ */
+ read_unlock(&tasklist_lock);
+ timer->it.cpu.firing = -1;
+ ret = TIMER_RETRY;
+ goto out;
+ }
+
+ if (new_expires.sched != 0 && !(flags & TIMER_ABSTIME)) {
+ cpu_time_add(timer->it_clock, &new_expires, val);
+ }
+
+ /*
+ * Install the new expiry time (or zero).
+ * For a timer with no notification action, we don't actually
+ * arm the timer (we'll just fake it for timer_gettime).
+ */
+ timer->it.cpu.expires = new_expires;
+ if (new_expires.sched != 0 &&
+ (timer->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE &&
+ cpu_time_before(timer->it_clock, val, new_expires)) {
+ arm_timer(timer, val);
+ }
+
+ read_unlock(&tasklist_lock);
+
+ /*
+ * Install the new reload setting, and
+ * set up the signal and overrun bookkeeping.
+ */
+ timer->it.cpu.incr = timespec_to_sample(timer->it_clock,
+ &new->it_interval);
+
+ /*
+ * This acts as a modification timestamp for the timer,
+ * so any automatic reload attempt will punt on seeing
+ * that we have reset the timer manually.
+ */
+ timer->it_requeue_pending = (timer->it_requeue_pending + 2) &
+ ~REQUEUE_PENDING;
+ timer->it_overrun_last = 0;
+ timer->it_overrun = -1;
+
+ if (new_expires.sched != 0 &&
+ (timer->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE &&
+ !cpu_time_before(timer->it_clock, val, new_expires)) {
+ /*
+ * The designated time already passed, so we notify
+ * immediately, even if the thread never runs to
+ * accumulate more time on this clock.
+ */
+ cpu_timer_fire(timer);
+ }
+
+ ret = 0;
+ out:
+ if (old) {
+ sample_to_timespec(timer->it_clock,
+ timer->it.cpu.incr, &old->it_interval);
+ }
+ return ret;
+}
+
+void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
+{
+ union cpu_time_count now;
+ struct task_struct *p = timer->it.cpu.task;
+ int clear_dead;
+
+ /*
+ * Easy part: convert the reload time.
+ */
+ sample_to_timespec(timer->it_clock,
+ timer->it.cpu.incr, &itp->it_interval);
+
+ if (timer->it.cpu.expires.sched == 0) { /* Timer not armed at all. */
+ itp->it_value.tv_sec = itp->it_value.tv_nsec = 0;
+ return;
+ }
+
+ if (unlikely(p == NULL)) {
+ /*
+ * This task already died and the timer will never fire.
+ * In this case, expires is actually the dead value.
+ */
+ dead:
+ sample_to_timespec(timer->it_clock, timer->it.cpu.expires,
+ &itp->it_value);
+ return;
+ }
+
+ /*
+ * Sample the clock to take the difference with the expiry time.
+ */
+ if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
+ cpu_clock_sample(timer->it_clock, p, &now);
+ clear_dead = p->exit_state;
+ } else {
+ read_lock(&tasklist_lock);
+ if (unlikely(p->signal == NULL)) {
+ /*
+ * The process has been reaped.
+ * We can't even collect a sample any more.
+ * Call the timer disarmed, nothing else to do.
+ */
+ put_task_struct(p);
+ timer->it.cpu.task = NULL;
+ timer->it.cpu.expires.sched = 0;
+ read_unlock(&tasklist_lock);
+ goto dead;
+ } else {
+ cpu_clock_sample_group(timer->it_clock, p, &now);
+ clear_dead = (unlikely(p->exit_state) &&
+ thread_group_empty(p));
+ }
+ read_unlock(&tasklist_lock);
+ }
+
+ if ((timer->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) {
+ if (timer->it.cpu.incr.sched == 0 &&
+ cpu_time_before(timer->it_clock,
+ timer->it.cpu.expires, now)) {
+ /*
+ * Do-nothing timer expired and has no reload,
+ * so it's as if it was never set.
+ */
+ timer->it.cpu.expires.sched = 0;
+ itp->it_value.tv_sec = itp->it_value.tv_nsec = 0;
+ return;
+ }
+ /*
+ * Account for any expirations and reloads that should
+ * have happened.
+ */
+ bump_cpu_timer(timer, now);
+ }
+
+ if (unlikely(clear_dead)) {
+ /*
+ * We've noticed that the thread is dead, but
+ * not yet reaped. Take this opportunity to
+ * drop our task ref.
+ */
+ clear_dead_task(timer, now);
+ goto dead;
+ }
+
+ if (cpu_time_before(timer->it_clock, now, timer->it.cpu.expires)) {
+ sample_to_timespec(timer->it_clock,
+ cpu_time_sub(timer->it_clock,
+ timer->it.cpu.expires, now),
+ &itp->it_value);
+ } else {
+ /*
+ * The timer should have expired already, but the firing
+ * hasn't taken place yet. Say it's just about to expire.
+ */
+ itp->it_value.tv_nsec = 1;
+ itp->it_value.tv_sec = 0;
+ }
+}
+
+/*
+ * Check for any per-thread CPU timers that have fired and move them off
+ * the tsk->cpu_timers[N] list onto the firing list. Here we update the
+ * tsk->it_*_expires values to reflect the remaining thread CPU timers.
+ */
+static void check_thread_timers(struct task_struct *tsk,
+ struct list_head *firing)
+{
+ struct list_head *timers = tsk->cpu_timers;
+
+ tsk->it_prof_expires = 0;
+ while (!list_empty(timers)) {
+ struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list,
+ entry);
+ if (cputime_lt(prof_ticks(tsk), t->expires.cpu)) {
+ tsk->it_prof_expires = t->expires.cpu;
+ break;
+ }
+ t->firing = 1;
+ list_move_tail(&t->entry, firing);
+ }
+
+ ++timers;
+ tsk->it_virt_expires = 0;
+ while (!list_empty(timers)) {
+ struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list,
+ entry);
+ if (cputime_lt(virt_ticks(tsk), t->expires.cpu)) {
+ tsk->it_virt_expires = t->expires.cpu;
+ break;
+ }
+ t->firing = 1;
+ list_move_tail(&t->entry, firing);
+ }
+
+ ++timers;
+ tsk->it_sched_expires = 0;
+ while (!list_empty(timers)) {
+ struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list,
+ entry);
+ if (tsk->sched_time < t->expires.sched) {
+ tsk->it_sched_expires = t->expires.sched;
+ break;
+ }
+ t->firing = 1;
+ list_move_tail(&t->entry, firing);
+ }
+}
+
+/*
+ * Check for any per-thread CPU timers that have fired and move them
+ * off the tsk->*_timers list onto the firing list. Per-thread timers
+ * have already been taken off.
+ */
+static void check_process_timers(struct task_struct *tsk,
+ struct list_head *firing)
+{
+ struct signal_struct *const sig = tsk->signal;
+ cputime_t utime, stime, ptime, virt_expires, prof_expires;
+ unsigned long long sched_time, sched_expires;
+ struct task_struct *t;
+ struct list_head *timers = sig->cpu_timers;
+
+ /*
+ * Don't sample the current process CPU clocks if there are no timers.
+ */
+ if (list_empty(&timers[CPUCLOCK_PROF]) &&
+ list_empty(&timers[CPUCLOCK_VIRT]) &&
+ list_empty(&timers[CPUCLOCK_SCHED]))
+ return;
+
+ /*
+ * Collect the current process totals.
+ */
+ utime = sig->utime;
+ stime = sig->stime;
+ sched_time = sig->sched_time;
+ t = tsk;
+ do {
+ utime = cputime_add(utime, t->utime);
+ stime = cputime_add(stime, t->stime);
+ sched_time += t->sched_time;
+ t = next_thread(t);
+ } while (t != tsk);
+ ptime = cputime_add(utime, stime);
+
+ prof_expires = cputime_zero;
+ while (!list_empty(timers)) {
+ struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list,
+ entry);
+ if (cputime_lt(ptime, t->expires.cpu)) {
+ prof_expires = t->expires.cpu;
+ break;
+ }
+ t->firing = 1;
+ list_move_tail(&t->entry, firing);
+ }
+
+ ++timers;
+ virt_expires = cputime_zero;
+ while (!list_empty(timers)) {
+ struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list,
+ entry);
+ if (cputime_lt(utime, t->expires.cpu)) {
+ virt_expires = t->expires.cpu;
+ break;
+ }
+ t->firing = 1;
+ list_move_tail(&t->entry, firing);
+ }
+
+ ++timers;
+ sched_expires = cputime_zero;
+ while (!list_empty(timers)) {
+ struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list,
+ entry);
+ if (sched_time < t->expires.sched) {
+ sched_expires = t->expires.sched;
+ break;
+ }
+ t->firing = 1;
+ list_move_tail(&t->entry, firing);
+ }
+
+ if (!cputime_eq(prof_expires, cputime_zero) ||
+ !cputime_eq(virt_expires, cputime_zero) ||
+ sched_expires != 0) {
+ /*
+ * Rebalance the threads' expiry times for the remaining
+ * process CPU timers.
+ */
+
+ cputime_t prof_left, virt_left, ticks;
+ unsigned long long sched_left, sched;
+ const unsigned int nthreads = atomic_read(&sig->live);
+
+ prof_left = cputime_sub(prof_expires,
+ cputime_add(utime, stime)) / nthreads;
+ virt_left = cputime_sub(virt_expires, utime) / nthreads;
+ if (sched_expires) {
+ sched_left = sched_expires - sched_time;
+ do_div(sched_left, nthreads);
+ } else {
+ sched_left = 0;
+ }
+ t = tsk;
+ do {
+ ticks = cputime_add(cputime_add(t->utime, t->stime),
+ prof_left);
+ if (!cputime_eq(prof_expires, cputime_zero) &&
+ (cputime_eq(t->it_prof_expires, cputime_zero) ||
+ cputime_gt(t->it_prof_expires, ticks))) {
+ t->it_prof_expires = ticks;
+ }
+
+ ticks = cputime_add(t->utime, virt_left);
+ if (!cputime_eq(virt_expires, cputime_zero) &&
+ (cputime_eq(t->it_virt_expires, cputime_zero) ||
+ cputime_gt(t->it_virt_expires, ticks))) {
+ t->it_virt_expires = ticks;
+ }
+
+ sched = t->sched_time + sched_left;
+ if (sched_expires && (t->it_sched_expires == 0 ||
+ t->it_sched_expires > sched)) {
+ t->it_sched_expires = sched;
+ }
+
+ do {
+ t = next_thread(t);
+ } while (unlikely(t->exit_state));
+ } while (t != tsk);
+ }
}
-void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *spec)
+
+/*
+ * This is called from the signal code (via do_schedule_next_timer)
+ * when the last timer signal was delivered and we have to reload the timer.
+ */
+void posix_cpu_timer_schedule(struct k_itimer *timer)
{
- BUG();
+ struct task_struct *p = timer->it.cpu.task;
+ union cpu_time_count now;
+
+ if (unlikely(p == NULL))
+ /*
+ * The task was cleaned up already, no future firings.
+ */
+ return;
+
+ /*
+ * Fetch the current sample and update the timer's expiry time.
+ */
+ if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
+ cpu_clock_sample(timer->it_clock, p, &now);
+ bump_cpu_timer(timer, now);
+ if (unlikely(p->exit_state)) {
+ clear_dead_task(timer, now);
+ return;
+ }
+ read_lock(&tasklist_lock); /* arm_timer needs it. */
+ } else {
+ read_lock(&tasklist_lock);
+ if (unlikely(p->signal == NULL)) {
+ /*
+ * The process has been reaped.
+ * We can't even collect a sample any more.
+ */
+ put_task_struct(p);
+ timer->it.cpu.task = p = NULL;
+ timer->it.cpu.expires.sched = 0;
+ read_unlock(&tasklist_lock);
+ return;
+ } else if (unlikely(p->exit_state) && thread_group_empty(p)) {
+ /*
+ * We've noticed that the thread is dead, but
+ * not yet reaped. Take this opportunity to
+ * drop our task ref.
+ */
+ clear_dead_task(timer, now);
+ read_unlock(&tasklist_lock);
+ return;
+ }
+ cpu_clock_sample_group(timer->it_clock, p, &now);
+ bump_cpu_timer(timer, now);
+ /* Leave the tasklist_lock locked for the call below. */
+ }
+
+ /*
+ * Now re-arm for the new expiry time.
+ */
+ arm_timer(timer, now);
+
+ read_unlock(&tasklist_lock);
+}
+
+/*
+ * This is called from the timer interrupt handler. The irq handler has
+ * already updated our counts. We need to check if any timers fire now.
+ * Interrupts are disabled.
+ */
+void run_posix_cpu_timers(struct task_struct *tsk)
+{
+ LIST_HEAD(firing);
+ struct k_itimer *timer, *next;
+
+ BUG_ON(!irqs_disabled());
+
+#define UNEXPIRED(clock) \
+ (tsk->it_##clock##_expires == 0 || \
+ cputime_lt(clock##_ticks(tsk), tsk->it_##clock##_expires))
+
+ if (UNEXPIRED(prof) && UNEXPIRED(virt) &&
+ (tsk->it_sched_expires == 0 ||
+ tsk->sched_time < tsk->it_sched_expires))
+ return;
+
+#undef UNEXPIRED
+
+ BUG_ON(tsk->exit_state);
+
+ /*
+ * Double-check with locks held.
+ */
+ read_lock(&tasklist_lock);
+ spin_lock(&tsk->sighand->siglock);
+
+ /*
+ * Here we take off tsk->cpu_timers[N] and tsk->signal->cpu_timers[N]
+ * all the timers that are firing, and put them on the firing list.
+ */
+ check_thread_timers(tsk, &firing);
+ check_process_timers(tsk, &firing);
+
+ /*
+ * We must release these locks before taking any timer's lock.
+ * There is a potential race with timer deletion here, as the
+ * siglock now protects our private firing list. We have set
+ * the firing flag in each timer, so that a deletion attempt
+ * that gets the timer lock before we do will give it up and
+ * spin until we've taken care of that timer below.
+ */
+ spin_unlock(&tsk->sighand->siglock);
+ read_unlock(&tasklist_lock);
+
+ /*
+ * Now that all the timers on our list have the firing flag,
+ * noone will touch their list entries but us. We'll take
+ * each timer's lock before clearing its firing flag, so no
+ * timer call will interfere.
+ */
+ list_for_each_entry_safe(timer, next, &firing, it.cpu.entry) {
+ int firing;
+ spin_lock(&timer->it_lock);
+ list_del_init(&timer->it.cpu.entry);
+ firing = timer->it.cpu.firing;
+ timer->it.cpu.firing = 0;
+ /*
+ * The firing flag is -1 if we collided with a reset
+ * of the timer, which already reported this
+ * almost-firing as an overrun. So don't generate an event.
+ */
+ if (likely(firing >= 0)) {
+ cpu_timer_fire(timer);
+ }
+ spin_unlock(&timer->it_lock);
+ }
+}
+
+static long posix_cpu_clock_nanosleep_restart(struct restart_block *);
+
+int posix_cpu_nsleep(clockid_t which_clock, int flags,
+ struct timespec *rqtp)
+{
+ struct restart_block *restart_block =
+ &current_thread_info()->restart_block;
+ struct k_itimer timer;
+ int error;
+
+ /*
+ * Diagnose required errors first.
+ */
+ if (CPUCLOCK_PERTHREAD(which_clock) &&
+ (CPUCLOCK_PID(which_clock) == 0 ||
+ CPUCLOCK_PID(which_clock) == current->pid))
+ return -EINVAL;
+
+ /*
+ * Set up a temporary timer and then wait for it to go off.
+ */
+ memset(&timer, 0, sizeof timer);
+ spin_lock_init(&timer.it_lock);
+ timer.it_clock = which_clock;
+ timer.it_overrun = -1;
+ error = posix_cpu_timer_create(&timer);
+ timer.it_process = current;
+ if (!error) {
+ struct timespec __user *rmtp;
+ static struct itimerspec zero_it;
+ struct itimerspec it = { .it_value = *rqtp,
+ .it_interval = {} };
+
+ spin_lock_irq(&timer.it_lock);
+ error = posix_cpu_timer_set(&timer, flags, &it, NULL);
+ if (error) {
+ spin_unlock_irq(&timer.it_lock);
+ return error;
+ }
+
+ while (!signal_pending(current)) {
+ if (timer.it.cpu.expires.sched == 0) {
+ /*
+ * Our timer fired and was reset.
+ */
+ spin_unlock_irq(&timer.it_lock);
+ return 0;
+ }
+
+ /*
+ * Block until cpu_timer_fire (or a signal) wakes us.
+ */
+ __set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&timer.it_lock);
+ schedule();
+ spin_lock_irq(&timer.it_lock);
+ }
+
+ /*
+ * We were interrupted by a signal.
+ */
+ sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp);
+ posix_cpu_timer_set(&timer, 0, &zero_it, &it);
+ spin_unlock_irq(&timer.it_lock);
+
+ if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) {
+ /*
+ * It actually did fire already.
+ */
+ return 0;
+ }
+
+ /*
+ * Report back to the user the time still remaining.
+ */
+ rmtp = (struct timespec __user *) restart_block->arg1;
+ if (rmtp != NULL && !(flags & TIMER_ABSTIME) &&
+ copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
+ return -EFAULT;
+
+ restart_block->fn = posix_cpu_clock_nanosleep_restart;
+ /* Caller already set restart_block->arg1 */
+ restart_block->arg0 = which_clock;
+ restart_block->arg2 = rqtp->tv_sec;
+ restart_block->arg3 = rqtp->tv_nsec;
+
+ error = -ERESTART_RESTARTBLOCK;
+ }
+
+ return error;
+}
+
+static long
+posix_cpu_clock_nanosleep_restart(struct restart_block *restart_block)
+{
+ clockid_t which_clock = restart_block->arg0;
+ struct timespec t = { .tv_sec = restart_block->arg2,
+ .tv_nsec = restart_block->arg3 };
+ restart_block->fn = do_no_restart_syscall;
+ return posix_cpu_nsleep(which_clock, TIMER_ABSTIME, &t);
}


@@ -253,6 +1311,16 @@ static int process_cpu_clock_get(clockid
{
return posix_cpu_clock_get(PROCESS_CLOCK, tp);
}
+static int process_cpu_timer_create(struct k_itimer *timer)
+{
+ timer->it_clock = PROCESS_CLOCK;
+ return posix_cpu_timer_create(timer);
+}
+static int process_cpu_nsleep(clockid_t which_clock, int flags,
+ struct timespec *rqtp)
+{
+ return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp);
+}
static int thread_cpu_clock_getres(clockid_t which_clock, struct timespec *tp)
{
return posix_cpu_clock_getres(THREAD_CLOCK, tp);
@@ -261,7 +1329,16 @@ static int thread_cpu_clock_get(clockid_
{
return posix_cpu_clock_get(THREAD_CLOCK, tp);
}
-
+static int thread_cpu_timer_create(struct k_itimer *timer)
+{
+ timer->it_clock = THREAD_CLOCK;
+ return posix_cpu_timer_create(timer);
+}
+static int thread_cpu_nsleep(clockid_t which_clock, int flags,
+ struct timespec *rqtp)
+{
+ return -EINVAL;
+}

static __init int init_posix_cpu_timers(void)
{
@@ -269,15 +1346,15 @@ static __init int init_posix_cpu_timers(
.clock_getres = process_cpu_clock_getres,
.clock_get = process_cpu_clock_get,
.clock_set = do_posix_clock_nosettime,
- .timer_create = do_posix_clock_notimer_create,
- .nsleep = do_posix_clock_nonanosleep,
+ .timer_create = process_cpu_timer_create,
+ .nsleep = process_cpu_nsleep,
};
struct k_clock thread = {
.clock_getres = thread_cpu_clock_getres,
.clock_get = thread_cpu_clock_get,
.clock_set = do_posix_clock_nosettime,
- .timer_create = do_posix_clock_notimer_create,
- .nsleep = do_posix_clock_nonanosleep,
+ .timer_create = thread_cpu_timer_create,
+ .nsleep = thread_cpu_nsleep,
};

register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
--- linux-2.6/kernel/posix-timers.c
+++ linux-2.6/kernel/posix-timers.c
@@ -92,14 +92,13 @@ static DEFINE_SPINLOCK(idr_lock);
* inactive. It could be in the "fire" routine getting a new expire time.
*/
#define TIMER_INACTIVE 1
-#define TIMER_RETRY 1

#ifdef CONFIG_SMP
# define timer_active(tmr) \
- ((tmr)->it_timer.entry.prev != (void *)TIMER_INACTIVE)
+ ((tmr)->it.real.timer.entry.prev != (void *)TIMER_INACTIVE)
# define set_timer_inactive(tmr) \
do { \
- (tmr)->it_timer.entry.prev = (void *)TIMER_INACTIVE; \
+ (tmr)->it.real.timer.entry.prev = (void *)TIMER_INACTIVE; \
} while (0)
#else
# define timer_active(tmr) BARFY // error to use outside of SMP
@@ -115,7 +114,6 @@ static DEFINE_SPINLOCK(idr_lock);
#endif


-#define REQUEUE_PENDING 1
/*
* The timer ID is turned into a timer address by idr_find().
* Verifying a valid ID consists of:
@@ -241,10 +239,11 @@ COMMONDEFN int common_clock_set(clockid_

COMMONDEFN int common_timer_create(struct k_itimer *new_timer)
{
- init_timer(&new_timer->it_timer);
- new_timer->it_timer.expires = 0;
- new_timer->it_timer.data = (unsigned long) new_timer;
- new_timer->it_timer.function = posix_timer_fn;
+ new_timer->it.real.incr = 0;
+ init_timer(&new_timer->it.real.timer);
+ new_timer->it.real.timer.expires = 0;
+ new_timer->it.real.timer.data = (unsigned long) new_timer;
+ new_timer->it.real.timer.function = posix_timer_fn;
set_timer_inactive(new_timer);
return 0;
}
@@ -360,9 +359,9 @@ static long add_clockset_delta(struct k_

set_normalized_timespec(&delta,
new_wall_to->tv_sec -
- timr->wall_to_prev.tv_sec,
+ timr->it.real.wall_to_prev.tv_sec,
new_wall_to->tv_nsec -
- timr->wall_to_prev.tv_nsec);
+ timr->it.real.wall_to_prev.tv_nsec);
if (likely(!(delta.tv_sec | delta.tv_nsec)))
return 0;
if (delta.tv_sec < 0) {
@@ -373,16 +372,16 @@ static long add_clockset_delta(struct k_
sign++;
}
tstojiffie(&delta, posix_clocks[timr->it_clock].res, &exp);
- timr->wall_to_prev = *new_wall_to;
- timr->it_timer.expires += (sign ? -exp : exp);
+ timr->it.real.wall_to_prev = *new_wall_to;
+ timr->it.real.timer.expires += (sign ? -exp : exp);
return 1;
}

static void remove_from_abslist(struct k_itimer *timr)
{
- if (!list_empty(&timr->abs_timer_entry)) {
+ if (!list_empty(&timr->it.real.abs_timer_entry)) {
spin_lock(&abs_list.lock);
- list_del_init(&timr->abs_timer_entry);
+ list_del_init(&timr->it.real.abs_timer_entry);
spin_unlock(&abs_list.lock);
}
}
@@ -396,7 +395,7 @@ static void schedule_next_timer(struct k
/*
* Set up the timer for the next interval (if there is one).
* Note: this code uses the abs_timer_lock to protect
- * wall_to_prev and must hold it until exp is set, not exactly
+ * it.real.wall_to_prev and must hold it until exp is set, not exactly
* obvious...

* This function is used for CLOCK_REALTIME* and
@@ -406,7 +405,7 @@ static void schedule_next_timer(struct k
* "other" CLOCKs "next timer" code (which, I suppose should
* also be added to the k_clock structure).
*/
- if (!timr->it_incr)
+ if (!timr->it.real.incr)
return;

do {
@@ -415,7 +414,7 @@ static void schedule_next_timer(struct k
posix_get_now(&now);
} while (read_seqretry(&xtime_lock, seq));

- if (!list_empty(&timr->abs_timer_entry)) {
+ if (!list_empty(&timr->it.real.abs_timer_entry)) {
spin_lock(&abs_list.lock);
add_clockset_delta(timr, &new_wall_to);

@@ -428,7 +427,7 @@ static void schedule_next_timer(struct k
timr->it_overrun_last = timr->it_overrun;
timr->it_overrun = -1;
++timr->it_requeue_pending;
- add_timer(&timr->it_timer);
+ add_timer(&timr->it.real.timer);
}

/*
@@ -452,7 +451,10 @@ void do_schedule_next_timer(struct sigin
if (!timr || timr->it_requeue_pending != info->si_sys_private)
goto exit;

- schedule_next_timer(timr);
+ if (timr->it_clock < 0) /* CPU clock */
+ posix_cpu_timer_schedule(timr);
+ else
+ schedule_next_timer(timr);
info->si_overrun = timr->it_overrun_last;
exit:
if (timr)
@@ -512,7 +514,7 @@ static void posix_timer_fn(unsigned long

spin_lock_irqsave(&timr->it_lock, flags);
set_timer_inactive(timr);
- if (!list_empty(&timr->abs_timer_entry)) {
+ if (!list_empty(&timr->it.real.abs_timer_entry)) {
spin_lock(&abs_list.lock);
do {
seq = read_seqbegin(&xtime_lock);
@@ -520,9 +522,9 @@ static void posix_timer_fn(unsigned long
} while (read_seqretry(&xtime_lock, seq));
set_normalized_timespec(&delta,
new_wall_to.tv_sec -
- timr->wall_to_prev.tv_sec,
+ timr->it.real.wall_to_prev.tv_sec,
new_wall_to.tv_nsec -
- timr->wall_to_prev.tv_nsec);
+ timr->it.real.wall_to_prev.tv_nsec);
if (likely((delta.tv_sec | delta.tv_nsec ) == 0)) {
/* do nothing, timer is on time */
} else if (delta.tv_sec < 0) {
@@ -532,9 +534,9 @@ static void posix_timer_fn(unsigned long
tstojiffie(&delta,
posix_clocks[timr->it_clock].res,
&exp);
- timr->wall_to_prev = new_wall_to;
- timr->it_timer.expires += exp;
- add_timer(&timr->it_timer);
+ timr->it.real.wall_to_prev = new_wall_to;
+ timr->it.real.timer.expires += exp;
+ add_timer(&timr->it.real.timer);
do_notify = 0;
}
spin_unlock(&abs_list.lock);
@@ -543,7 +545,7 @@ static void posix_timer_fn(unsigned long
if (do_notify) {
int si_private=0;

- if (timr->it_incr)
+ if (timr->it.real.incr)
si_private = ++timr->it_requeue_pending;
else {
remove_from_abslist(timr);
@@ -597,7 +599,7 @@ static struct k_itimer * alloc_posix_tim
if (!tmr)
return tmr;
memset(tmr, 0, sizeof (struct k_itimer));
- INIT_LIST_HEAD(&tmr->abs_timer_entry);
+ INIT_LIST_HEAD(&tmr->it.real.abs_timer_entry);
if (unlikely(!(tmr->sigq = sigqueue_alloc()))) {
kmem_cache_free(posix_timers_cache, tmr);
tmr = NULL;
@@ -669,7 +671,6 @@ sys_timer_create(clockid_t which_clock,
it_id_set = IT_ID_SET;
new_timer->it_id = (timer_t) new_timer_id;
new_timer->it_clock = which_clock;
- new_timer->it_incr = 0;
new_timer->it_overrun = -1;
error = CLOCK_DISPATCH(which_clock, timer_create, (new_timer));
if (error)
@@ -830,30 +831,30 @@ common_timer_get(struct k_itimer *timr,
struct now_struct now;

do
- expires = timr->it_timer.expires;
- while ((volatile long) (timr->it_timer.expires) != expires);
+ expires = timr->it.real.timer.expires;
+ while ((volatile long) (timr->it.real.timer.expires) != expires);

posix_get_now(&now);

if (expires &&
((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) &&
- !timr->it_incr &&
- posix_time_before(&timr->it_timer, &now))
- timr->it_timer.expires = expires = 0;
+ !timr->it.real.incr &&
+ posix_time_before(&timr->it.real.timer, &now))
+ timr->it.real.timer.expires = expires = 0;
if (expires) {
if (timr->it_requeue_pending & REQUEUE_PENDING ||
(timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) {
posix_bump_timer(timr, now);
- expires = timr->it_timer.expires;
+ expires = timr->it.real.timer.expires;
}
else
- if (!timer_pending(&timr->it_timer))
+ if (!timer_pending(&timr->it.real.timer))
expires = 0;
if (expires)
expires -= now.jiffies;
}
jiffies_to_timespec(expires, &cur_setting->it_value);
- jiffies_to_timespec(timr->it_incr, &cur_setting->it_interval);
+ jiffies_to_timespec(timr->it.real.incr, &cur_setting->it_interval);

if (cur_setting->it_value.tv_sec < 0) {
cur_setting->it_value.tv_nsec = 1;
@@ -1007,13 +1008,13 @@ common_timer_set(struct k_itimer *timr,
common_timer_get(timr, old_setting);

/* disable the timer */
- timr->it_incr = 0;
+ timr->it.real.incr = 0;
/*
* careful here. If smp we could be in the "fire" routine which will
* be spinning as we hold the lock. But this is ONLY an SMP issue.
*/
#ifdef CONFIG_SMP
- if (timer_active(timr) && !del_timer(&timr->it_timer))
+ if (timer_active(timr) && !del_timer(&timr->it.real.timer))
/*
* It can only be active if on an other cpu. Since
* we have cleared the interval stuff above, it should
@@ -1026,7 +1027,7 @@ common_timer_set(struct k_itimer *timr,

set_timer_inactive(timr);
#else
- del_timer(&timr->it_timer);
+ del_timer(&timr->it.real.timer);
#endif
remove_from_abslist(timr);

@@ -1038,29 +1039,29 @@ common_timer_set(struct k_itimer *timr,
*switch off the timer when it_value is zero
*/
if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec) {
- timr->it_timer.expires = 0;
+ timr->it.real.timer.expires = 0;
return 0;
}

if (adjust_abs_time(clock,
&new_setting->it_value, flags & TIMER_ABSTIME,
- &expire_64, &(timr->wall_to_prev))) {
+ &expire_64, &(timr->it.real.wall_to_prev))) {
return -EINVAL;
}
- timr->it_timer.expires = (unsigned long)expire_64;
+ timr->it.real.timer.expires = (unsigned long)expire_64;
tstojiffie(&new_setting->it_interval, clock->res, &expire_64);
- timr->it_incr = (unsigned long)expire_64;
+ timr->it.real.incr = (unsigned long)expire_64;

/*
* We do not even queue SIGEV_NONE timers! But we do put them
* in the abs list so we can do that right.
*/
if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE))
- add_timer(&timr->it_timer);
+ add_timer(&timr->it.real.timer);

if (flags & TIMER_ABSTIME && clock->abs_struct) {
spin_lock(&clock->abs_struct->lock);
- list_add_tail(&(timr->abs_timer_entry),
+ list_add_tail(&(timr->it.real.abs_timer_entry),
&(clock->abs_struct->list));
spin_unlock(&clock->abs_struct->lock);
}
@@ -1111,9 +1112,9 @@ retry:

COMMONDEFN int common_timer_del(struct k_itimer *timer)
{
- timer->it_incr = 0;
+ timer->it.real.incr = 0;
#ifdef CONFIG_SMP
- if (timer_active(timer) && !del_timer(&timer->it_timer))
+ if (timer_active(timer) && !del_timer(&timer->it.real.timer))
/*
* It can only be active if on an other cpu. Since
* we have cleared the interval stuff above, it should
@@ -1124,7 +1125,7 @@ COMMONDEFN int common_timer_del(struct k
*/
return TIMER_RETRY;
#else
- del_timer(&timer->it_timer);
+ del_timer(&timer->it.real.timer);
#endif
remove_from_abslist(timer);

@@ -1446,13 +1447,13 @@ void clock_was_set(void)
break;
}
timr = list_entry(cws_list.next, struct k_itimer,
- abs_timer_entry);
+ it.real.abs_timer_entry);

- list_del_init(&timr->abs_timer_entry);
+ list_del_init(&timr->it.real.abs_timer_entry);
if (add_clockset_delta(timr, &new_wall_to) &&
- del_timer(&timr->it_timer)) /* timer run yet? */
- add_timer(&timr->it_timer);
- list_add(&timr->abs_timer_entry, &abs_list.list);
+ del_timer(&timr->it.real.timer)) /* timer run yet? */
+ add_timer(&timr->it.real.timer);
+ list_add(&timr->it.real.abs_timer_entry, &abs_list.list);
spin_unlock_irq(&abs_list.lock);
} while (1);

@@ -1480,13 +1481,13 @@ sys_clock_nanosleep(clockid_t which_cloc
if ((unsigned) t.tv_nsec >= NSEC_PER_SEC || t.tv_sec < 0)
return -EINVAL;

- ret = CLOCK_DISPATCH(which_clock, nsleep, (which_clock, flags, &t));
-
/*
- * Do this here as common_nsleep does not have the real address
+ * Do this here as nsleep function does not have the real address.
*/
restart_block->arg1 = (unsigned long)rmtp;

+ ret = CLOCK_DISPATCH(which_clock, nsleep, (which_clock, flags, &t));
+
if ((ret == -ERESTART_RESTARTBLOCK) && rmtp &&
copy_to_user(rmtp, &t, sizeof (t)))
return -EFAULT;
--- linux-2.6/kernel/signal.c
+++ linux-2.6/kernel/signal.c
@@ -22,6 +22,7 @@
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/ptrace.h>
+#include <linux/posix-timers.h>
#include <asm/param.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -347,7 +348,9 @@ void __exit_signal(struct task_struct *t
if (!atomic_read(&sig->count))
BUG();
spin_lock(&sighand->siglock);
+ posix_cpu_timers_exit(tsk);
if (atomic_dec_and_test(&sig->count)) {
+ posix_cpu_timers_exit_group(tsk);
if (tsk == sig->curr_target)
sig->curr_target = next_thread(tsk);
tsk->signal = NULL;
--- linux-2.6/kernel/timer.c
+++ linux-2.6/kernel/timer.c
@@ -30,6 +30,7 @@
#include <linux/thread_info.h>
#include <linux/time.h>
#include <linux/jiffies.h>
+#include <linux/posix-timers.h>
#include <linux/cpu.h>
#include <linux/syscalls.h>

@@ -824,6 +825,7 @@ void update_process_times(int user_tick)
if (rcu_pending(cpu))
rcu_check_callbacks(cpu, user_tick);
scheduler_tick();
+ run_posix_cpu_timers(p);
}

/*


2005-01-25 02:38:39

by George Anzinger

[permalink] [raw]
Subject: Re: [PATCH 4/7] posix-timers: CPU clock support for POSIX timers

Roland McGrath wrote:
> POSIX requires that when you claim _POSIX_CPUTIME and _POSIX_THREAD_CPUTIME,
> not only the clock_* calls but also timer_* calls must support the thread
> and process CPU time clocks. This patch provides that support, building on
> my recent additions to support these clocks in the POSIX clock_* interfaces.
> This patch will not work without those changes, as well as the patch fixing
> the timer lock-siglock deadlock problem.
>
> The apparent pervasive changes to posix-timers.c are simply that some
> fields of struct k_itimer have changed name and moved into a union.
> This was appropriate since the data structures required for the existing
> real-time timer support and for the new thread/process CPU-time timers are
> quite different.

Possibly you could bury these name changes in defines. I suspect the code would
be easier to read and that we really don't need to be reminded that it is a
union on each reference.


--
George Anzinger [email protected]
High-res-timers: http://sourceforge.net/projects/high-res-timers/

2005-01-25 02:40:24

by Christoph Lameter

[permalink] [raw]
Subject: Re: [PATCH 4/7] posix-timers: CPU clock support for POSIX timers

On Mon, 24 Jan 2005, George Anzinger wrote:

> > The apparent pervasive changes to posix-timers.c are simply that some
> > fields of struct k_itimer have changed name and moved into a union.
> > This was appropriate since the data structures required for the existing
> > real-time timer support and for the new thread/process CPU-time timers are
> > quite different.
>
> Possibly you could bury these name changes in defines. I suspect the code would
> be easier to read and that we really don't need to be reminded that it is a
> union on each reference.

It would be great to have a kind of private field that other clocks (like
clock drivers) could use for their purposes. mmtimer f.e. does use some
of the fields for the tick based timers for its purposes.

2005-01-25 22:55:53

by Christoph Lameter

[permalink] [raw]
Subject: Re: [PATCH 4/7] posix-timers: CPU clock support for POSIX timers

On Mon, 24 Jan 2005, Christoph Lameter wrote:

> It would be great to have a kind of private field that other clocks (like
> clock drivers) could use for their purposes. mmtimer f.e. does use some
> of the fields for the tick based timers for its purposes.

On that note:

Your patch breaks the mmtimer driver because it used k_itimer values for
its own purposes. Here is a fix by defining an additional structure
in k_itimer (same approach for mmtimer as the cpu timers):

Signed-off-by: Christoph Lameter <[email protected]>

Index: linux-2.6.10/include/linux/posix-timers.h
===================================================================
--- linux-2.6.10.orig/include/linux/posix-timers.h 2005-01-25 14:35:11.000000000 -0800
+++ linux-2.6.10/include/linux/posix-timers.h 2005-01-25 14:35:16.000000000 -0800
@@ -57,6 +57,12 @@ struct k_itimer {
unsigned long incr; /* interval in jiffies */
} real;
struct cpu_timer_list cpu;
+ struct {
+ unsigned int clock;
+ unsigned int node;
+ unsigned long incr;
+ unsigned long expires;
+ } mmtimer;
} it;
};

Index: linux-2.6.10/drivers/char/mmtimer.c
===================================================================
--- linux-2.6.10.orig/drivers/char/mmtimer.c 2005-01-25 14:35:09.000000000 -0800
+++ linux-2.6.10/drivers/char/mmtimer.c 2005-01-25 14:34:41.000000000 -0800
@@ -420,19 +420,19 @@ static int inline reschedule_periodic_ti
int n;
struct k_itimer *t = x->timer;

- t->it_timer.magic = x->i;
+ t->it.mmtimer.clock = x->i;
t->it_overrun--;

n = 0;
do {

- t->it_timer.expires += t->it_incr << n;
+ t->it.mmtimer.expires += t->it.mmtimer.incr << n;
t->it_overrun += 1 << n;
n++;
if (n > 20)
return 1;

- } while (mmtimer_setup(x->i, t->it_timer.expires));
+ } while (mmtimer_setup(x->i, t->it.mmtimer.expires));

return 0;
}
@@ -468,7 +468,7 @@ mmtimer_interrupt(int irq, void *dev_id,
spin_lock(&base[i].lock);
if (base[i].cpu == smp_processor_id()) {
if (base[i].timer)
- expires = base[i].timer->it_timer.expires;
+ expires = base[i].timer->it.mmtimer.expires;
/* expires test won't work with shared irqs */
if ((mmtimer_int_pending(i) > 0) ||
(expires && (expires < rtc_time()))) {
@@ -505,7 +505,7 @@ void mmtimer_tasklet(unsigned long data)

t->it_overrun++;
}
- if(t->it_incr) {
+ if(t->it.mmtimer.incr) {
/* Periodic timer */
if (reschedule_periodic_timer(x)) {
printk(KERN_WARNING "mmtimer: unable to reschedule\n");
@@ -513,7 +513,7 @@ void mmtimer_tasklet(unsigned long data)
}
} else {
/* Ensure we don't false trigger in mmtimer_interrupt */
- t->it_timer.expires = 0;
+ t->it.mmtimer.expires = 0;
}
t->it_overrun_last = t->it_overrun;
out:
@@ -524,7 +524,7 @@ out:
static int sgi_timer_create(struct k_itimer *timer)
{
/* Insure that a newly created timer is off */
- timer->it_timer.magic = TIMER_OFF;
+ timer->it.mmtimer.clock = TIMER_OFF;
return 0;
}

@@ -535,8 +535,8 @@ static int sgi_timer_create(struct k_iti
*/
static int sgi_timer_del(struct k_itimer *timr)
{
- int i = timr->it_timer.magic;
- cnodeid_t nodeid = timr->it_timer.data;
+ int i = timr->it.mmtimer.clock;
+ cnodeid_t nodeid = timr->it.mmtimer.node;
mmtimer_t *t = timers + nodeid * NUM_COMPARATORS +i;
unsigned long irqflags;

@@ -544,8 +544,8 @@ static int sgi_timer_del(struct k_itimer
spin_lock_irqsave(&t->lock, irqflags);
mmtimer_disable_int(cnodeid_to_nasid(nodeid),i);
t->timer = NULL;
- timr->it_timer.magic = TIMER_OFF;
- timr->it_timer.expires = 0;
+ timr->it.mmtimer.clock = TIMER_OFF;
+ timr->it.mmtimer.expires = 0;
spin_unlock_irqrestore(&t->lock, irqflags);
}
return 0;
@@ -558,7 +558,7 @@ static int sgi_timer_del(struct k_itimer
static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
{

- if (timr->it_timer.magic == TIMER_OFF) {
+ if (timr->it.mmtimer.clock == TIMER_OFF) {
cur_setting->it_interval.tv_nsec = 0;
cur_setting->it_interval.tv_sec = 0;
cur_setting->it_value.tv_nsec = 0;
@@ -566,8 +566,8 @@ static void sgi_timer_get(struct k_itime
return;
}

- ns_to_timespec(cur_setting->it_interval, timr->it_incr * sgi_clock_period);
- ns_to_timespec(cur_setting->it_value, (timr->it_timer.expires - rtc_time())* sgi_clock_period);
+ ns_to_timespec(cur_setting->it_interval, timr->it.mmtimer.incr * sgi_clock_period);
+ ns_to_timespec(cur_setting->it_value, (timr->it.mmtimer.expires - rtc_time())* sgi_clock_period);
return;
}

@@ -640,19 +640,19 @@ retry:
base[i].timer = timr;
base[i].cpu = smp_processor_id();

- timr->it_timer.magic = i;
- timr->it_timer.data = nodeid;
- timr->it_incr = period;
- timr->it_timer.expires = when;
+ timr->it.mmtimer.clock = i;
+ timr->it.mmtimer.node = nodeid;
+ timr->it.mmtimer.incr = period;
+ timr->it.mmtimer.expires = when;

if (period == 0) {
if (mmtimer_setup(i, when)) {
mmtimer_disable_int(-1, i);
posix_timer_event(timr, 0);
- timr->it_timer.expires = 0;
+ timr->it.mmtimer.expires = 0;
}
} else {
- timr->it_timer.expires -= period;
+ timr->it.mmtimer.expires -= period;
if (reschedule_periodic_timer(base+i))
err = -EINVAL;
}
>

2005-01-25 23:40:02

by Roland McGrath

[permalink] [raw]
Subject: Re: [PATCH 4/7] posix-timers: CPU clock support for POSIX timers

> Possibly you could bury these name changes in defines. I suspect the
> code would be easier to read and that we really don't need to be reminded
> that it is a union on each reference.

To be honest, I can never really predict the direction of vitriolic opinion
I'll get on such things. I'm happy to change it however people prefer.


Thanks,
Roland

2005-01-25 23:43:16

by George Anzinger

[permalink] [raw]
Subject: Re: [PATCH 4/7] posix-timers: CPU clock support for POSIX timers

Christoph Lameter wrote:
> On Mon, 24 Jan 2005, Christoph Lameter wrote:
>
>
>>It would be great to have a kind of private field that other clocks (like
>>clock drivers) could use for their purposes. mmtimer f.e. does use some
>>of the fields for the tick based timers for its purposes.
>
>
> On that note:
>
> Your patch breaks the mmtimer driver because it used k_itimer values for
> its own purposes. Here is a fix by defining an additional structure
> in k_itimer (same approach for mmtimer as the cpu timers):

I would like to get a read on the following defines...
#define mmclock mmtimer.clock
#define mmnode mmtimer.node
#define mmincr mmtimer.incr
#define mmexpires mmtimer.expires

Then, of course, you would use the defines instead of the "." references. Is
this a big no-no in kernel code. Seems to me it makes things a bit easier to read.

George
>
> Signed-off-by: Christoph Lameter <[email protected]>
>
> Index: linux-2.6.10/include/linux/posix-timers.h
> ===================================================================
> --- linux-2.6.10.orig/include/linux/posix-timers.h 2005-01-25 14:35:11.000000000 -0800
> +++ linux-2.6.10/include/linux/posix-timers.h 2005-01-25 14:35:16.000000000 -0800
> @@ -57,6 +57,12 @@ struct k_itimer {
> unsigned long incr; /* interval in jiffies */
> } real;
> struct cpu_timer_list cpu;
> + struct {
> + unsigned int clock;
> + unsigned int node;
> + unsigned long incr;
> + unsigned long expires;
> + } mmtimer;
> } it;
> };
>
#define mmclock mmtimer.clock
#define mmnode mmtimer.node
#define mmincr mmtimer.incr
#define mmexpires mmtimer.expires
> Index: linux-2.6.10/drivers/char/mmtimer.c
> ===================================================================
> --- linux-2.6.10.orig/drivers/char/mmtimer.c 2005-01-25 14:35:09.000000000 -0800
> +++ linux-2.6.10/drivers/char/mmtimer.c 2005-01-25 14:34:41.000000000 -0800
> @@ -420,19 +420,19 @@ static int inline reschedule_periodic_ti
> int n;
> struct k_itimer *t = x->timer;
>
> - t->it_timer.magic = x->i;
> + t->it.mmtimer.clock = x->i;
> t->it_overrun--;
>
> n = 0;
> do {
>
> - t->it_timer.expires += t->it_incr << n;
> + t->it.mmtimer.expires += t->it.mmtimer.incr << n;
> t->it_overrun += 1 << n;
> n++;
> if (n > 20)
> return 1;
>
> - } while (mmtimer_setup(x->i, t->it_timer.expires));
> + } while (mmtimer_setup(x->i, t->it.mmtimer.expires));
>
> return 0;
> }
> @@ -468,7 +468,7 @@ mmtimer_interrupt(int irq, void *dev_id,
> spin_lock(&base[i].lock);
> if (base[i].cpu == smp_processor_id()) {
> if (base[i].timer)
> - expires = base[i].timer->it_timer.expires;
> + expires = base[i].timer->it.mmtimer.expires;
> /* expires test won't work with shared irqs */
> if ((mmtimer_int_pending(i) > 0) ||
> (expires && (expires < rtc_time()))) {
> @@ -505,7 +505,7 @@ void mmtimer_tasklet(unsigned long data)
>
> t->it_overrun++;
> }
> - if(t->it_incr) {
> + if(t->it.mmtimer.incr) {
> /* Periodic timer */
> if (reschedule_periodic_timer(x)) {
> printk(KERN_WARNING "mmtimer: unable to reschedule\n");
> @@ -513,7 +513,7 @@ void mmtimer_tasklet(unsigned long data)
> }
> } else {
> /* Ensure we don't false trigger in mmtimer_interrupt */
> - t->it_timer.expires = 0;
> + t->it.mmtimer.expires = 0;
> }
> t->it_overrun_last = t->it_overrun;
> out:
> @@ -524,7 +524,7 @@ out:
> static int sgi_timer_create(struct k_itimer *timer)
> {
> /* Insure that a newly created timer is off */
> - timer->it_timer.magic = TIMER_OFF;
> + timer->it.mmtimer.clock = TIMER_OFF;
> return 0;
> }
>
> @@ -535,8 +535,8 @@ static int sgi_timer_create(struct k_iti
> */
> static int sgi_timer_del(struct k_itimer *timr)
> {
> - int i = timr->it_timer.magic;
> - cnodeid_t nodeid = timr->it_timer.data;
> + int i = timr->it.mmtimer.clock;
> + cnodeid_t nodeid = timr->it.mmtimer.node;
> mmtimer_t *t = timers + nodeid * NUM_COMPARATORS +i;
> unsigned long irqflags;
>
> @@ -544,8 +544,8 @@ static int sgi_timer_del(struct k_itimer
> spin_lock_irqsave(&t->lock, irqflags);
> mmtimer_disable_int(cnodeid_to_nasid(nodeid),i);
> t->timer = NULL;
> - timr->it_timer.magic = TIMER_OFF;
> - timr->it_timer.expires = 0;
> + timr->it.mmtimer.clock = TIMER_OFF;
> + timr->it.mmtimer.expires = 0;
> spin_unlock_irqrestore(&t->lock, irqflags);
> }
> return 0;
> @@ -558,7 +558,7 @@ static int sgi_timer_del(struct k_itimer
> static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
> {
>
> - if (timr->it_timer.magic == TIMER_OFF) {
> + if (timr->it.mmtimer.clock == TIMER_OFF) {
> cur_setting->it_interval.tv_nsec = 0;
> cur_setting->it_interval.tv_sec = 0;
> cur_setting->it_value.tv_nsec = 0;
> @@ -566,8 +566,8 @@ static void sgi_timer_get(struct k_itime
> return;
> }
>
> - ns_to_timespec(cur_setting->it_interval, timr->it_incr * sgi_clock_period);
> - ns_to_timespec(cur_setting->it_value, (timr->it_timer.expires - rtc_time())* sgi_clock_period);
> + ns_to_timespec(cur_setting->it_interval, timr->it.mmtimer.incr * sgi_clock_period);
> + ns_to_timespec(cur_setting->it_value, (timr->it.mmtimer.expires - rtc_time())* sgi_clock_period);
> return;
> }
>
> @@ -640,19 +640,19 @@ retry:
> base[i].timer = timr;
> base[i].cpu = smp_processor_id();
>
> - timr->it_timer.magic = i;
> - timr->it_timer.data = nodeid;
> - timr->it_incr = period;
> - timr->it_timer.expires = when;
> + timr->it.mmtimer.clock = i;
> + timr->it.mmtimer.node = nodeid;
> + timr->it.mmtimer.incr = period;
> + timr->it.mmtimer.expires = when;
>
> if (period == 0) {
> if (mmtimer_setup(i, when)) {
> mmtimer_disable_int(-1, i);
> posix_timer_event(timr, 0);
> - timr->it_timer.expires = 0;
> + timr->it.mmtimer.expires = 0;
> }
> } else {
> - timr->it_timer.expires -= period;
> + timr->it.mmtimer.expires -= period;
> if (reschedule_periodic_timer(base+i))
> err = -EINVAL;
> }
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

--
George Anzinger [email protected]
High-res-timers: http://sourceforge.net/projects/high-res-timers/

2005-01-25 23:51:12

by Christoph Lameter

[permalink] [raw]
Subject: Re: [PATCH 4/7] posix-timers: CPU clock support for POSIX timers

On Tue, 25 Jan 2005, George Anzinger wrote:

> > Your patch breaks the mmtimer driver because it used k_itimer values for
> > its own purposes. Here is a fix by defining an additional structure
> > in k_itimer (same approach for mmtimer as the cpu timers):
>
> I would like to get a read on the following defines...
> #define mmclock mmtimer.clock
> #define mmnode mmtimer.node
> #define mmincr mmtimer.incr
> #define mmexpires mmtimer.expires
>
> Then, of course, you would use the defines instead of the "." references. Is
> this a big no-no in kernel code. Seems to me it makes things a bit easier to read.

Less code to get to the values would be preferable. Maybe this could be
another patch to clean up the clock driver stuff and provide some
standardized mechanism to provide private data space for future clock
drivers?

2005-01-26 01:01:22

by Roland McGrath

[permalink] [raw]
Subject: Re: [PATCH 4/7] posix-timers: CPU clock support for POSIX timers

> Your patch breaks the mmtimer driver because it used k_itimer values for
> its own purposes. Here is a fix by defining an additional structure
> in k_itimer (same approach for mmtimer as the cpu timers):

This seems reasonable enough to me. Perhaps if there will be lots of timer
guts implementations, and more coming in modules or whatnot, then the union
should be replaced with a more generic private-data buffer, or at least
have a vanilla padding alternative in the union. But I am certainly happy
with the simple path of just adding in the implementations as they come
like you've done for mmtimer.


Thanks,
Roland

2005-01-26 01:08:51

by Chris Wedgwood

[permalink] [raw]
Subject: Re: [PATCH 4/7] posix-timers: CPU clock support for POSIX timers

On Tue, Jan 25, 2005 at 03:39:12PM -0800, George Anzinger wrote:

> I would like to get a read on the following defines...
> #define mmclock mmtimer.clock
> #define mmnode mmtimer.node
> #define mmincr mmtimer.incr
> #define mmexpires mmtimer.expires

Ick, we already abuse the preprocessor too much, I really don't like
that. Yes, it saves a few keystrokes but makes things hard to find
and/or more vague when using cscope/grep, etc.