diff options
author | Oleg Nesterov <oleg@redhat.com> | 2011-04-01 14:12:38 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2011-04-03 20:11:05 -0400 |
commit | ee77f075921730b2b465880f9fd4367003bdab39 (patch) | |
tree | dfae10b9718b79650477f912de148c903bc1bbd0 /include/linux | |
parent | 780006eac2fe7f4d2582da16a096e5a44c4767ff (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.h | 6 |
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 | ||
1783 | extern void task_clear_group_stop_pending(struct task_struct *task); | 1783 | extern void task_clear_group_stop_pending(struct task_struct *task); |
1784 | 1784 | ||