/* * Mutexes: blocking mutual exclusion locks * * started by Ingo Molnar: * * Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar * * This file contains mutex debugging related internal declarations, * prototypes and inline functions, for the CONFIG_DEBUG_MUTEXES case. * More details are in kernel/mutex-debug.c. */ extern spinlock_t debug_mutex_lock; extern struct list_head debug_mutex_held_locks; extern int debug_mutex_on; /* * In the debug case we carry the caller's instruction pointer into * other functions, but we dont want the function argument overhead * in the nondebug case - hence these macros: */ #define __IP_DECL__ , unsigned long ip #define __IP__ , ip #define __RET_IP__ , (unsigned long)__builtin_return_address(0) /* * This must be called with lock->wait_lock held. */ extern void debug_mutex_set_owner(struct mutex *lock, struct thread_info *new_owner __IP_DECL__); static inline void debug_mutex_clear_owner(struct mutex *lock) { lock->owner = NULL; } extern void debug_mutex_init_waiter(struct mutex_waiter *waiter); extern void debug_mutex_wake_waiter(struct mutex *lock, struct mutex_waiter *waiter); extern void debug_mutex_free_waiter(struct mutex_waiter *waiter); extern void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter, struct thread_info *ti __IP_DECL__); extern void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter, struct thread_info *ti); extern void debug_mutex_unlock(struct mutex *lock); extern void debug_mutex_init(struct mutex *lock, const char *name); #define debug_spin_lock(lock) \ do { \ local_irq_disable(); \ if (debug_mutex_on) \ spin_lock(lock); \ } while (0) #define debug_spin_unlock(lock) \ do { \ if (debug_mutex_on) \ spin_unlock(lock); \ local_irq_enable(); \ preempt_check_resched(); \ } while (0) #define debug_spin_lock_save(lock, flags) \ do { \ local_irq_save(flags); \ if (debug_mutex_on) \ spin_lock(lock); \ } while (0) #define debug_spin_lock_restore(lock, flags) \ do { \ if (debug_mutex_on) \ spin_unlock(lock); \ local_irq_restore(flags); \ preempt_check_resched(); \ } while (0) #define spin_lock_mutex(lock) \ do { \ struct mutex *l = container_of(lock, struct mutex, wait_lock); \ \ DEBUG_WARN_ON(in_interrupt()); \ debug_spin_lock(&debug_mutex_lock); \ spin_lock(lock); \ DEBUG_WARN_ON(l->magic != l); \ } while (0) #define spin_unlock_mutex(lock) \ do { \ spin_unlock(lock); \ debug_spin_unlock(&debug_mutex_lock); \ } while (0) #define DEBUG_OFF() \ do { \ if (debug_mutex_on) { \ debug_mutex_on = 0; \ console_verbose(); \ if (spin_is_locked(&debug_mutex_lock)) \ spin_unlock(&debug_mutex_lock); \ } \ } while (0) #define DEBUG_BUG() \ do { \ if (debug_mutex_on) { \ DEBUG_OFF(); \ BUG(); \ } \ } while (0) #define DEBUG_WARN_ON(c) \ do { \ if (unlikely(c && debug_mutex_on)) { \ DEBUG_OFF(); \ WARN_ON(1); \ } \ } while (0) # define DEBUG_BUG_ON(c) \ do { \ if (unlikely(c)) \ DEBUG_BUG(); \ } while (0) #ifdef CONFIG_SMP # define SMP_DEBUG_WARN_ON(c) DEBUG_WARN_ON(c) # define SMP_DEBUG_BUG_ON(c) DEBUG_BUG_ON(c) #else # define SMP_DEBUG_WARN_ON(c) do { } while (0) # define SMP_DEBUG_BUG_ON(c) do { } while (0) #endif