diff options
Diffstat (limited to 'kernel/locking/rtmutex_common.h')
| -rw-r--r-- | kernel/locking/rtmutex_common.h | 135 | 
1 files changed, 92 insertions, 43 deletions
diff --git a/kernel/locking/rtmutex_common.h b/kernel/locking/rtmutex_common.h index a90c22abdbca..c47e8361bfb5 100644 --- a/kernel/locking/rtmutex_common.h +++ b/kernel/locking/rtmutex_common.h @@ -25,29 +25,90 @@   * @pi_tree_entry:	pi node to enqueue into the mutex owner waiters tree   * @task:		task reference to the blocked task   * @lock:		Pointer to the rt_mutex on which the waiter blocks + * @wake_state:		Wakeup state to use (TASK_NORMAL or TASK_RTLOCK_WAIT)   * @prio:		Priority of the waiter   * @deadline:		Deadline of the waiter if applicable + * @ww_ctx:		WW context pointer   */  struct rt_mutex_waiter {  	struct rb_node		tree_entry;  	struct rb_node		pi_tree_entry;  	struct task_struct	*task; -	struct rt_mutex		*lock; +	struct rt_mutex_base	*lock; +	unsigned int		wake_state;  	int			prio;  	u64			deadline; +	struct ww_acquire_ctx	*ww_ctx;  }; +/** + * rt_wake_q_head - Wrapper around regular wake_q_head to support + *		    "sleeping" spinlocks on RT + * @head:		The regular wake_q_head for sleeping lock variants + * @rtlock_task:	Task pointer for RT lock (spin/rwlock) wakeups + */ +struct rt_wake_q_head { +	struct wake_q_head	head; +	struct task_struct	*rtlock_task; +}; + +#define DEFINE_RT_WAKE_Q(name)						\ +	struct rt_wake_q_head name = {					\ +		.head		= WAKE_Q_HEAD_INITIALIZER(name.head),	\ +		.rtlock_task	= NULL,					\ +	} + +/* + * PI-futex support (proxy locking functions, etc.): + */ +extern void rt_mutex_init_proxy_locked(struct rt_mutex_base *lock, +				       struct task_struct *proxy_owner); +extern void rt_mutex_proxy_unlock(struct rt_mutex_base *lock); +extern int __rt_mutex_start_proxy_lock(struct rt_mutex_base *lock, +				     struct rt_mutex_waiter *waiter, +				     struct task_struct *task); +extern int rt_mutex_start_proxy_lock(struct rt_mutex_base *lock, +				     struct rt_mutex_waiter *waiter, +				     struct task_struct *task); +extern int rt_mutex_wait_proxy_lock(struct rt_mutex_base *lock, +			       struct hrtimer_sleeper *to, +			       struct rt_mutex_waiter *waiter); +extern bool rt_mutex_cleanup_proxy_lock(struct rt_mutex_base *lock, +				 struct rt_mutex_waiter *waiter); + +extern int rt_mutex_futex_trylock(struct rt_mutex_base *l); +extern int __rt_mutex_futex_trylock(struct rt_mutex_base *l); + +extern void rt_mutex_futex_unlock(struct rt_mutex_base *lock); +extern bool __rt_mutex_futex_unlock(struct rt_mutex_base *lock, +				struct rt_wake_q_head *wqh); + +extern void rt_mutex_postunlock(struct rt_wake_q_head *wqh); +  /*   * Must be guarded because this header is included from rcu/tree_plugin.h   * unconditionally.   */  #ifdef CONFIG_RT_MUTEXES -static inline int rt_mutex_has_waiters(struct rt_mutex *lock) +static inline int rt_mutex_has_waiters(struct rt_mutex_base *lock)  {  	return !RB_EMPTY_ROOT(&lock->waiters.rb_root);  } -static inline struct rt_mutex_waiter *rt_mutex_top_waiter(struct rt_mutex *lock) +/* + * Lockless speculative check whether @waiter is still the top waiter on + * @lock. This is solely comparing pointers and not derefencing the + * leftmost entry which might be about to vanish. + */ +static inline bool rt_mutex_waiter_is_top_waiter(struct rt_mutex_base *lock, +						 struct rt_mutex_waiter *waiter) +{ +	struct rb_node *leftmost = rb_first_cached(&lock->waiters); + +	return rb_entry(leftmost, struct rt_mutex_waiter, tree_entry) == waiter; +} + +static inline struct rt_mutex_waiter *rt_mutex_top_waiter(struct rt_mutex_base *lock)  {  	struct rb_node *leftmost = rb_first_cached(&lock->waiters);  	struct rt_mutex_waiter *w = NULL; @@ -72,19 +133,12 @@ static inline struct rt_mutex_waiter *task_top_pi_waiter(struct task_struct *p)  #define RT_MUTEX_HAS_WAITERS	1UL -static inline struct task_struct *rt_mutex_owner(struct rt_mutex *lock) +static inline struct task_struct *rt_mutex_owner(struct rt_mutex_base *lock)  {  	unsigned long owner = (unsigned long) READ_ONCE(lock->owner);  	return (struct task_struct *) (owner & ~RT_MUTEX_HAS_WAITERS);  } -#else /* CONFIG_RT_MUTEXES */ -/* Used in rcu/tree_plugin.h */ -static inline struct task_struct *rt_mutex_owner(struct rt_mutex *lock) -{ -	return NULL; -} -#endif  /* !CONFIG_RT_MUTEXES */  /*   * Constants for rt mutex functions which have a selectable deadlock @@ -101,49 +155,21 @@ enum rtmutex_chainwalk {  	RT_MUTEX_FULL_CHAINWALK,  }; -static inline void __rt_mutex_basic_init(struct rt_mutex *lock) +static inline void __rt_mutex_base_init(struct rt_mutex_base *lock)  { -	lock->owner = NULL;  	raw_spin_lock_init(&lock->wait_lock);  	lock->waiters = RB_ROOT_CACHED; +	lock->owner = NULL;  } -/* - * PI-futex support (proxy locking functions, etc.): - */ -extern void rt_mutex_init_proxy_locked(struct rt_mutex *lock, -				       struct task_struct *proxy_owner); -extern void rt_mutex_proxy_unlock(struct rt_mutex *lock); -extern void rt_mutex_init_waiter(struct rt_mutex_waiter *waiter); -extern int __rt_mutex_start_proxy_lock(struct rt_mutex *lock, -				     struct rt_mutex_waiter *waiter, -				     struct task_struct *task); -extern int rt_mutex_start_proxy_lock(struct rt_mutex *lock, -				     struct rt_mutex_waiter *waiter, -				     struct task_struct *task); -extern int rt_mutex_wait_proxy_lock(struct rt_mutex *lock, -			       struct hrtimer_sleeper *to, -			       struct rt_mutex_waiter *waiter); -extern bool rt_mutex_cleanup_proxy_lock(struct rt_mutex *lock, -				 struct rt_mutex_waiter *waiter); - -extern int rt_mutex_futex_trylock(struct rt_mutex *l); -extern int __rt_mutex_futex_trylock(struct rt_mutex *l); - -extern void rt_mutex_futex_unlock(struct rt_mutex *lock); -extern bool __rt_mutex_futex_unlock(struct rt_mutex *lock, -				 struct wake_q_head *wqh); - -extern void rt_mutex_postunlock(struct wake_q_head *wake_q); -  /* Debug functions */ -static inline void debug_rt_mutex_unlock(struct rt_mutex *lock) +static inline void debug_rt_mutex_unlock(struct rt_mutex_base *lock)  {  	if (IS_ENABLED(CONFIG_DEBUG_RT_MUTEXES))  		DEBUG_LOCKS_WARN_ON(rt_mutex_owner(lock) != current);  } -static inline void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock) +static inline void debug_rt_mutex_proxy_unlock(struct rt_mutex_base *lock)  {  	if (IS_ENABLED(CONFIG_DEBUG_RT_MUTEXES))  		DEBUG_LOCKS_WARN_ON(!rt_mutex_owner(lock)); @@ -161,4 +187,27 @@ static inline void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter)  		memset(waiter, 0x22, sizeof(*waiter));  } +static inline void rt_mutex_init_waiter(struct rt_mutex_waiter *waiter) +{ +	debug_rt_mutex_init_waiter(waiter); +	RB_CLEAR_NODE(&waiter->pi_tree_entry); +	RB_CLEAR_NODE(&waiter->tree_entry); +	waiter->wake_state = TASK_NORMAL; +	waiter->task = NULL; +} + +static inline void rt_mutex_init_rtlock_waiter(struct rt_mutex_waiter *waiter) +{ +	rt_mutex_init_waiter(waiter); +	waiter->wake_state = TASK_RTLOCK_WAIT; +} + +#else /* CONFIG_RT_MUTEXES */ +/* Used in rcu/tree_plugin.h */ +static inline struct task_struct *rt_mutex_owner(struct rt_mutex_base *lock) +{ +	return NULL; +} +#endif  /* !CONFIG_RT_MUTEXES */ +  #endif  |