Skip to content

Commit 3f186d9

Browse files
committed
futex: Add mutex around futex exit
The mutex will be used in subsequent changes to replace the busy looping of a waiter when the futex owner is currently executing the exit cleanup to prevent a potential live lock. Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Ingo Molnar <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent af8cbda commit 3f186d9

File tree

3 files changed

+18
-0
lines changed

3 files changed

+18
-0
lines changed

include/linux/futex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ static inline void futex_init_task(struct task_struct *tsk)
6565
INIT_LIST_HEAD(&tsk->pi_state_list);
6666
tsk->pi_state_cache = NULL;
6767
tsk->futex_state = FUTEX_STATE_OK;
68+
mutex_init(&tsk->futex_exit_mutex);
6869
}
6970

7071
void futex_exit_recursive(struct task_struct *tsk);

include/linux/sched.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,7 @@ struct task_struct {
10531053
#endif
10541054
struct list_head pi_state_list;
10551055
struct futex_pi_state *pi_state_cache;
1056+
struct mutex futex_exit_mutex;
10561057
unsigned int futex_state;
10571058
#endif
10581059
#ifdef CONFIG_PERF_EVENTS

kernel/futex.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3698,11 +3698,22 @@ static void futex_cleanup(struct task_struct *tsk)
36983698
*/
36993699
void futex_exit_recursive(struct task_struct *tsk)
37003700
{
3701+
/* If the state is FUTEX_STATE_EXITING then futex_exit_mutex is held */
3702+
if (tsk->futex_state == FUTEX_STATE_EXITING)
3703+
mutex_unlock(&tsk->futex_exit_mutex);
37013704
tsk->futex_state = FUTEX_STATE_DEAD;
37023705
}
37033706

37043707
static void futex_cleanup_begin(struct task_struct *tsk)
37053708
{
3709+
/*
3710+
* Prevent various race issues against a concurrent incoming waiter
3711+
* including live locks by forcing the waiter to block on
3712+
* tsk->futex_exit_mutex when it observes FUTEX_STATE_EXITING in
3713+
* attach_to_pi_owner().
3714+
*/
3715+
mutex_lock(&tsk->futex_exit_mutex);
3716+
37063717
/*
37073718
* Switch the state to FUTEX_STATE_EXITING under tsk->pi_lock.
37083719
*
@@ -3726,6 +3737,11 @@ static void futex_cleanup_end(struct task_struct *tsk, int state)
37263737
* take another loop until it becomes visible.
37273738
*/
37283739
tsk->futex_state = state;
3740+
/*
3741+
* Drop the exit protection. This unblocks waiters which observed
3742+
* FUTEX_STATE_EXITING to reevaluate the state.
3743+
*/
3744+
mutex_unlock(&tsk->futex_exit_mutex);
37293745
}
37303746

37313747
void futex_exec_release(struct task_struct *tsk)

0 commit comments

Comments
 (0)