Commit 23f78d4a authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] pi-futex: rt mutex core

Core functions for the rt-mutex subsystem.
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarArjan van de Ven <arjan@linux.intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b29739f9
...@@ -124,6 +124,7 @@ extern struct group_info init_groups; ...@@ -124,6 +124,7 @@ extern struct group_info init_groups;
.cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \
.fs_excl = ATOMIC_INIT(0), \ .fs_excl = ATOMIC_INIT(0), \
.pi_lock = SPIN_LOCK_UNLOCKED, \ .pi_lock = SPIN_LOCK_UNLOCKED, \
INIT_RT_MUTEXES(tsk) \
} }
......
/*
* RT Mutexes: blocking mutual exclusion locks with PI support
*
* started by Ingo Molnar and Thomas Gleixner:
*
* Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
* Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
*
* This file contains the public data structure and API definitions.
*/
#ifndef __LINUX_RT_MUTEX_H
#define __LINUX_RT_MUTEX_H
#include <linux/linkage.h>
#include <linux/plist.h>
#include <linux/spinlock_types.h>
/*
* The rt_mutex structure
*
* @wait_lock: spinlock to protect the structure
* @wait_list: pilist head to enqueue waiters in priority order
* @owner: the mutex owner
*/
struct rt_mutex {
spinlock_t wait_lock;
struct plist_head wait_list;
struct task_struct *owner;
#ifdef CONFIG_DEBUG_RT_MUTEXES
int save_state;
struct list_head held_list_entry;
unsigned long acquire_ip;
const char *name, *file;
int line;
void *magic;
#endif
};
struct rt_mutex_waiter;
struct hrtimer_sleeper;
#ifdef CONFIG_DEBUG_RT_MUTEXES
# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname) \
, .name = #mutexname, .file = __FILE__, .line = __LINE__
# define rt_mutex_init(mutex) __rt_mutex_init(mutex, __FUNCTION__)
extern void rt_mutex_debug_task_free(struct task_struct *tsk);
#else
# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname)
# define rt_mutex_init(mutex) __rt_mutex_init(mutex, NULL)
# define rt_mutex_debug_task_free(t) do { } while (0)
#endif
#define __RT_MUTEX_INITIALIZER(mutexname) \
{ .wait_lock = SPIN_LOCK_UNLOCKED \
, .wait_list = PLIST_HEAD_INIT(mutexname.wait_list, mutexname.wait_lock) \
, .owner = NULL \
__DEBUG_RT_MUTEX_INITIALIZER(mutexname)}
#define DEFINE_RT_MUTEX(mutexname) \
struct rt_mutex mutexname = __RT_MUTEX_INITIALIZER(mutexname)
/***
* rt_mutex_is_locked - is the mutex locked
* @lock: the mutex to be queried
*
* Returns 1 if the mutex is locked, 0 if unlocked.
*/
static inline int rt_mutex_is_locked(struct rt_mutex *lock)
{
return lock->owner != NULL;
}
extern void __rt_mutex_init(struct rt_mutex *lock, const char *name);
extern void rt_mutex_destroy(struct rt_mutex *lock);
extern void rt_mutex_lock(struct rt_mutex *lock);
extern int rt_mutex_lock_interruptible(struct rt_mutex *lock,
int detect_deadlock);
extern int rt_mutex_timed_lock(struct rt_mutex *lock,
struct hrtimer_sleeper *timeout,
int detect_deadlock);
extern int rt_mutex_trylock(struct rt_mutex *lock);
extern void rt_mutex_unlock(struct rt_mutex *lock);
#ifdef CONFIG_DEBUG_RT_MUTEXES
# define INIT_RT_MUTEX_DEBUG(tsk) \
.held_list_head = LIST_HEAD_INIT(tsk.held_list_head), \
.held_list_lock = SPIN_LOCK_UNLOCKED
#else
# define INIT_RT_MUTEX_DEBUG(tsk)
#endif
#ifdef CONFIG_RT_MUTEXES
# define INIT_RT_MUTEXES(tsk) \
.pi_waiters = PLIST_HEAD_INIT(tsk.pi_waiters, tsk.pi_lock), \
INIT_RT_MUTEX_DEBUG(tsk)
#else
# define INIT_RT_MUTEXES(tsk)
#endif
#endif
...@@ -73,6 +73,7 @@ struct sched_param { ...@@ -73,6 +73,7 @@ struct sched_param {
#include <linux/seccomp.h> #include <linux/seccomp.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/futex.h> #include <linux/futex.h>
#include <linux/rtmutex.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/param.h> #include <linux/param.h>
...@@ -858,6 +859,17 @@ struct task_struct { ...@@ -858,6 +859,17 @@ struct task_struct {
/* Protection of the PI data structures: */ /* Protection of the PI data structures: */
spinlock_t pi_lock; spinlock_t pi_lock;
#ifdef CONFIG_RT_MUTEXES
/* PI waiters blocked on a rt_mutex held by this task */
struct plist_head pi_waiters;
/* Deadlock detection and priority inheritance handling */
struct rt_mutex_waiter *pi_blocked_on;
# ifdef CONFIG_DEBUG_RT_MUTEXES
spinlock_t held_list_lock;
struct list_head held_list_head;
# endif
#endif
#ifdef CONFIG_DEBUG_MUTEXES #ifdef CONFIG_DEBUG_MUTEXES
/* mutex deadlock detection */ /* mutex deadlock detection */
struct mutex_waiter *blocked_on; struct mutex_waiter *blocked_on;
......
...@@ -149,6 +149,7 @@ enum ...@@ -149,6 +149,7 @@ enum
KERN_ACPI_VIDEO_FLAGS=71, /* int: flags for setting up video after ACPI sleep */ KERN_ACPI_VIDEO_FLAGS=71, /* int: flags for setting up video after ACPI sleep */
KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */ KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */
KERN_COMPAT_LOG=73, /* int: print compat layer messages */ KERN_COMPAT_LOG=73, /* int: print compat layer messages */
KERN_MAX_LOCK_DEPTH=74,
}; };
......
...@@ -339,9 +339,14 @@ config BASE_FULL ...@@ -339,9 +339,14 @@ config BASE_FULL
kernel data structures. This saves memory on small machines, kernel data structures. This saves memory on small machines,
but may reduce performance. but may reduce performance.
config RT_MUTEXES
boolean
select PLIST
config FUTEX config FUTEX
bool "Enable futex support" if EMBEDDED bool "Enable futex support" if EMBEDDED
default y default y
select RT_MUTEXES
help help
Disabling this option will cause the kernel to be built without Disabling this option will cause the kernel to be built without
support for "fast userspace mutexes". The resulting kernel may not support for "fast userspace mutexes". The resulting kernel may not
......
...@@ -16,6 +16,7 @@ obj-$(CONFIG_FUTEX) += futex.o ...@@ -16,6 +16,7 @@ obj-$(CONFIG_FUTEX) += futex.o
ifeq ($(CONFIG_COMPAT),y) ifeq ($(CONFIG_COMPAT),y)
obj-$(CONFIG_FUTEX) += futex_compat.o obj-$(CONFIG_FUTEX) += futex_compat.o
endif endif
obj-$(CONFIG_RT_MUTEXES) += rtmutex.o
obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
obj-$(CONFIG_SMP) += cpu.o spinlock.o obj-$(CONFIG_SMP) += cpu.o spinlock.o
obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
......
...@@ -104,6 +104,7 @@ static kmem_cache_t *mm_cachep; ...@@ -104,6 +104,7 @@ static kmem_cache_t *mm_cachep;
void free_task(struct task_struct *tsk) void free_task(struct task_struct *tsk)
{ {
free_thread_info(tsk->thread_info); free_thread_info(tsk->thread_info);
rt_mutex_debug_task_free(tsk);
free_task_struct(tsk); free_task_struct(tsk);
} }
EXPORT_SYMBOL(free_task); EXPORT_SYMBOL(free_task);
...@@ -913,6 +914,19 @@ asmlinkage long sys_set_tid_address(int __user *tidptr) ...@@ -913,6 +914,19 @@ asmlinkage long sys_set_tid_address(int __user *tidptr)
return current->pid; return current->pid;
} }
static inline void rt_mutex_init_task(struct task_struct *p)
{
#ifdef CONFIG_RT_MUTEXES
spin_lock_init(&p->pi_lock);
plist_head_init(&p->pi_waiters, &p->pi_lock);
p->pi_blocked_on = NULL;
# ifdef CONFIG_DEBUG_RT_MUTEXES
spin_lock_init(&p->held_list_lock);
INIT_LIST_HEAD(&p->held_list_head);
# endif
#endif
}
/* /*
* This creates a new process as a copy of the old one, * This creates a new process as a copy of the old one,
* but does not actually start it yet. * but does not actually start it yet.
...@@ -1034,6 +1048,8 @@ static task_t *copy_process(unsigned long clone_flags, ...@@ -1034,6 +1048,8 @@ static task_t *copy_process(unsigned long clone_flags,
mpol_fix_fork_child_flag(p); mpol_fix_fork_child_flag(p);
#endif #endif
rt_mutex_init_task(p);
#ifdef CONFIG_DEBUG_MUTEXES #ifdef CONFIG_DEBUG_MUTEXES
p->blocked_on = NULL; /* not blocked yet */ p->blocked_on = NULL; /* not blocked yet */
#endif #endif
......
This diff is collapsed.
/*
* RT-Mutexes: blocking mutual exclusion locks with PI support
*
* started by Ingo Molnar and Thomas Gleixner:
*
* Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
* Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
*
* This file contains macros used solely by rtmutex.c.
* Non-debug version.
*/
#define __IP_DECL__
#define __IP__
#define __RET_IP__
#define rt_mutex_deadlock_check(l) (0)
#define rt_mutex_deadlock_account_lock(m, t) do { } while (0)
#define rt_mutex_deadlock_account_unlock(l) do { } while (0)
#define debug_rt_mutex_init_waiter(w) do { } while (0)
#define debug_rt_mutex_free_waiter(w) do { } while (0)
#define debug_rt_mutex_lock(l) do { } while (0)
#define debug_rt_mutex_proxy_lock(l,p) do { } while (0)
#define debug_rt_mutex_proxy_unlock(l) do { } while (0)
#define debug_rt_mutex_unlock(l) do { } while (0)
#define debug_rt_mutex_init(m, n) do { } while (0)
#define debug_rt_mutex_deadlock(d, a ,l) do { } while (0)
#define debug_rt_mutex_print_deadlock(w) do { } while (0)
#define debug_rt_mutex_detect_deadlock(w,d) (d)
#define debug_rt_mutex_reset_waiter(w) do { } while (0)
/*
* RT Mutexes: blocking mutual exclusion locks with PI support
*
* started by Ingo Molnar and Thomas Gleixner:
*
* Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
* Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
*
* This file contains the private data structure and API definitions.
*/
#ifndef __KERNEL_RTMUTEX_COMMON_H
#define __KERNEL_RTMUTEX_COMMON_H
#include <linux/rtmutex.h>
/*
* This is the control structure for tasks blocked on a rt_mutex,
* which is allocated on the kernel stack on of the blocked task.
*
* @list_entry: pi node to enqueue into the mutex waiters list
* @pi_list_entry: pi node to enqueue into the mutex owner waiters list
* @task: task reference to the blocked task
*/
struct rt_mutex_waiter {
struct plist_node list_entry;
struct plist_node pi_list_entry;
struct task_struct *task;
struct rt_mutex *lock;
#ifdef CONFIG_DEBUG_RT_MUTEXES
unsigned long ip;
pid_t deadlock_task_pid;
struct rt_mutex *deadlock_lock;
#endif
};
/*
* Various helpers to access the waiters-plist:
*/
static inline int rt_mutex_has_waiters(struct rt_mutex *lock)
{
return !plist_head_empty(&lock->wait_list);
}
static inline struct rt_mutex_waiter *
rt_mutex_top_waiter(struct rt_mutex *lock)
{
struct rt_mutex_waiter *w;
w = plist_first_entry(&lock->wait_list, struct rt_mutex_waiter,
list_entry);
BUG_ON(w->lock != lock);
return w;
}
static inline int task_has_pi_waiters(struct task_struct *p)
{
return !plist_head_empty(&p->pi_waiters);
}
static inline struct rt_mutex_waiter *
task_top_pi_waiter(struct task_struct *p)
{
return plist_first_entry(&p->pi_waiters, struct rt_mutex_waiter,
pi_list_entry);
}
/*
* lock->owner state tracking:
*/
#define RT_MUTEX_OWNER_PENDING 1UL
#define RT_MUTEX_HAS_WAITERS 2UL
#define RT_MUTEX_OWNER_MASKALL 3UL
static inline struct task_struct *rt_mutex_owner(struct rt_mutex *lock)
{
return (struct task_struct *)
((unsigned long)lock->owner & ~RT_MUTEX_OWNER_MASKALL);
}
static inline struct task_struct *rt_mutex_real_owner(struct rt_mutex *lock)
{
return (struct task_struct *)
((unsigned long)lock->owner & ~RT_MUTEX_HAS_WAITERS);
}
static inline unsigned long rt_mutex_owner_pending(struct rt_mutex *lock)
{
return (unsigned long)lock->owner & RT_MUTEX_OWNER_PENDING;
}
#endif
...@@ -133,6 +133,10 @@ extern int acct_parm[]; ...@@ -133,6 +133,10 @@ extern int acct_parm[];
extern int no_unaligned_warning; extern int no_unaligned_warning;
#endif #endif
#ifdef CONFIG_RT_MUTEXES
extern int max_lock_depth;
#endif
static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t, static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t,
ctl_table *, void **); ctl_table *, void **);
static int proc_doutsstring(ctl_table *table, int write, struct file *filp, static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
...@@ -688,6 +692,17 @@ static ctl_table kern_table[] = { ...@@ -688,6 +692,17 @@ static ctl_table kern_table[] = {
.proc_handler = &proc_dointvec, .proc_handler = &proc_dointvec,
}, },
#endif #endif
#ifdef CONFIG_RT_MUTEXES
{
.ctl_name = KERN_MAX_LOCK_DEPTH,
.procname = "max_lock_depth",
.data = &max_lock_depth,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
#endif
{ .ctl_name = 0 } { .ctl_name = 0 }
}; };
......
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