• O
    signal: Turn SIGNAL_STOP_DEQUEUED into GROUP_STOP_DEQUEUED · ee77f075
    Oleg Nesterov 提交于
    This patch moves SIGNAL_STOP_DEQUEUED from signal_struct->flags to
    task_struct->group_stop, and thus makes it per-thread.
    
    Like SIGNAL_STOP_DEQUEUED, GROUP_STOP_DEQUEUED can be false-positive
    after return from get_signal_to_deliver(), this is fine. The only
    purpose of this bit is: we can drop ->siglock after __dequeue_signal()
    returns the sig_kernel_stop() signal and before we call
    do_signal_stop(), in this case we must not miss SIGCONT if it comes in
    between.
    
    But, unlike SIGNAL_STOP_DEQUEUED, GROUP_STOP_DEQUEUED can not be
    false-positive in do_signal_stop() if multiple threads dequeue the
    sig_kernel_stop() signal at the same time.
    
    Consider two threads T1 and T2, SIGTTIN has a hanlder.
    
    	- T1 dequeues SIGTSTP and sets SIGNAL_STOP_DEQUEUED, then
    	  it drops ->siglock
    
    	- SIGCONT comes and clears SIGNAL_STOP_DEQUEUED, SIGTSTP
    	  should be cancelled.
    
    	- T2 dequeues SIGTTIN and sets SIGNAL_STOP_DEQUEUED again.
    	  Since we have a handler we should not stop, T2 returns
    	  to usermode to run the handler.
    
    	- T1 continues, calls do_signal_stop() and wrongly starts
    	  the group stop because SIGNAL_STOP_DEQUEUED was restored
    	  in between.
    
    With or without this change:
    
    	- we need to do something with ptrace_signal() which can
    	  return SIGSTOP, but this needs another discussion
    
    	- SIGSTOP can be lost if it races with the mt exec, will
    	  be fixed later.
    Signed-off-by: NOleg Nesterov <oleg@redhat.com>
    Signed-off-by: NTejun Heo <tj@kernel.org>
    ee77f075
sched.h 76.3 KB