mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge branch 'v28-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'v28-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (36 commits) fix documentation of sysrq-q really Fix documentation of sysrq-q timer_list: add base address to clock base timer_list: print cpu number of clockevents device timer_list: print real timer address NOHZ: restart tick device from irq_enter() NOHZ: split tick_nohz_restart_sched_tick() NOHZ: unify the nohz function calls in irq_enter() timers: fix itimer/many thread hang, fix timers: fix itimer/many thread hang, v3 ntp: improve adjtimex frequency rounding timekeeping: fix rounding problem during clock update ntp: let update_persistent_clock() sleep hrtimer: reorder struct hrtimer to save 8 bytes on 64bit builds posix-timers: lock_timer: make it readable posix-timers: lock_timer: kill the bogus ->it_id check posix-timers: kill ->it_sigev_signo and ->it_sigev_value posix-timers: sys_timer_create: cleanup the error handling posix-timers: move the initialization of timer->sigq from send to create path posix-timers: sys_timer_create: simplify and s/tasklist/rcu/ ... Fix trivial conflicts due to sysrq-q description clahes in Documentation/sysrq.txt and drivers/char/sysrq.c
This commit is contained in:
@@ -95,8 +95,9 @@ On all - write a character to /proc/sysrq-trigger. e.g.:
|
||||
|
||||
'p' - Will dump the current registers and flags to your console.
|
||||
|
||||
'q' - Will dump a list of all running hrtimers.
|
||||
WARNING: Does not cover any other timers
|
||||
'q' - Will dump per CPU lists of all armed hrtimers (but NOT regular
|
||||
timer_list timers) and detailed information about all
|
||||
clockevent devices.
|
||||
|
||||
'r' - Turns off keyboard raw mode and sets it to XLATE.
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ static void sysrq_handle_show_timers(int key, struct tty_struct *tty)
|
||||
static struct sysrq_key_op sysrq_show_timers_op = {
|
||||
.handler = sysrq_handle_show_timers,
|
||||
.help_msg = "show-all-timers(Q)",
|
||||
.action_msg = "Show pending hrtimers (no others)",
|
||||
.action_msg = "Show clockevent devices & pending hrtimers (no others)",
|
||||
};
|
||||
|
||||
static void sysrq_handle_mountro(int key, struct tty_struct *tty)
|
||||
|
||||
@@ -237,9 +237,12 @@ static int __init parse_pmtmr(char *arg)
|
||||
|
||||
if (strict_strtoul(arg, 16, &base))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
if (base > UINT_MAX)
|
||||
return -ERANGE;
|
||||
#endif
|
||||
printk(KERN_INFO "PMTMR IOPort override: 0x%04x -> 0x%04lx\n",
|
||||
(unsigned int)pmtmr_ioport, base);
|
||||
pmtmr_ioport, base);
|
||||
pmtmr_ioport = base;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -1341,20 +1341,15 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
|
||||
prstatus->pr_pgrp = task_pgrp_vnr(p);
|
||||
prstatus->pr_sid = task_session_vnr(p);
|
||||
if (thread_group_leader(p)) {
|
||||
struct task_cputime cputime;
|
||||
|
||||
/*
|
||||
* This is the record for the group leader. Add in the
|
||||
* cumulative times of previous dead threads. This total
|
||||
* won't include the time of each live thread whose state
|
||||
* is included in the core dump. The final total reported
|
||||
* to our parent process when it calls wait4 will include
|
||||
* those sums as well as the little bit more time it takes
|
||||
* this and each other thread to finish dying after the
|
||||
* core dump synchronization phase.
|
||||
* This is the record for the group leader. It shows the
|
||||
* group-wide total, not its individual thread total.
|
||||
*/
|
||||
cputime_to_timeval(cputime_add(p->utime, p->signal->utime),
|
||||
&prstatus->pr_utime);
|
||||
cputime_to_timeval(cputime_add(p->stime, p->signal->stime),
|
||||
&prstatus->pr_stime);
|
||||
thread_group_cputime(p, &cputime);
|
||||
cputime_to_timeval(cputime.utime, &prstatus->pr_utime);
|
||||
cputime_to_timeval(cputime.stime, &prstatus->pr_stime);
|
||||
} else {
|
||||
cputime_to_timeval(p->utime, &prstatus->pr_utime);
|
||||
cputime_to_timeval(p->stime, &prstatus->pr_stime);
|
||||
|
||||
@@ -388,20 +388,20 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
|
||||
|
||||
/* add up live thread stats at the group level */
|
||||
if (whole) {
|
||||
struct task_cputime cputime;
|
||||
struct task_struct *t = task;
|
||||
do {
|
||||
min_flt += t->min_flt;
|
||||
maj_flt += t->maj_flt;
|
||||
utime = cputime_add(utime, task_utime(t));
|
||||
stime = cputime_add(stime, task_stime(t));
|
||||
gtime = cputime_add(gtime, task_gtime(t));
|
||||
t = next_thread(t);
|
||||
} while (t != task);
|
||||
|
||||
min_flt += sig->min_flt;
|
||||
maj_flt += sig->maj_flt;
|
||||
utime = cputime_add(utime, sig->utime);
|
||||
stime = cputime_add(stime, sig->stime);
|
||||
thread_group_cputime(task, &cputime);
|
||||
utime = cputime.utime;
|
||||
stime = cputime.stime;
|
||||
gtime = cputime_add(gtime, sig->gtime);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ struct clocksource;
|
||||
* @read: returns a cycle value
|
||||
* @mask: bitmask for two's complement
|
||||
* subtraction of non 64 bit counters
|
||||
* @mult: cycle to nanosecond multiplier
|
||||
* @mult: cycle to nanosecond multiplier (adjusted by NTP)
|
||||
* @mult_orig: cycle to nanosecond multiplier (unadjusted by NTP)
|
||||
* @shift: cycle to nanosecond divisor (power of two)
|
||||
* @flags: flags describing special properties
|
||||
* @vread: vsyscall based read
|
||||
@@ -63,6 +64,7 @@ struct clocksource {
|
||||
cycle_t (*read)(void);
|
||||
cycle_t mask;
|
||||
u32 mult;
|
||||
u32 mult_orig;
|
||||
u32 shift;
|
||||
unsigned long flags;
|
||||
cycle_t (*vread)(void);
|
||||
@@ -77,6 +79,7 @@ struct clocksource {
|
||||
/* timekeeping specific data, ignore */
|
||||
cycle_t cycle_interval;
|
||||
u64 xtime_interval;
|
||||
u32 raw_interval;
|
||||
/*
|
||||
* Second part is written at each timer interrupt
|
||||
* Keep it in a different cache line to dirty no
|
||||
@@ -85,6 +88,7 @@ struct clocksource {
|
||||
cycle_t cycle_last ____cacheline_aligned_in_smp;
|
||||
u64 xtime_nsec;
|
||||
s64 error;
|
||||
struct timespec raw_time;
|
||||
|
||||
#ifdef CONFIG_CLOCKSOURCE_WATCHDOG
|
||||
/* Watchdog related data, used by the framework */
|
||||
@@ -201,17 +205,19 @@ static inline void clocksource_calculate_interval(struct clocksource *c,
|
||||
{
|
||||
u64 tmp;
|
||||
|
||||
/* XXX - All of this could use a whole lot of optimization */
|
||||
/* Do the ns -> cycle conversion first, using original mult */
|
||||
tmp = length_nsec;
|
||||
tmp <<= c->shift;
|
||||
tmp += c->mult/2;
|
||||
do_div(tmp, c->mult);
|
||||
tmp += c->mult_orig/2;
|
||||
do_div(tmp, c->mult_orig);
|
||||
|
||||
c->cycle_interval = (cycle_t)tmp;
|
||||
if (c->cycle_interval == 0)
|
||||
c->cycle_interval = 1;
|
||||
|
||||
/* Go back from cycles -> shifted ns, this time use ntp adjused mult */
|
||||
c->xtime_interval = (u64)c->cycle_interval * c->mult;
|
||||
c->raw_interval = ((u64)c->cycle_interval * c->mult_orig) >> c->shift;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -125,12 +125,12 @@ struct hrtimer {
|
||||
enum hrtimer_restart (*function)(struct hrtimer *);
|
||||
struct hrtimer_clock_base *base;
|
||||
unsigned long state;
|
||||
enum hrtimer_cb_mode cb_mode;
|
||||
struct list_head cb_entry;
|
||||
enum hrtimer_cb_mode cb_mode;
|
||||
#ifdef CONFIG_TIMER_STATS
|
||||
int start_pid;
|
||||
void *start_site;
|
||||
char start_comm[16];
|
||||
int start_pid;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -155,10 +155,8 @@ struct hrtimer_sleeper {
|
||||
* @first: pointer to the timer node which expires first
|
||||
* @resolution: the resolution of the clock, in nanoseconds
|
||||
* @get_time: function to retrieve the current time of the clock
|
||||
* @get_softirq_time: function to retrieve the current time from the softirq
|
||||
* @softirq_time: the time when running the hrtimer queue in the softirq
|
||||
* @offset: offset of this clock to the monotonic base
|
||||
* @reprogram: function to reprogram the timer event
|
||||
*/
|
||||
struct hrtimer_clock_base {
|
||||
struct hrtimer_cpu_base *cpu_base;
|
||||
@@ -167,13 +165,9 @@ struct hrtimer_clock_base {
|
||||
struct rb_node *first;
|
||||
ktime_t resolution;
|
||||
ktime_t (*get_time)(void);
|
||||
ktime_t (*get_softirq_time)(void);
|
||||
ktime_t softirq_time;
|
||||
#ifdef CONFIG_HIGH_RES_TIMERS
|
||||
ktime_t offset;
|
||||
int (*reprogram)(struct hrtimer *t,
|
||||
struct hrtimer_clock_base *b,
|
||||
ktime_t n);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ static inline int kstat_irqs(int irq)
|
||||
return sum;
|
||||
}
|
||||
|
||||
extern unsigned long long task_delta_exec(struct task_struct *);
|
||||
extern void account_user_time(struct task_struct *, cputime_t);
|
||||
extern void account_user_time_scaled(struct task_struct *, cputime_t);
|
||||
extern void account_system_time(struct task_struct *, int, cputime_t);
|
||||
|
||||
@@ -45,8 +45,6 @@ struct k_itimer {
|
||||
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 */
|
||||
struct task_struct *it_process; /* process to send signal to */
|
||||
struct sigqueue *sigq; /* signal queue entry. */
|
||||
union {
|
||||
@@ -115,4 +113,6 @@ void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
|
||||
|
||||
long clock_nanosleep_restart(struct restart_block *restart_block);
|
||||
|
||||
void update_rlimit_cpu(unsigned long rlim_new);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -434,6 +434,39 @@ struct pacct_struct {
|
||||
unsigned long ac_minflt, ac_majflt;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct task_cputime - collected CPU time counts
|
||||
* @utime: time spent in user mode, in &cputime_t units
|
||||
* @stime: time spent in kernel mode, in &cputime_t units
|
||||
* @sum_exec_runtime: total time spent on the CPU, in nanoseconds
|
||||
*
|
||||
* This structure groups together three kinds of CPU time that are
|
||||
* tracked for threads and thread groups. Most things considering
|
||||
* CPU time want to group these counts together and treat all three
|
||||
* of them in parallel.
|
||||
*/
|
||||
struct task_cputime {
|
||||
cputime_t utime;
|
||||
cputime_t stime;
|
||||
unsigned long long sum_exec_runtime;
|
||||
};
|
||||
/* Alternate field names when used to cache expirations. */
|
||||
#define prof_exp stime
|
||||
#define virt_exp utime
|
||||
#define sched_exp sum_exec_runtime
|
||||
|
||||
/**
|
||||
* struct thread_group_cputime - thread group interval timer counts
|
||||
* @totals: thread group interval timers; substructure for
|
||||
* uniprocessor kernel, per-cpu for SMP kernel.
|
||||
*
|
||||
* This structure contains the version of task_cputime, above, that is
|
||||
* used for thread group CPU clock calculations.
|
||||
*/
|
||||
struct thread_group_cputime {
|
||||
struct task_cputime *totals;
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE! "signal_struct" does not have it's own
|
||||
* locking, because a shared signal_struct always
|
||||
@@ -479,6 +512,17 @@ struct signal_struct {
|
||||
cputime_t it_prof_expires, it_virt_expires;
|
||||
cputime_t it_prof_incr, it_virt_incr;
|
||||
|
||||
/*
|
||||
* Thread group totals for process CPU clocks.
|
||||
* See thread_group_cputime(), et al, for details.
|
||||
*/
|
||||
struct thread_group_cputime cputime;
|
||||
|
||||
/* Earliest-expiration cache. */
|
||||
struct task_cputime cputime_expires;
|
||||
|
||||
struct list_head cpu_timers[3];
|
||||
|
||||
/* job control IDs */
|
||||
|
||||
/*
|
||||
@@ -509,7 +553,7 @@ struct signal_struct {
|
||||
* Live threads maintain their own counters and add to these
|
||||
* in __exit_signal, except for the group leader.
|
||||
*/
|
||||
cputime_t utime, stime, cutime, cstime;
|
||||
cputime_t cutime, cstime;
|
||||
cputime_t gtime;
|
||||
cputime_t cgtime;
|
||||
unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
|
||||
@@ -517,14 +561,6 @@ struct signal_struct {
|
||||
unsigned long inblock, oublock, cinblock, coublock;
|
||||
struct task_io_accounting ioac;
|
||||
|
||||
/*
|
||||
* Cumulative ns of scheduled CPU time for dead threads in the
|
||||
* group, not including a zombie group leader. (This only differs
|
||||
* from jiffies_to_ns(utime + stime) if sched_clock uses something
|
||||
* other than jiffies.)
|
||||
*/
|
||||
unsigned long long sum_sched_runtime;
|
||||
|
||||
/*
|
||||
* We don't bother to synchronize most readers of this at all,
|
||||
* because there is no reader checking a limit that actually needs
|
||||
@@ -536,8 +572,6 @@ struct signal_struct {
|
||||
*/
|
||||
struct rlimit rlim[RLIM_NLIMITS];
|
||||
|
||||
struct list_head cpu_timers[3];
|
||||
|
||||
/* keep the process-shared keyrings here so that they do the right
|
||||
* thing in threads created with CLONE_THREAD */
|
||||
#ifdef CONFIG_KEYS
|
||||
@@ -1146,8 +1180,7 @@ struct task_struct {
|
||||
/* 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 task_cputime cputime_expires;
|
||||
struct list_head cpu_timers[3];
|
||||
|
||||
/* process credentials */
|
||||
@@ -1597,6 +1630,7 @@ extern unsigned long long cpu_clock(int cpu);
|
||||
|
||||
extern unsigned long long
|
||||
task_sched_runtime(struct task_struct *task);
|
||||
extern unsigned long long thread_group_sched_runtime(struct task_struct *task);
|
||||
|
||||
/* sched_exec is called by processes performing an exec */
|
||||
#ifdef CONFIG_SMP
|
||||
@@ -2093,6 +2127,30 @@ static inline int spin_needbreak(spinlock_t *lock)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread group CPU time accounting.
|
||||
*/
|
||||
|
||||
extern int thread_group_cputime_alloc(struct task_struct *);
|
||||
extern void thread_group_cputime(struct task_struct *, struct task_cputime *);
|
||||
|
||||
static inline void thread_group_cputime_init(struct signal_struct *sig)
|
||||
{
|
||||
sig->cputime.totals = NULL;
|
||||
}
|
||||
|
||||
static inline int thread_group_cputime_clone_thread(struct task_struct *curr)
|
||||
{
|
||||
if (curr->signal->cputime.totals)
|
||||
return 0;
|
||||
return thread_group_cputime_alloc(curr);
|
||||
}
|
||||
|
||||
static inline void thread_group_cputime_free(struct signal_struct *sig)
|
||||
{
|
||||
free_percpu(sig->cputime.totals);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reevaluate whether the task has signals pending delivery.
|
||||
* Wake the task if so.
|
||||
|
||||
@@ -96,9 +96,11 @@ extern cpumask_t *tick_get_broadcast_oneshot_mask(void);
|
||||
extern void tick_clock_notify(void);
|
||||
extern int tick_check_oneshot_change(int allow_nohz);
|
||||
extern struct tick_sched *tick_get_tick_sched(int cpu);
|
||||
extern void tick_check_idle(int cpu);
|
||||
# else
|
||||
static inline void tick_clock_notify(void) { }
|
||||
static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
|
||||
static inline void tick_check_idle(int cpu) { }
|
||||
# endif
|
||||
|
||||
#else /* CONFIG_GENERIC_CLOCKEVENTS */
|
||||
@@ -106,26 +108,23 @@ static inline void tick_init(void) { }
|
||||
static inline void tick_cancel_sched_timer(int cpu) { }
|
||||
static inline void tick_clock_notify(void) { }
|
||||
static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
|
||||
static inline void tick_check_idle(int cpu) { }
|
||||
#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
|
||||
|
||||
# ifdef CONFIG_NO_HZ
|
||||
extern void tick_nohz_stop_sched_tick(int inidle);
|
||||
extern void tick_nohz_restart_sched_tick(void);
|
||||
extern void tick_nohz_update_jiffies(void);
|
||||
extern ktime_t tick_nohz_get_sleep_length(void);
|
||||
extern void tick_nohz_stop_idle(int cpu);
|
||||
extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time);
|
||||
# else
|
||||
static inline void tick_nohz_stop_sched_tick(int inidle) { }
|
||||
static inline void tick_nohz_restart_sched_tick(void) { }
|
||||
static inline void tick_nohz_update_jiffies(void) { }
|
||||
static inline ktime_t tick_nohz_get_sleep_length(void)
|
||||
{
|
||||
ktime_t len = { .tv64 = NSEC_PER_SEC/HZ };
|
||||
|
||||
return len;
|
||||
}
|
||||
static inline void tick_nohz_stop_idle(int cpu) { }
|
||||
static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; }
|
||||
# endif /* !NO_HZ */
|
||||
|
||||
|
||||
@@ -119,6 +119,7 @@ extern int do_setitimer(int which, struct itimerval *value,
|
||||
extern unsigned int alarm_setitimer(unsigned int seconds);
|
||||
extern int do_getitimer(int which, struct itimerval *value);
|
||||
extern void getnstimeofday(struct timespec *tv);
|
||||
extern void getrawmonotonic(struct timespec *ts);
|
||||
extern void getboottime(struct timespec *ts);
|
||||
extern void monotonic_to_bootbased(struct timespec *ts);
|
||||
|
||||
@@ -127,6 +128,9 @@ extern int timekeeping_valid_for_hres(void);
|
||||
extern void update_wall_time(void);
|
||||
extern void update_xtime_cache(u64 nsec);
|
||||
|
||||
struct tms;
|
||||
extern void do_sys_times(struct tms *);
|
||||
|
||||
/**
|
||||
* timespec_to_ns - Convert timespec to nanoseconds
|
||||
* @ts: pointer to the timespec variable to be converted
|
||||
@@ -216,6 +220,7 @@ struct itimerval {
|
||||
#define CLOCK_MONOTONIC 1
|
||||
#define CLOCK_PROCESS_CPUTIME_ID 2
|
||||
#define CLOCK_THREAD_CPUTIME_ID 3
|
||||
#define CLOCK_MONOTONIC_RAW 4
|
||||
|
||||
/*
|
||||
* The IDs of various hardware clocks:
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
*/
|
||||
#define SHIFT_USEC 16 /* frequency offset scale (shift) */
|
||||
#define PPM_SCALE (NSEC_PER_USEC << (NTP_SCALE_SHIFT - SHIFT_USEC))
|
||||
#define PPM_SCALE_INV_SHIFT 20
|
||||
#define PPM_SCALE_INV_SHIFT 19
|
||||
#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + NTP_SCALE_SHIFT)) / \
|
||||
PPM_SCALE + 1)
|
||||
|
||||
@@ -141,8 +141,15 @@ struct timex {
|
||||
#define ADJ_MICRO 0x1000 /* select microsecond resolution */
|
||||
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
|
||||
#define ADJ_TICK 0x4000 /* tick value */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define ADJ_ADJTIME 0x8000 /* switch between adjtime/adjtimex modes */
|
||||
#define ADJ_OFFSET_SINGLESHOT 0x0001 /* old-fashioned adjtime */
|
||||
#define ADJ_OFFSET_READONLY 0x2000 /* read-only adjtime */
|
||||
#else
|
||||
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
|
||||
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
|
||||
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
|
||||
#endif
|
||||
|
||||
/* xntp 3.4 compatibility names */
|
||||
#define MOD_OFFSET ADJ_OFFSET
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/timex.h>
|
||||
#include <linux/migrate.h>
|
||||
#include <linux/posix-timers.h>
|
||||
#include <linux/times.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
@@ -208,49 +209,23 @@ asmlinkage long compat_sys_setitimer(int which,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
|
||||
{
|
||||
return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
|
||||
}
|
||||
|
||||
asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
|
||||
{
|
||||
/*
|
||||
* In the SMP world we might just be unlucky and have one of
|
||||
* the times increment as we use it. Since the value is an
|
||||
* atomically safe type this is just fine. Conceptually its
|
||||
* as if the syscall took an instant longer to occur.
|
||||
*/
|
||||
if (tbuf) {
|
||||
struct tms tms;
|
||||
struct compat_tms tmp;
|
||||
struct task_struct *tsk = current;
|
||||
struct task_struct *t;
|
||||
cputime_t utime, stime, cutime, cstime;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
utime = tsk->signal->utime;
|
||||
stime = tsk->signal->stime;
|
||||
t = tsk;
|
||||
do {
|
||||
utime = cputime_add(utime, t->utime);
|
||||
stime = cputime_add(stime, t->stime);
|
||||
t = next_thread(t);
|
||||
} while (t != tsk);
|
||||
|
||||
/*
|
||||
* While we have tasklist_lock read-locked, no dying thread
|
||||
* can be updating current->signal->[us]time. Instead,
|
||||
* we got their counts included in the live thread loop.
|
||||
* However, another thread can come in right now and
|
||||
* do a wait call that updates current->signal->c[us]time.
|
||||
* To make sure we always see that pair updated atomically,
|
||||
* we take the siglock around fetching them.
|
||||
*/
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
cutime = tsk->signal->cutime;
|
||||
cstime = tsk->signal->cstime;
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
tmp.tms_utime = compat_jiffies_to_clock_t(cputime_to_jiffies(utime));
|
||||
tmp.tms_stime = compat_jiffies_to_clock_t(cputime_to_jiffies(stime));
|
||||
tmp.tms_cutime = compat_jiffies_to_clock_t(cputime_to_jiffies(cutime));
|
||||
tmp.tms_cstime = compat_jiffies_to_clock_t(cputime_to_jiffies(cstime));
|
||||
do_sys_times(&tms);
|
||||
/* Convert our struct tms to the compat version. */
|
||||
tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime);
|
||||
tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime);
|
||||
tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime);
|
||||
tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime);
|
||||
if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
@@ -112,8 +112,6 @@ static void __exit_signal(struct task_struct *tsk)
|
||||
* We won't ever get here for the group leader, since it
|
||||
* will have been the last reference on the signal_struct.
|
||||
*/
|
||||
sig->utime = cputime_add(sig->utime, task_utime(tsk));
|
||||
sig->stime = cputime_add(sig->stime, task_stime(tsk));
|
||||
sig->gtime = cputime_add(sig->gtime, task_gtime(tsk));
|
||||
sig->min_flt += tsk->min_flt;
|
||||
sig->maj_flt += tsk->maj_flt;
|
||||
@@ -122,7 +120,6 @@ static void __exit_signal(struct task_struct *tsk)
|
||||
sig->inblock += task_io_get_inblock(tsk);
|
||||
sig->oublock += task_io_get_oublock(tsk);
|
||||
task_io_accounting_add(&sig->ioac, &tsk->ioac);
|
||||
sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
|
||||
sig = NULL; /* Marker for below. */
|
||||
}
|
||||
|
||||
@@ -1301,6 +1298,7 @@ static int wait_task_zombie(struct task_struct *p, int options,
|
||||
if (likely(!traced)) {
|
||||
struct signal_struct *psig;
|
||||
struct signal_struct *sig;
|
||||
struct task_cputime cputime;
|
||||
|
||||
/*
|
||||
* The resource counters for the group leader are in its
|
||||
@@ -1316,20 +1314,23 @@ static int wait_task_zombie(struct task_struct *p, int options,
|
||||
* need to protect the access to p->parent->signal fields,
|
||||
* as other threads in the parent group can be right
|
||||
* here reaping other children at the same time.
|
||||
*
|
||||
* We use thread_group_cputime() to get times for the thread
|
||||
* group, which consolidates times for all threads in the
|
||||
* group including the group leader.
|
||||
*/
|
||||
spin_lock_irq(&p->parent->sighand->siglock);
|
||||
psig = p->parent->signal;
|
||||
sig = p->signal;
|
||||
thread_group_cputime(p, &cputime);
|
||||
psig->cutime =
|
||||
cputime_add(psig->cutime,
|
||||
cputime_add(p->utime,
|
||||
cputime_add(sig->utime,
|
||||
sig->cutime)));
|
||||
cputime_add(cputime.utime,
|
||||
sig->cutime));
|
||||
psig->cstime =
|
||||
cputime_add(psig->cstime,
|
||||
cputime_add(p->stime,
|
||||
cputime_add(sig->stime,
|
||||
sig->cstime)));
|
||||
cputime_add(cputime.stime,
|
||||
sig->cstime));
|
||||
psig->cgtime =
|
||||
cputime_add(psig->cgtime,
|
||||
cputime_add(p->gtime,
|
||||
|
||||
@@ -759,15 +759,44 @@ void __cleanup_sighand(struct sighand_struct *sighand)
|
||||
kmem_cache_free(sighand_cachep, sighand);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize POSIX timer handling for a thread group.
|
||||
*/
|
||||
static void posix_cpu_timers_init_group(struct signal_struct *sig)
|
||||
{
|
||||
/* Thread group counters. */
|
||||
thread_group_cputime_init(sig);
|
||||
|
||||
/* Expiration times and increments. */
|
||||
sig->it_virt_expires = cputime_zero;
|
||||
sig->it_virt_incr = cputime_zero;
|
||||
sig->it_prof_expires = cputime_zero;
|
||||
sig->it_prof_incr = cputime_zero;
|
||||
|
||||
/* Cached expiration times. */
|
||||
sig->cputime_expires.prof_exp = cputime_zero;
|
||||
sig->cputime_expires.virt_exp = cputime_zero;
|
||||
sig->cputime_expires.sched_exp = 0;
|
||||
|
||||
/* The timer lists. */
|
||||
INIT_LIST_HEAD(&sig->cpu_timers[0]);
|
||||
INIT_LIST_HEAD(&sig->cpu_timers[1]);
|
||||
INIT_LIST_HEAD(&sig->cpu_timers[2]);
|
||||
}
|
||||
|
||||
static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
|
||||
{
|
||||
struct signal_struct *sig;
|
||||
int ret;
|
||||
|
||||
if (clone_flags & CLONE_THREAD) {
|
||||
atomic_inc(¤t->signal->count);
|
||||
atomic_inc(¤t->signal->live);
|
||||
return 0;
|
||||
ret = thread_group_cputime_clone_thread(current);
|
||||
if (likely(!ret)) {
|
||||
atomic_inc(¤t->signal->count);
|
||||
atomic_inc(¤t->signal->live);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL);
|
||||
tsk->signal = sig;
|
||||
@@ -795,40 +824,25 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
|
||||
sig->it_real_incr.tv64 = 0;
|
||||
sig->real_timer.function = it_real_fn;
|
||||
|
||||
sig->it_virt_expires = cputime_zero;
|
||||
sig->it_virt_incr = cputime_zero;
|
||||
sig->it_prof_expires = cputime_zero;
|
||||
sig->it_prof_incr = cputime_zero;
|
||||
|
||||
sig->leader = 0; /* session leadership doesn't inherit */
|
||||
sig->tty_old_pgrp = NULL;
|
||||
sig->tty = NULL;
|
||||
|
||||
sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
|
||||
sig->cutime = sig->cstime = cputime_zero;
|
||||
sig->gtime = cputime_zero;
|
||||
sig->cgtime = cputime_zero;
|
||||
sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
|
||||
sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
|
||||
sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
|
||||
task_io_accounting_init(&sig->ioac);
|
||||
sig->sum_sched_runtime = 0;
|
||||
INIT_LIST_HEAD(&sig->cpu_timers[0]);
|
||||
INIT_LIST_HEAD(&sig->cpu_timers[1]);
|
||||
INIT_LIST_HEAD(&sig->cpu_timers[2]);
|
||||
taskstats_tgid_init(sig);
|
||||
|
||||
task_lock(current->group_leader);
|
||||
memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim);
|
||||
task_unlock(current->group_leader);
|
||||
|
||||
if (sig->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
|
||||
/*
|
||||
* New sole thread in the process gets an expiry time
|
||||
* of the whole CPU time limit.
|
||||
*/
|
||||
tsk->it_prof_expires =
|
||||
secs_to_cputime(sig->rlim[RLIMIT_CPU].rlim_cur);
|
||||
}
|
||||
posix_cpu_timers_init_group(sig);
|
||||
|
||||
acct_init_pacct(&sig->pacct);
|
||||
|
||||
tty_audit_fork(sig);
|
||||
@@ -838,6 +852,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
|
||||
|
||||
void __cleanup_signal(struct signal_struct *sig)
|
||||
{
|
||||
thread_group_cputime_free(sig);
|
||||
exit_thread_group_keys(sig);
|
||||
tty_kref_put(sig->tty);
|
||||
kmem_cache_free(signal_cachep, sig);
|
||||
@@ -887,6 +902,19 @@ void mm_init_owner(struct mm_struct *mm, struct task_struct *p)
|
||||
}
|
||||
#endif /* CONFIG_MM_OWNER */
|
||||
|
||||
/*
|
||||
* Initialize POSIX timer handling for a single task.
|
||||
*/
|
||||
static void posix_cpu_timers_init(struct task_struct *tsk)
|
||||
{
|
||||
tsk->cputime_expires.prof_exp = cputime_zero;
|
||||
tsk->cputime_expires.virt_exp = cputime_zero;
|
||||
tsk->cputime_expires.sched_exp = 0;
|
||||
INIT_LIST_HEAD(&tsk->cpu_timers[0]);
|
||||
INIT_LIST_HEAD(&tsk->cpu_timers[1]);
|
||||
INIT_LIST_HEAD(&tsk->cpu_timers[2]);
|
||||
}
|
||||
|
||||
/*
|
||||
* This creates a new process as a copy of the old one,
|
||||
* but does not actually start it yet.
|
||||
@@ -997,12 +1025,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||||
task_io_accounting_init(&p->ioac);
|
||||
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]);
|
||||
posix_cpu_timers_init(p);
|
||||
|
||||
p->lock_depth = -1; /* -1 = no lock */
|
||||
do_posix_clock_monotonic_gettime(&p->start_time);
|
||||
@@ -1203,21 +1226,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||||
if (clone_flags & CLONE_THREAD) {
|
||||
p->group_leader = current->group_leader;
|
||||
list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);
|
||||
|
||||
if (!cputime_eq(current->signal->it_virt_expires,
|
||||
cputime_zero) ||
|
||||
!cputime_eq(current->signal->it_prof_expires,
|
||||
cputime_zero) ||
|
||||
current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY ||
|
||||
!list_empty(¤t->signal->cpu_timers[0]) ||
|
||||
!list_empty(¤t->signal->cpu_timers[1]) ||
|
||||
!list_empty(¤t->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);
|
||||
}
|
||||
}
|
||||
|
||||
if (likely(p->pid)) {
|
||||
|
||||
@@ -1403,9 +1403,7 @@ void hrtimer_run_queues(void)
|
||||
if (!base->first)
|
||||
continue;
|
||||
|
||||
if (base->get_softirq_time)
|
||||
base->softirq_time = base->get_softirq_time();
|
||||
else if (gettime) {
|
||||
if (gettime) {
|
||||
hrtimer_get_softirq_time(cpu_base);
|
||||
gettime = 0;
|
||||
}
|
||||
@@ -1688,9 +1686,11 @@ static void migrate_hrtimers(int cpu)
|
||||
new_base = &get_cpu_var(hrtimer_bases);
|
||||
|
||||
tick_cancel_sched_timer(cpu);
|
||||
|
||||
local_irq_disable();
|
||||
spin_lock(&new_base->lock);
|
||||
/*
|
||||
* The caller is globally serialized and nobody else
|
||||
* takes two locks at once, deadlock is not possible.
|
||||
*/
|
||||
spin_lock_irq(&new_base->lock);
|
||||
spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
|
||||
|
||||
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
|
||||
@@ -1703,8 +1703,7 @@ static void migrate_hrtimers(int cpu)
|
||||
raise = 1;
|
||||
|
||||
spin_unlock(&old_base->lock);
|
||||
spin_unlock(&new_base->lock);
|
||||
local_irq_enable();
|
||||
spin_unlock_irq(&new_base->lock);
|
||||
put_cpu_var(hrtimer_bases);
|
||||
|
||||
if (raise)
|
||||
|
||||
@@ -55,17 +55,15 @@ int do_getitimer(int which, struct itimerval *value)
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
break;
|
||||
case ITIMER_VIRTUAL:
|
||||
read_lock(&tasklist_lock);
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
cval = tsk->signal->it_virt_expires;
|
||||
cinterval = tsk->signal->it_virt_incr;
|
||||
if (!cputime_eq(cval, cputime_zero)) {
|
||||
struct task_struct *t = tsk;
|
||||
cputime_t utime = tsk->signal->utime;
|
||||
do {
|
||||
utime = cputime_add(utime, t->utime);
|
||||
t = next_thread(t);
|
||||
} while (t != tsk);
|
||||
struct task_cputime cputime;
|
||||
cputime_t utime;
|
||||
|
||||
thread_group_cputime(tsk, &cputime);
|
||||
utime = cputime.utime;
|
||||
if (cputime_le(cval, utime)) { /* about to fire */
|
||||
cval = jiffies_to_cputime(1);
|
||||
} else {
|
||||
@@ -73,25 +71,19 @@ int do_getitimer(int which, struct itimerval *value)
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
read_unlock(&tasklist_lock);
|
||||
cputime_to_timeval(cval, &value->it_value);
|
||||
cputime_to_timeval(cinterval, &value->it_interval);
|
||||
break;
|
||||
case ITIMER_PROF:
|
||||
read_lock(&tasklist_lock);
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
cval = tsk->signal->it_prof_expires;
|
||||
cinterval = tsk->signal->it_prof_incr;
|
||||
if (!cputime_eq(cval, cputime_zero)) {
|
||||
struct task_struct *t = tsk;
|
||||
cputime_t ptime = cputime_add(tsk->signal->utime,
|
||||
tsk->signal->stime);
|
||||
do {
|
||||
ptime = cputime_add(ptime,
|
||||
cputime_add(t->utime,
|
||||
t->stime));
|
||||
t = next_thread(t);
|
||||
} while (t != tsk);
|
||||
struct task_cputime times;
|
||||
cputime_t ptime;
|
||||
|
||||
thread_group_cputime(tsk, ×);
|
||||
ptime = cputime_add(times.utime, times.stime);
|
||||
if (cputime_le(cval, ptime)) { /* about to fire */
|
||||
cval = jiffies_to_cputime(1);
|
||||
} else {
|
||||
@@ -99,7 +91,6 @@ int do_getitimer(int which, struct itimerval *value)
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
read_unlock(&tasklist_lock);
|
||||
cputime_to_timeval(cval, &value->it_value);
|
||||
cputime_to_timeval(cinterval, &value->it_interval);
|
||||
break;
|
||||
@@ -185,7 +176,6 @@ again:
|
||||
case ITIMER_VIRTUAL:
|
||||
nval = timeval_to_cputime(&value->it_value);
|
||||
ninterval = timeval_to_cputime(&value->it_interval);
|
||||
read_lock(&tasklist_lock);
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
cval = tsk->signal->it_virt_expires;
|
||||
cinterval = tsk->signal->it_virt_incr;
|
||||
@@ -200,7 +190,6 @@ again:
|
||||
tsk->signal->it_virt_expires = nval;
|
||||
tsk->signal->it_virt_incr = ninterval;
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
read_unlock(&tasklist_lock);
|
||||
if (ovalue) {
|
||||
cputime_to_timeval(cval, &ovalue->it_value);
|
||||
cputime_to_timeval(cinterval, &ovalue->it_interval);
|
||||
@@ -209,7 +198,6 @@ again:
|
||||
case ITIMER_PROF:
|
||||
nval = timeval_to_cputime(&value->it_value);
|
||||
ninterval = timeval_to_cputime(&value->it_interval);
|
||||
read_lock(&tasklist_lock);
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
cval = tsk->signal->it_prof_expires;
|
||||
cinterval = tsk->signal->it_prof_incr;
|
||||
@@ -224,7 +212,6 @@ again:
|
||||
tsk->signal->it_prof_expires = nval;
|
||||
tsk->signal->it_prof_incr = ninterval;
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
read_unlock(&tasklist_lock);
|
||||
if (ovalue) {
|
||||
cputime_to_timeval(cval, &ovalue->it_value);
|
||||
cputime_to_timeval(cinterval, &ovalue->it_interval);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -222,6 +222,15 @@ static int posix_ktime_get_ts(clockid_t which_clock, struct timespec *tp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get monotonic time for posix timers
|
||||
*/
|
||||
static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp)
|
||||
{
|
||||
getrawmonotonic(tp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize everything, well, just everything in Posix clocks/timers ;)
|
||||
*/
|
||||
@@ -235,9 +244,15 @@ static __init int init_posix_timers(void)
|
||||
.clock_get = posix_ktime_get_ts,
|
||||
.clock_set = do_posix_clock_nosettime,
|
||||
};
|
||||
struct k_clock clock_monotonic_raw = {
|
||||
.clock_getres = hrtimer_get_res,
|
||||
.clock_get = posix_get_monotonic_raw,
|
||||
.clock_set = do_posix_clock_nosettime,
|
||||
};
|
||||
|
||||
register_posix_clock(CLOCK_REALTIME, &clock_realtime);
|
||||
register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic);
|
||||
register_posix_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);
|
||||
|
||||
posix_timers_cache = kmem_cache_create("posix_timers_cache",
|
||||
sizeof (struct k_itimer), 0, SLAB_PANIC,
|
||||
@@ -298,6 +313,7 @@ void do_schedule_next_timer(struct siginfo *info)
|
||||
|
||||
int posix_timer_event(struct k_itimer *timr, int si_private)
|
||||
{
|
||||
int shared, ret;
|
||||
/*
|
||||
* FIXME: if ->sigq is queued we can race with
|
||||
* dequeue_signal()->do_schedule_next_timer().
|
||||
@@ -311,25 +327,10 @@ int posix_timer_event(struct k_itimer *timr, int si_private)
|
||||
*/
|
||||
timr->sigq->info.si_sys_private = si_private;
|
||||
|
||||
timr->sigq->info.si_signo = timr->it_sigev_signo;
|
||||
timr->sigq->info.si_code = SI_TIMER;
|
||||
timr->sigq->info.si_tid = timr->it_id;
|
||||
timr->sigq->info.si_value = timr->it_sigev_value;
|
||||
|
||||
if (timr->it_sigev_notify & SIGEV_THREAD_ID) {
|
||||
struct task_struct *leader;
|
||||
int ret = send_sigqueue(timr->sigq, timr->it_process, 0);
|
||||
|
||||
if (likely(ret >= 0))
|
||||
return ret;
|
||||
|
||||
timr->it_sigev_notify = SIGEV_SIGNAL;
|
||||
leader = timr->it_process->group_leader;
|
||||
put_task_struct(timr->it_process);
|
||||
timr->it_process = leader;
|
||||
}
|
||||
|
||||
return send_sigqueue(timr->sigq, timr->it_process, 1);
|
||||
shared = !(timr->it_sigev_notify & SIGEV_THREAD_ID);
|
||||
ret = send_sigqueue(timr->sigq, timr->it_process, shared);
|
||||
/* If we failed to send the signal the timer stops. */
|
||||
return ret > 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(posix_timer_event);
|
||||
|
||||
@@ -468,11 +469,9 @@ sys_timer_create(const clockid_t which_clock,
|
||||
struct sigevent __user *timer_event_spec,
|
||||
timer_t __user * created_timer_id)
|
||||
{
|
||||
int error = 0;
|
||||
struct k_itimer *new_timer = NULL;
|
||||
int new_timer_id;
|
||||
struct task_struct *process = NULL;
|
||||
unsigned long flags;
|
||||
struct k_itimer *new_timer;
|
||||
int error, new_timer_id;
|
||||
struct task_struct *process;
|
||||
sigevent_t event;
|
||||
int it_id_set = IT_ID_NOT_SET;
|
||||
|
||||
@@ -490,12 +489,11 @@ sys_timer_create(const clockid_t which_clock,
|
||||
goto out;
|
||||
}
|
||||
spin_lock_irq(&idr_lock);
|
||||
error = idr_get_new(&posix_timers_id, (void *) new_timer,
|
||||
&new_timer_id);
|
||||
error = idr_get_new(&posix_timers_id, new_timer, &new_timer_id);
|
||||
spin_unlock_irq(&idr_lock);
|
||||
if (error == -EAGAIN)
|
||||
goto retry;
|
||||
else if (error) {
|
||||
if (error) {
|
||||
if (error == -EAGAIN)
|
||||
goto retry;
|
||||
/*
|
||||
* Weird looking, but we return EAGAIN if the IDR is
|
||||
* full (proper POSIX return value for this)
|
||||
@@ -526,67 +524,43 @@ sys_timer_create(const clockid_t which_clock,
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
new_timer->it_sigev_notify = event.sigev_notify;
|
||||
new_timer->it_sigev_signo = event.sigev_signo;
|
||||
new_timer->it_sigev_value = event.sigev_value;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
if ((process = good_sigevent(&event))) {
|
||||
/*
|
||||
* We may be setting up this process for another
|
||||
* thread. It may be exiting. To catch this
|
||||
* case the we check the PF_EXITING flag. If
|
||||
* the flag is not set, the siglock will catch
|
||||
* him before it is too late (in exit_itimers).
|
||||
*
|
||||
* The exec case is a bit more invloved but easy
|
||||
* to code. If the process is in our thread
|
||||
* group (and it must be or we would not allow
|
||||
* it here) and is doing an exec, it will cause
|
||||
* us to be killed. In this case it will wait
|
||||
* for us to die which means we can finish this
|
||||
* linkage with our last gasp. I.e. no code :)
|
||||
*/
|
||||
spin_lock_irqsave(&process->sighand->siglock, flags);
|
||||
if (!(process->flags & PF_EXITING)) {
|
||||
new_timer->it_process = process;
|
||||
list_add(&new_timer->list,
|
||||
&process->signal->posix_timers);
|
||||
if (new_timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
|
||||
get_task_struct(process);
|
||||
spin_unlock_irqrestore(&process->sighand->siglock, flags);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&process->sighand->siglock, flags);
|
||||
process = NULL;
|
||||
}
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
rcu_read_lock();
|
||||
process = good_sigevent(&event);
|
||||
if (process)
|
||||
get_task_struct(process);
|
||||
rcu_read_unlock();
|
||||
if (!process) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
new_timer->it_sigev_notify = SIGEV_SIGNAL;
|
||||
new_timer->it_sigev_signo = SIGALRM;
|
||||
new_timer->it_sigev_value.sival_int = new_timer->it_id;
|
||||
event.sigev_notify = SIGEV_SIGNAL;
|
||||
event.sigev_signo = SIGALRM;
|
||||
event.sigev_value.sival_int = new_timer->it_id;
|
||||
process = current->group_leader;
|
||||
spin_lock_irqsave(&process->sighand->siglock, flags);
|
||||
new_timer->it_process = process;
|
||||
list_add(&new_timer->list, &process->signal->posix_timers);
|
||||
spin_unlock_irqrestore(&process->sighand->siglock, flags);
|
||||
get_task_struct(process);
|
||||
}
|
||||
|
||||
new_timer->it_sigev_notify = event.sigev_notify;
|
||||
new_timer->sigq->info.si_signo = event.sigev_signo;
|
||||
new_timer->sigq->info.si_value = event.sigev_value;
|
||||
new_timer->sigq->info.si_tid = new_timer->it_id;
|
||||
new_timer->sigq->info.si_code = SI_TIMER;
|
||||
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
new_timer->it_process = process;
|
||||
list_add(&new_timer->list, ¤t->signal->posix_timers);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* In the case of the timer belonging to another task, after
|
||||
* the task is unlocked, the timer is owned by the other task
|
||||
* and may cease to exist at any time. Don't use or modify
|
||||
* new_timer after the unlock call.
|
||||
*/
|
||||
|
||||
out:
|
||||
if (error)
|
||||
release_posix_timer(new_timer, it_id_set);
|
||||
|
||||
release_posix_timer(new_timer, it_id_set);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -597,7 +571,7 @@ out:
|
||||
* the find to the timer lock. To avoid a dead lock, the timer id MUST
|
||||
* be release with out holding the timer lock.
|
||||
*/
|
||||
static struct k_itimer * lock_timer(timer_t timer_id, unsigned long *flags)
|
||||
static struct k_itimer *lock_timer(timer_t timer_id, unsigned long *flags)
|
||||
{
|
||||
struct k_itimer *timr;
|
||||
/*
|
||||
@@ -605,23 +579,20 @@ static struct k_itimer * lock_timer(timer_t timer_id, unsigned long *flags)
|
||||
* flags part over to the timer lock. Must not let interrupts in
|
||||
* while we are moving the lock.
|
||||
*/
|
||||
|
||||
spin_lock_irqsave(&idr_lock, *flags);
|
||||
timr = (struct k_itimer *) idr_find(&posix_timers_id, (int) timer_id);
|
||||
timr = idr_find(&posix_timers_id, (int)timer_id);
|
||||
if (timr) {
|
||||
spin_lock(&timr->it_lock);
|
||||
|
||||
if ((timr->it_id != timer_id) || !(timr->it_process) ||
|
||||
!same_thread_group(timr->it_process, current)) {
|
||||
spin_unlock(&timr->it_lock);
|
||||
spin_unlock_irqrestore(&idr_lock, *flags);
|
||||
timr = NULL;
|
||||
} else
|
||||
if (timr->it_process &&
|
||||
same_thread_group(timr->it_process, current)) {
|
||||
spin_unlock(&idr_lock);
|
||||
} else
|
||||
spin_unlock_irqrestore(&idr_lock, *flags);
|
||||
return timr;
|
||||
}
|
||||
spin_unlock(&timr->it_lock);
|
||||
}
|
||||
spin_unlock_irqrestore(&idr_lock, *flags);
|
||||
|
||||
return timr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -862,8 +833,7 @@ retry_delete:
|
||||
* This keeps any tasks waiting on the spin lock from thinking
|
||||
* they got something (see the lock code above).
|
||||
*/
|
||||
if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
|
||||
put_task_struct(timer->it_process);
|
||||
put_task_struct(timer->it_process);
|
||||
timer->it_process = NULL;
|
||||
|
||||
unlock_timer(timer, flags);
|
||||
@@ -890,8 +860,7 @@ retry_delete:
|
||||
* This keeps any tasks waiting on the spin lock from thinking
|
||||
* they got something (see the lock code above).
|
||||
*/
|
||||
if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
|
||||
put_task_struct(timer->it_process);
|
||||
put_task_struct(timer->it_process);
|
||||
timer->it_process = NULL;
|
||||
|
||||
unlock_timer(timer, flags);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user