Commit 45f37e86 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched

* git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched:
  latencytop: Change Kconfig dependency.
  futex: Add bitset conditional wait/wakeup functionality
  futex: Remove warn on in return fixup path
  x86: replace LOCK_PREFIX in futex.h
  tick-sched: add more debug information
  timekeeping: update xtime_cache when time(zone) changes
  hrtimer: fix hrtimer_init_sleeper() users
parents e30ec452 aa7d9350
...@@ -44,6 +44,9 @@ config LOCKDEP_SUPPORT ...@@ -44,6 +44,9 @@ config LOCKDEP_SUPPORT
config STACKTRACE_SUPPORT config STACKTRACE_SUPPORT
def_bool y def_bool y
config HAVE_LATENCYTOP_SUPPORT
def_bool y
config SEMAPHORE_SLEEPERS config SEMAPHORE_SLEEPERS
def_bool y def_bool y
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
"1: movl %2, %0\n \ "1: movl %2, %0\n \
movl %0, %3\n" \ movl %0, %3\n" \
insn "\n" \ insn "\n" \
"2: " LOCK_PREFIX "cmpxchgl %3, %2\n \ "2: lock; cmpxchgl %3, %2\n \
jnz 1b\n \ jnz 1b\n \
3: .section .fixup,\"ax\"\n \ 3: .section .fixup,\"ax\"\n \
4: mov %5, %1\n \ 4: mov %5, %1\n \
...@@ -72,7 +72,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr) ...@@ -72,7 +72,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
__futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg); __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
break; break;
case FUTEX_OP_ADD: case FUTEX_OP_ADD:
__futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval, __futex_atomic_op1("lock; xaddl %0, %2", ret, oldval,
uaddr, oparg); uaddr, oparg);
break; break;
case FUTEX_OP_OR: case FUTEX_OP_OR:
...@@ -111,8 +111,8 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) ...@@ -111,8 +111,8 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
return -EFAULT; return -EFAULT;
__asm__ __volatile__( __asm__ __volatile__(
"1: " LOCK_PREFIX "cmpxchgl %3, %1 \n"
"1: lock; cmpxchgl %3, %1 \n"
"2: .section .fixup, \"ax\" \n" "2: .section .fixup, \"ax\" \n"
"3: mov %2, %0 \n" "3: mov %2, %0 \n"
" jmp 2b \n" " jmp 2b \n"
......
...@@ -21,6 +21,8 @@ union ktime; ...@@ -21,6 +21,8 @@ union ktime;
#define FUTEX_LOCK_PI 6 #define FUTEX_LOCK_PI 6
#define FUTEX_UNLOCK_PI 7 #define FUTEX_UNLOCK_PI 7
#define FUTEX_TRYLOCK_PI 8 #define FUTEX_TRYLOCK_PI 8
#define FUTEX_WAIT_BITSET 9
#define FUTEX_WAKE_BITSET 10
#define FUTEX_PRIVATE_FLAG 128 #define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CMD_MASK ~FUTEX_PRIVATE_FLAG #define FUTEX_CMD_MASK ~FUTEX_PRIVATE_FLAG
...@@ -33,6 +35,8 @@ union ktime; ...@@ -33,6 +35,8 @@ union ktime;
#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG) #define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) #define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG) #define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITS | FUTEX_PRIVATE_FLAG)
#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITS | FUTEX_PRIVATE_FLAG)
/* /*
* Support for robust futexes: the kernel cleans up held futexes at * Support for robust futexes: the kernel cleans up held futexes at
...@@ -111,6 +115,12 @@ struct robust_list_head { ...@@ -111,6 +115,12 @@ struct robust_list_head {
*/ */
#define ROBUST_LIST_LIMIT 2048 #define ROBUST_LIST_LIMIT 2048
/*
* bitset with all bits set for the FUTEX_xxx_BITSET OPs to request a
* match of any bit.
*/
#define FUTEX_BITSET_MATCH_ANY 0xffffffff
#ifdef __KERNEL__ #ifdef __KERNEL__
long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout, long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout,
u32 __user *uaddr2, u32 val2, u32 val3); u32 __user *uaddr2, u32 val2, u32 val3);
......
...@@ -23,6 +23,7 @@ struct restart_block { ...@@ -23,6 +23,7 @@ struct restart_block {
u32 *uaddr; u32 *uaddr;
u32 val; u32 val;
u32 flags; u32 flags;
u32 bitset;
u64 time; u64 time;
} futex; } futex;
}; };
......
...@@ -39,6 +39,8 @@ enum tick_nohz_mode { ...@@ -39,6 +39,8 @@ enum tick_nohz_mode {
* @idle_calls: Total number of idle calls * @idle_calls: Total number of idle calls
* @idle_sleeps: Number of idle calls, where the sched tick was stopped * @idle_sleeps: Number of idle calls, where the sched tick was stopped
* @idle_entrytime: Time when the idle call was entered * @idle_entrytime: Time when the idle call was entered
* @idle_waketime: Time when the idle was interrupted
* @idle_exittime: Time when the idle state was left
* @idle_sleeptime: Sum of the time slept in idle with sched tick stopped * @idle_sleeptime: Sum of the time slept in idle with sched tick stopped
* @sleep_length: Duration of the current idle sleep * @sleep_length: Duration of the current idle sleep
*/ */
...@@ -53,6 +55,8 @@ struct tick_sched { ...@@ -53,6 +55,8 @@ struct tick_sched {
unsigned long idle_sleeps; unsigned long idle_sleeps;
int idle_active; int idle_active;
ktime_t idle_entrytime; ktime_t idle_entrytime;
ktime_t idle_waketime;
ktime_t idle_exittime;
ktime_t idle_sleeptime; ktime_t idle_sleeptime;
ktime_t idle_lastupdate; ktime_t idle_lastupdate;
ktime_t sleep_length; ktime_t sleep_length;
......
...@@ -122,6 +122,7 @@ extern void monotonic_to_bootbased(struct timespec *ts); ...@@ -122,6 +122,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran); extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_is_continuous(void); extern int timekeeping_is_continuous(void);
extern void update_wall_time(void); extern void update_wall_time(void);
extern void update_xtime_cache(u64 nsec);
/** /**
* timespec_to_ns - Convert timespec to nanoseconds * timespec_to_ns - Convert timespec to nanoseconds
......
...@@ -109,6 +109,9 @@ struct futex_q { ...@@ -109,6 +109,9 @@ struct futex_q {
/* Optional priority inheritance state: */ /* Optional priority inheritance state: */
struct futex_pi_state *pi_state; struct futex_pi_state *pi_state;
struct task_struct *task; struct task_struct *task;
/* Bitset for the optional bitmasked wakeup */
u32 bitset;
}; };
/* /*
...@@ -722,7 +725,7 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2) ...@@ -722,7 +725,7 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
* to this virtual address: * to this virtual address:
*/ */
static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared, static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
int nr_wake) int nr_wake, u32 bitset)
{ {
struct futex_hash_bucket *hb; struct futex_hash_bucket *hb;
struct futex_q *this, *next; struct futex_q *this, *next;
...@@ -730,6 +733,9 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared, ...@@ -730,6 +733,9 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
union futex_key key; union futex_key key;
int ret; int ret;
if (!bitset)
return -EINVAL;
futex_lock_mm(fshared); futex_lock_mm(fshared);
ret = get_futex_key(uaddr, fshared, &key); ret = get_futex_key(uaddr, fshared, &key);
...@@ -746,6 +752,11 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared, ...@@ -746,6 +752,11 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
/* Check if one of the bits is set in both bitsets */
if (!(this->bitset & bitset))
continue;
wake_futex(this); wake_futex(this);
if (++ret >= nr_wake) if (++ret >= nr_wake)
break; break;
...@@ -1156,7 +1167,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, ...@@ -1156,7 +1167,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
static long futex_wait_restart(struct restart_block *restart); static long futex_wait_restart(struct restart_block *restart);
static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared, static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
u32 val, ktime_t *abs_time) u32 val, ktime_t *abs_time, u32 bitset)
{ {
struct task_struct *curr = current; struct task_struct *curr = current;
DECLARE_WAITQUEUE(wait, curr); DECLARE_WAITQUEUE(wait, curr);
...@@ -1167,7 +1178,11 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared, ...@@ -1167,7 +1178,11 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
struct hrtimer_sleeper t; struct hrtimer_sleeper t;
int rem = 0; int rem = 0;
if (!bitset)
return -EINVAL;
q.pi_state = NULL; q.pi_state = NULL;
q.bitset = bitset;
retry: retry:
futex_lock_mm(fshared); futex_lock_mm(fshared);
...@@ -1252,6 +1267,8 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared, ...@@ -1252,6 +1267,8 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
t.timer.expires = *abs_time; t.timer.expires = *abs_time;
hrtimer_start(&t.timer, t.timer.expires, HRTIMER_MODE_ABS); hrtimer_start(&t.timer, t.timer.expires, HRTIMER_MODE_ABS);
if (!hrtimer_active(&t.timer))
t.task = NULL;
/* /*
* the timer could have already expired, in which * the timer could have already expired, in which
...@@ -1293,6 +1310,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared, ...@@ -1293,6 +1310,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
restart->futex.uaddr = (u32 *)uaddr; restart->futex.uaddr = (u32 *)uaddr;
restart->futex.val = val; restart->futex.val = val;
restart->futex.time = abs_time->tv64; restart->futex.time = abs_time->tv64;
restart->futex.bitset = bitset;
restart->futex.flags = 0; restart->futex.flags = 0;
if (fshared) if (fshared)
...@@ -1319,7 +1337,8 @@ static long futex_wait_restart(struct restart_block *restart) ...@@ -1319,7 +1337,8 @@ static long futex_wait_restart(struct restart_block *restart)
restart->fn = do_no_restart_syscall; restart->fn = do_no_restart_syscall;
if (restart->futex.flags & FLAGS_SHARED) if (restart->futex.flags & FLAGS_SHARED)
fshared = &current->mm->mmap_sem; fshared = &current->mm->mmap_sem;
return (long)futex_wait(uaddr, fshared, restart->futex.val, &t); return (long)futex_wait(uaddr, fshared, restart->futex.val, &t,
restart->futex.bitset);
} }
...@@ -1535,9 +1554,6 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared, ...@@ -1535,9 +1554,6 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
owner = rt_mutex_owner(&q.pi_state->pi_mutex); owner = rt_mutex_owner(&q.pi_state->pi_mutex);
res = fixup_pi_state_owner(uaddr, &q, owner); res = fixup_pi_state_owner(uaddr, &q, owner);
WARN_ON(rt_mutex_owner(&q.pi_state->pi_mutex) !=
owner);
/* propagate -EFAULT, if the fixup failed */ /* propagate -EFAULT, if the fixup failed */
if (res) if (res)
ret = res; ret = res;
...@@ -1943,7 +1959,8 @@ int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi) ...@@ -1943,7 +1959,8 @@ int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)
* PI futexes happens in exit_pi_state(): * PI futexes happens in exit_pi_state():
*/ */
if (!pi && (uval & FUTEX_WAITERS)) if (!pi && (uval & FUTEX_WAITERS))
futex_wake(uaddr, &curr->mm->mmap_sem, 1); futex_wake(uaddr, &curr->mm->mmap_sem, 1,
FUTEX_BITSET_MATCH_ANY);
} }
return 0; return 0;
} }
...@@ -2043,10 +2060,14 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, ...@@ -2043,10 +2060,14 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
switch (cmd) { switch (cmd) {
case FUTEX_WAIT: case FUTEX_WAIT:
ret = futex_wait(uaddr, fshared, val, timeout); val3 = FUTEX_BITSET_MATCH_ANY;
case FUTEX_WAIT_BITSET:
ret = futex_wait(uaddr, fshared, val, timeout, val3);
break; break;
case FUTEX_WAKE: case FUTEX_WAKE:
ret = futex_wake(uaddr, fshared, val); val3 = FUTEX_BITSET_MATCH_ANY;
case FUTEX_WAKE_BITSET:
ret = futex_wake(uaddr, fshared, val, val3);
break; break;
case FUTEX_FD: case FUTEX_FD:
/* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */ /* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
...@@ -2086,7 +2107,8 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val, ...@@ -2086,7 +2107,8 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
u32 val2 = 0; u32 val2 = 0;
int cmd = op & FUTEX_CMD_MASK; int cmd = op & FUTEX_CMD_MASK;
if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) { if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
cmd == FUTEX_WAIT_BITSET)) {
if (copy_from_user(&ts, utime, sizeof(ts)) != 0) if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
return -EFAULT; return -EFAULT;
if (!timespec_valid(&ts)) if (!timespec_valid(&ts))
......
...@@ -167,7 +167,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val, ...@@ -167,7 +167,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
int val2 = 0; int val2 = 0;
int cmd = op & FUTEX_CMD_MASK; int cmd = op & FUTEX_CMD_MASK;
if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) { if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
cmd == FUTEX_WAIT_BITSET)) {
if (get_compat_timespec(&ts, utime)) if (get_compat_timespec(&ts, utime))
return -EFAULT; return -EFAULT;
if (!timespec_valid(&ts)) if (!timespec_valid(&ts))
......
...@@ -1315,6 +1315,8 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod ...@@ -1315,6 +1315,8 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
} while (t->task && !signal_pending(current)); } while (t->task && !signal_pending(current));
__set_current_state(TASK_RUNNING);
return t->task == NULL; return t->task == NULL;
} }
......
...@@ -129,6 +129,7 @@ static inline void warp_clock(void) ...@@ -129,6 +129,7 @@ static inline void warp_clock(void)
write_seqlock_irq(&xtime_lock); write_seqlock_irq(&xtime_lock);
wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60; wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
xtime.tv_sec += sys_tz.tz_minuteswest * 60; xtime.tv_sec += sys_tz.tz_minuteswest * 60;
update_xtime_cache(0);
write_sequnlock_irq(&xtime_lock); write_sequnlock_irq(&xtime_lock);
clock_was_set(); clock_was_set();
} }
......
...@@ -137,6 +137,7 @@ void tick_nohz_update_jiffies(void) ...@@ -137,6 +137,7 @@ void tick_nohz_update_jiffies(void)
cpu_clear(cpu, nohz_cpu_mask); cpu_clear(cpu, nohz_cpu_mask);
now = ktime_get(); now = ktime_get();
ts->idle_waketime = now;
local_irq_save(flags); local_irq_save(flags);
tick_do_update_jiffies64(now); tick_do_update_jiffies64(now);
...@@ -400,6 +401,7 @@ void tick_nohz_restart_sched_tick(void) ...@@ -400,6 +401,7 @@ void tick_nohz_restart_sched_tick(void)
* Cancel the scheduled timer and restore the tick * Cancel the scheduled timer and restore the tick
*/ */
ts->tick_stopped = 0; ts->tick_stopped = 0;
ts->idle_exittime = now;
hrtimer_cancel(&ts->sched_timer); hrtimer_cancel(&ts->sched_timer);
ts->sched_timer.expires = ts->idle_tick; ts->sched_timer.expires = ts->idle_tick;
......
...@@ -47,7 +47,7 @@ struct timespec wall_to_monotonic __attribute__ ((aligned (16))); ...@@ -47,7 +47,7 @@ struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
static unsigned long total_sleep_time; /* seconds */ static unsigned long total_sleep_time; /* seconds */
static struct timespec xtime_cache __attribute__ ((aligned (16))); static struct timespec xtime_cache __attribute__ ((aligned (16)));
static inline void update_xtime_cache(u64 nsec) void update_xtime_cache(u64 nsec)
{ {
xtime_cache = xtime; xtime_cache = xtime;
timespec_add_ns(&xtime_cache, nsec); timespec_add_ns(&xtime_cache, nsec);
...@@ -145,6 +145,7 @@ int do_settimeofday(struct timespec *tv) ...@@ -145,6 +145,7 @@ int do_settimeofday(struct timespec *tv)
set_normalized_timespec(&xtime, sec, nsec); set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
update_xtime_cache(0);
clock->error = 0; clock->error = 0;
ntp_clear(); ntp_clear();
...@@ -252,8 +253,8 @@ void __init timekeeping_init(void) ...@@ -252,8 +253,8 @@ void __init timekeeping_init(void)
xtime.tv_nsec = 0; xtime.tv_nsec = 0;
set_normalized_timespec(&wall_to_monotonic, set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec); -xtime.tv_sec, -xtime.tv_nsec);
update_xtime_cache(0);
total_sleep_time = 0; total_sleep_time = 0;
write_sequnlock_irqrestore(&xtime_lock, flags); write_sequnlock_irqrestore(&xtime_lock, flags);
} }
...@@ -290,6 +291,7 @@ static int timekeeping_resume(struct sys_device *dev) ...@@ -290,6 +291,7 @@ static int timekeeping_resume(struct sys_device *dev)
} }
/* Make sure that we have the correct xtime reference */ /* Make sure that we have the correct xtime reference */
timespec_add_ns(&xtime, timekeeping_suspend_nsecs); timespec_add_ns(&xtime, timekeeping_suspend_nsecs);
update_xtime_cache(0);
/* re-base the last cycle value */ /* re-base the last cycle value */
clock->cycle_last = clocksource_read(clock); clock->cycle_last = clocksource_read(clock);
clock->error = 0; clock->error = 0;
......
...@@ -166,6 +166,8 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now) ...@@ -166,6 +166,8 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
P(idle_calls); P(idle_calls);
P(idle_sleeps); P(idle_sleeps);
P_ns(idle_entrytime); P_ns(idle_entrytime);
P_ns(idle_waketime);
P_ns(idle_exittime);
P_ns(idle_sleeptime); P_ns(idle_sleeptime);
P(last_jiffies); P(last_jiffies);
P(next_jiffies); P(next_jiffies);
......
...@@ -581,7 +581,7 @@ config LATENCYTOP ...@@ -581,7 +581,7 @@ config LATENCYTOP
select STACKTRACE select STACKTRACE
select SCHEDSTATS select SCHEDSTATS
select SCHED_DEBUG select SCHED_DEBUG
depends on X86 || X86_64 depends on HAVE_LATENCYTOP_SUPPORT
help help
Enable this option if you want to use the LatencyTOP tool Enable this option if you want to use the LatencyTOP tool
to find out which userspace is blocking on what kernel operations. to find out which userspace is blocking on what kernel operations.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment