summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2005-03-07 18:16:42 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-03-07 18:16:42 -0800
commit2c3871a8f5244025fe9d846f76994251319e23e4 (patch)
treedadb300b5d7deb0c703af5f6d549ef456532fa46 /include/linux
parent68f35a6b0d81c1e5e47ea05fc787b28a4b99a762 (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.h9
-rw-r--r--include/linux/posix-timers.h51
-rw-r--r--include/linux/sched.h7
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;