aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2011-04-01 14:12:38 -0400
committerTejun Heo <tj@kernel.org>2011-04-03 20:11:05 -0400
commitee77f075921730b2b465880f9fd4367003bdab39 (patch)
treedfae10b9718b79650477f912de148c903bc1bbd0 /include/linux
parent780006eac2fe7f4d2582da16a096e5a44c4767ff (diff)
signal: Turn SIGNAL_STOP_DEQUEUED into GROUP_STOP_DEQUEUED
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: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/sched.h6
1 files changed, 3 insertions, 3 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 456d80ed3b78..8cef82d4cf77 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -652,9 +652,8 @@ struct signal_struct {
652 * Bits in flags field of signal_struct. 652 * Bits in flags field of signal_struct.
653 */ 653 */
654#define SIGNAL_STOP_STOPPED 0x00000001 /* job control stop in effect */ 654#define SIGNAL_STOP_STOPPED 0x00000001 /* job control stop in effect */
655#define SIGNAL_STOP_DEQUEUED 0x00000002 /* stop signal dequeued */ 655#define SIGNAL_STOP_CONTINUED 0x00000002 /* SIGCONT since WCONTINUED reap */
656#define SIGNAL_STOP_CONTINUED 0x00000004 /* SIGCONT since WCONTINUED reap */ 656#define SIGNAL_GROUP_EXIT 0x00000004 /* group exit in progress */
657#define SIGNAL_GROUP_EXIT 0x00000008 /* group exit in progress */
658/* 657/*
659 * Pending notifications to parent. 658 * Pending notifications to parent.
660 */ 659 */
@@ -1779,6 +1778,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
1779#define GROUP_STOP_PENDING (1 << 16) /* task should stop for group stop */ 1778#define GROUP_STOP_PENDING (1 << 16) /* task should stop for group stop */
1780#define GROUP_STOP_CONSUME (1 << 17) /* consume group stop count */ 1779#define GROUP_STOP_CONSUME (1 << 17) /* consume group stop count */
1781#define GROUP_STOP_TRAPPING (1 << 18) /* switching from STOPPED to TRACED */ 1780#define GROUP_STOP_TRAPPING (1 << 18) /* switching from STOPPED to TRACED */
1781#define GROUP_STOP_DEQUEUED (1 << 19) /* stop signal dequeued */
1782 1782
1783extern void task_clear_group_stop_pending(struct task_struct *task); 1783extern void task_clear_group_stop_pending(struct task_struct *task);
1784 1784