2006-06-27 13:54:55 +04:00
/*
* 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 code is based on the rt . c implementation in the preempt - rt tree .
* Portions of said code are
*
* Copyright ( C ) 2004 LynuxWorks , Inc . , Igor Manyilov , Bill Huey
* Copyright ( C ) 2006 Esben Nielsen
* Copyright ( C ) 2006 Kihon Technologies Inc . ,
* Steven Rostedt < rostedt @ goodmis . org >
*
* See rt . c in preempt - rt for proper credits and further information
*/
# include <linux/sched.h>
2013-02-07 19:47:07 +04:00
# include <linux/sched/rt.h>
2017-02-08 20:51:35 +03:00
# include <linux/sched/debug.h>
2006-06-27 13:54:55 +04:00
# include <linux/delay.h>
2011-05-23 22:51:41 +04:00
# include <linux/export.h>
2006-06-27 13:54:55 +04:00
# include <linux/spinlock.h>
# include <linux/kallsyms.h>
# include <linux/syscalls.h>
# include <linux/interrupt.h>
rtmutex: Turn the plist into an rb-tree
Turn the pi-chains from plist to rb-tree, in the rt_mutex code,
and provide a proper comparison function for -deadline and
-priority tasks.
This is done mainly because:
- classical prio field of the plist is just an int, which might
not be enough for representing a deadline;
- manipulating such a list would become O(nr_deadline_tasks),
which might be to much, as the number of -deadline task increases.
Therefore, an rb-tree is used, and tasks are queued in it according
to the following logic:
- among two -priority (i.e., SCHED_BATCH/OTHER/RR/FIFO) tasks, the
one with the higher (lower, actually!) prio wins;
- among a -priority and a -deadline task, the latter always wins;
- among two -deadline tasks, the one with the earliest deadline
wins.
Queueing and dequeueing functions are changed accordingly, for both
the list of a task's pi-waiters and the list of tasks blocked on
a pi-lock.
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-again-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-10-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 17:43:43 +04:00
# include <linux/rbtree.h>
2006-06-27 13:54:55 +04:00
# include <linux/fs.h>
2006-07-03 11:24:33 +04:00
# include <linux/debug_locks.h>
2006-06-27 13:54:55 +04:00
# include "rtmutex_common.h"
2006-07-03 11:25:41 +04:00
static void printk_task ( struct task_struct * p )
2006-06-27 13:54:55 +04:00
{
if ( p )
2007-10-19 10:40:40 +04:00
printk ( " %16s:%5d [%p, %3d] " , p - > comm , task_pid_nr ( p ) , p , p - > prio ) ;
2006-06-27 13:54:55 +04:00
else
printk ( " <none> " ) ;
}
static void printk_lock ( struct rt_mutex * lock , int print_owner )
{
if ( lock - > name )
printk ( " [%p] {%s} \n " ,
lock , lock - > name ) ;
else
printk ( " [%p] {%s:%d} \n " ,
lock , lock - > file , lock - > line ) ;
if ( print_owner & & rt_mutex_owner ( lock ) ) {
printk ( " .. ->owner: %p \n " , lock - > owner ) ;
printk ( " .. held by: " ) ;
printk_task ( rt_mutex_owner ( lock ) ) ;
printk ( " \n " ) ;
}
}
void rt_mutex_debug_task_free ( struct task_struct * task )
{
rtmutex: Turn the plist into an rb-tree
Turn the pi-chains from plist to rb-tree, in the rt_mutex code,
and provide a proper comparison function for -deadline and
-priority tasks.
This is done mainly because:
- classical prio field of the plist is just an int, which might
not be enough for representing a deadline;
- manipulating such a list would become O(nr_deadline_tasks),
which might be to much, as the number of -deadline task increases.
Therefore, an rb-tree is used, and tasks are queued in it according
to the following logic:
- among two -priority (i.e., SCHED_BATCH/OTHER/RR/FIFO) tasks, the
one with the higher (lower, actually!) prio wins;
- among a -priority and a -deadline task, the latter always wins;
- among two -deadline tasks, the one with the earliest deadline
wins.
Queueing and dequeueing functions are changed accordingly, for both
the list of a task's pi-waiters and the list of tasks blocked on
a pi-lock.
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-again-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-10-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 17:43:43 +04:00
DEBUG_LOCKS_WARN_ON ( ! RB_EMPTY_ROOT ( & task - > pi_waiters ) ) ;
2011-06-08 11:58:38 +04:00
DEBUG_LOCKS_WARN_ON ( task - > pi_blocked_on ) ;
2006-06-27 13:54:55 +04:00
}
/*
* We fill out the fields in the waiter to store the information about
* the deadlock . We print when we return . act_waiter can be NULL in
* case of a remove waiter operation .
*/
2014-05-22 07:25:47 +04:00
void debug_rt_mutex_deadlock ( enum rtmutex_chainwalk chwalk ,
struct rt_mutex_waiter * act_waiter ,
2006-06-27 13:54:55 +04:00
struct rt_mutex * lock )
{
struct task_struct * task ;
2014-05-22 07:25:47 +04:00
if ( ! debug_locks | | chwalk = = RT_MUTEX_FULL_CHAINWALK | | ! act_waiter )
2006-06-27 13:54:55 +04:00
return ;
task = rt_mutex_owner ( act_waiter - > lock ) ;
if ( task & & task ! = current ) {
2008-02-08 15:21:53 +03:00
act_waiter - > deadlock_task_pid = get_pid ( task_pid ( task ) ) ;
2006-06-27 13:54:55 +04:00
act_waiter - > deadlock_lock = lock ;
}
}
void debug_rt_mutex_print_deadlock ( struct rt_mutex_waiter * waiter )
{
struct task_struct * task ;
2011-06-08 11:58:38 +04:00
if ( ! waiter - > deadlock_lock | | ! debug_locks )
2006-06-27 13:54:55 +04:00
return ;
2008-02-08 15:21:53 +03:00
rcu_read_lock ( ) ;
task = pid_task ( waiter - > deadlock_task_pid , PIDTYPE_PID ) ;
if ( ! task ) {
rcu_read_unlock ( ) ;
2006-06-27 13:54:55 +04:00
return ;
2008-02-08 15:21:53 +03:00
}
2006-06-27 13:54:55 +04:00
2011-10-05 15:20:24 +04:00
if ( ! debug_locks_off ( ) ) {
rcu_read_unlock ( ) ;
2011-06-08 11:58:38 +04:00
return ;
2011-10-05 15:20:24 +04:00
}
2006-06-27 13:54:55 +04:00
printk ( " \n ============================================ \n " ) ;
printk ( " [ BUG: circular locking deadlock detected! ] \n " ) ;
2011-10-28 07:36:55 +04:00
printk ( " %s \n " , print_tainted ( ) ) ;
2006-06-27 13:54:55 +04:00
printk ( " -------------------------------------------- \n " ) ;
printk ( " %s/%d is deadlocking current task %s/%d \n \n " ,
2007-10-19 10:40:40 +04:00
task - > comm , task_pid_nr ( task ) ,
current - > comm , task_pid_nr ( current ) ) ;
2006-06-27 13:54:55 +04:00
printk ( " \n 1) %s/%d is trying to acquire this lock: \n " ,
2007-10-19 10:40:40 +04:00
current - > comm , task_pid_nr ( current ) ) ;
2006-06-27 13:54:55 +04:00
printk_lock ( waiter - > lock , 1 ) ;
2007-10-19 10:40:40 +04:00
printk ( " \n 2) %s/%d is blocked on this lock: \n " ,
task - > comm , task_pid_nr ( task ) ) ;
2006-06-27 13:54:55 +04:00
printk_lock ( waiter - > deadlock_lock , 1 ) ;
2006-07-03 11:24:33 +04:00
debug_show_held_locks ( current ) ;
debug_show_held_locks ( task ) ;
2006-06-27 13:54:55 +04:00
2007-10-19 10:40:40 +04:00
printk ( " \n %s/%d's [blocked] stackdump: \n \n " ,
task - > comm , task_pid_nr ( task ) ) ;
2006-06-27 13:54:55 +04:00
show_stack ( task , NULL ) ;
printk ( " \n %s/%d's [current] stackdump: \n \n " ,
2007-10-19 10:40:40 +04:00
current - > comm , task_pid_nr ( current ) ) ;
2006-06-27 13:54:55 +04:00
dump_stack ( ) ;
2006-07-03 11:24:33 +04:00
debug_show_all_locks ( ) ;
2008-02-08 15:21:53 +03:00
rcu_read_unlock ( ) ;
2006-07-03 11:24:33 +04:00
2006-06-27 13:54:55 +04:00
printk ( " [ turning off deadlock detection. "
" Please report this trace. ] \n \n " ) ;
}
2006-07-03 11:24:33 +04:00
void debug_rt_mutex_lock ( struct rt_mutex * lock )
2006-06-27 13:54:55 +04:00
{
}
void debug_rt_mutex_unlock ( struct rt_mutex * lock )
{
2011-06-08 11:58:38 +04:00
DEBUG_LOCKS_WARN_ON ( rt_mutex_owner ( lock ) ! = current ) ;
2006-06-27 13:54:55 +04:00
}
2006-07-03 11:24:33 +04:00
void
debug_rt_mutex_proxy_lock ( struct rt_mutex * lock , struct task_struct * powner )
2006-06-27 13:54:55 +04:00
{
}
void debug_rt_mutex_proxy_unlock ( struct rt_mutex * lock )
{
2011-06-08 11:58:38 +04:00
DEBUG_LOCKS_WARN_ON ( ! rt_mutex_owner ( lock ) ) ;
2006-06-27 13:54:55 +04:00
}
void debug_rt_mutex_init_waiter ( struct rt_mutex_waiter * waiter )
{
memset ( waiter , 0x11 , sizeof ( * waiter ) ) ;
2008-02-08 15:21:53 +03:00
waiter - > deadlock_task_pid = NULL ;
2006-06-27 13:54:55 +04:00
}
void debug_rt_mutex_free_waiter ( struct rt_mutex_waiter * waiter )
{
2008-02-08 15:21:53 +03:00
put_pid ( waiter - > deadlock_task_pid ) ;
2006-06-27 13:54:55 +04:00
memset ( waiter , 0x22 , sizeof ( * waiter ) ) ;
}
void debug_rt_mutex_init ( struct rt_mutex * lock , const char * name )
{
2006-07-03 11:24:33 +04:00
/*
* Make sure we are not reinitializing a held lock :
*/
debug_check_no_locks_freed ( ( void * ) lock , sizeof ( * lock ) ) ;
lock - > name = name ;
2006-06-27 13:54:55 +04:00
}
2006-07-03 11:25:41 +04:00
void
rt_mutex_deadlock_account_lock ( struct rt_mutex * lock , struct task_struct * task )
2006-06-27 13:54:55 +04:00
{
}
void rt_mutex_deadlock_account_unlock ( struct task_struct * task )
{
}