diff options
| author | Roland McGrath <roland@redhat.com> | 2005-03-07 18:16:42 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-03-07 18:16:42 -0800 |
| commit | 2c3871a8f5244025fe9d846f76994251319e23e4 (patch) | |
| tree | dadb300b5d7deb0c703af5f6d549ef456532fa46 /include/linux | |
| parent | 68f35a6b0d81c1e5e47ea05fc787b28a4b99a762 (diff) | |
[PATCH] 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).
From: Christoph Lameter <clameter@sgi.com>
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):
From: Roland McGrath <roland@redhat.com>
Fix bug identified by Alexander Nyberg <alexn@dsv.su.se>
> The problem arises from code touching the union in alloc_posix_timer()
> which makes firing go non-zero. When firing is checked in
> posix_cpu_timer_set() it will be positive causing an infinite loop.
>
> So either the below fix or preferably move the INIT_LIST_HEAD(x) from
> alloc_posix_timer() to somewhere later where it doesn't disturb the other
> union members.
Thanks for finding this problem. The latter is what I think is the right
solution. This patch does that, and also removes some superfluous rezeroing.
Signed-off-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Christoph Lameter <clameter@sgi.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/init_task.h | 9 | ||||
| -rw-r--r-- | include/linux/posix-timers.h | 51 | ||||
| -rw-r--r-- | include/linux/sched.h | 7 |
3 files changed, 57 insertions, 10 deletions
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 6498e9da9ce6..aa1eb2d45ed8 100644 --- a/include/linux/init_task.h +++ b/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 diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index a0140c8f72b7..2820fd4ab58b 100644 --- a/include/linux/posix-timers.h +++ b/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,27 @@ 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; + struct { + unsigned int clock; + unsigned int node; + unsigned long incr; + unsigned long expires; + } mmtimer; + } it; }; struct k_clock_abs { @@ -57,6 +82,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 +108,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 +122,16 @@ int posix_cpu_clock_get(clockid_t which_clock, struct timespec *); 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 diff --git a/include/linux/sched.h b/include/linux/sched.h index 5fff51dc7c32..36a6174597f7 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -338,6 +338,8 @@ struct signal_struct { * have no need to disable irqs. */ struct rlimit rlim[RLIM_NLIMITS]; + + struct list_head cpu_timers[3]; }; /* @@ -612,6 +614,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; |
