mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	task_work: teach task_work_add() to do signal_wake_up()
So that the target task will exit the wait_event_interruptible-like loop and call task_work_run() asap. The patch turns "bool notify" into 0,TWA_RESUME,TWA_SIGNAL enum, the new TWA_SIGNAL flag implies signal_wake_up(). However, it needs to avoid the race with recalc_sigpending(), so the patch also adds the new JOBCTL_TASK_WORK bit included in JOBCTL_PENDING_MASK. TODO: once this patch is merged we need to change all current users of task_work_add(notify = true) to use TWA_RESUME. Cc: stable@vger.kernel.org # v5.7 Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
		
							parent
							
								
									d60b5fbc1c
								
							
						
					
					
						commit
						e91b481623
					
				
					 4 changed files with 28 additions and 7 deletions
				
			
		|  | @ -19,6 +19,7 @@ struct task_struct; | |||
| #define JOBCTL_TRAPPING_BIT	21	/* switching to TRACED */ | ||||
| #define JOBCTL_LISTENING_BIT	22	/* ptracer is listening for events */ | ||||
| #define JOBCTL_TRAP_FREEZE_BIT	23	/* trap for cgroup freezer */ | ||||
| #define JOBCTL_TASK_WORK_BIT	24	/* set by TWA_SIGNAL */ | ||||
| 
 | ||||
| #define JOBCTL_STOP_DEQUEUED	(1UL << JOBCTL_STOP_DEQUEUED_BIT) | ||||
| #define JOBCTL_STOP_PENDING	(1UL << JOBCTL_STOP_PENDING_BIT) | ||||
|  | @ -28,9 +29,10 @@ struct task_struct; | |||
| #define JOBCTL_TRAPPING		(1UL << JOBCTL_TRAPPING_BIT) | ||||
| #define JOBCTL_LISTENING	(1UL << JOBCTL_LISTENING_BIT) | ||||
| #define JOBCTL_TRAP_FREEZE	(1UL << JOBCTL_TRAP_FREEZE_BIT) | ||||
| #define JOBCTL_TASK_WORK	(1UL << JOBCTL_TASK_WORK_BIT) | ||||
| 
 | ||||
| #define JOBCTL_TRAP_MASK	(JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY) | ||||
| #define JOBCTL_PENDING_MASK	(JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK) | ||||
| #define JOBCTL_PENDING_MASK	(JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK | JOBCTL_TASK_WORK) | ||||
| 
 | ||||
| extern bool task_set_jobctl_pending(struct task_struct *task, unsigned long mask); | ||||
| extern void task_clear_jobctl_trapping(struct task_struct *task); | ||||
|  |  | |||
|  | @ -13,7 +13,10 @@ init_task_work(struct callback_head *twork, task_work_func_t func) | |||
| 	twork->func = func; | ||||
| } | ||||
| 
 | ||||
| int task_work_add(struct task_struct *task, struct callback_head *twork, bool); | ||||
| #define TWA_RESUME	1 | ||||
| #define TWA_SIGNAL	2 | ||||
| int task_work_add(struct task_struct *task, struct callback_head *twork, int); | ||||
| 
 | ||||
| struct callback_head *task_work_cancel(struct task_struct *, task_work_func_t); | ||||
| void task_work_run(void); | ||||
| 
 | ||||
|  |  | |||
|  | @ -2529,9 +2529,6 @@ bool get_signal(struct ksignal *ksig) | |||
| 	struct signal_struct *signal = current->signal; | ||||
| 	int signr; | ||||
| 
 | ||||
| 	if (unlikely(current->task_works)) | ||||
| 		task_work_run(); | ||||
| 
 | ||||
| 	if (unlikely(uprobe_deny_signal())) | ||||
| 		return false; | ||||
| 
 | ||||
|  | @ -2544,6 +2541,13 @@ bool get_signal(struct ksignal *ksig) | |||
| 
 | ||||
| relock: | ||||
| 	spin_lock_irq(&sighand->siglock); | ||||
| 	current->jobctl &= ~JOBCTL_TASK_WORK; | ||||
| 	if (unlikely(current->task_works)) { | ||||
| 		spin_unlock_irq(&sighand->siglock); | ||||
| 		task_work_run(); | ||||
| 		goto relock; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Every stopped thread goes here after wakeup. Check to see if | ||||
| 	 * we should notify the parent, prepare_signal(SIGCONT) encodes | ||||
|  |  | |||
|  | @ -25,9 +25,10 @@ static struct callback_head work_exited; /* all we need is ->next == NULL */ | |||
|  * 0 if succeeds or -ESRCH. | ||||
|  */ | ||||
| int | ||||
| task_work_add(struct task_struct *task, struct callback_head *work, bool notify) | ||||
| task_work_add(struct task_struct *task, struct callback_head *work, int notify) | ||||
| { | ||||
| 	struct callback_head *head; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	do { | ||||
| 		head = READ_ONCE(task->task_works); | ||||
|  | @ -36,8 +37,19 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify) | |||
| 		work->next = head; | ||||
| 	} while (cmpxchg(&task->task_works, head, work) != head); | ||||
| 
 | ||||
| 	if (notify) | ||||
| 	switch (notify) { | ||||
| 	case TWA_RESUME: | ||||
| 		set_notify_resume(task); | ||||
| 		break; | ||||
| 	case TWA_SIGNAL: | ||||
| 		if (lock_task_sighand(task, &flags)) { | ||||
| 			task->jobctl |= JOBCTL_TASK_WORK; | ||||
| 			signal_wake_up(task, 0); | ||||
| 			unlock_task_sighand(task, &flags); | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Oleg Nesterov
						Oleg Nesterov