aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c69
1 files changed, 17 insertions, 52 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index e99ec2f891a0..e3bdec914626 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1682,8 +1682,7 @@ out:
1682 * Returns nonzero if we've actually stopped and released the siglock. 1682 * Returns nonzero if we've actually stopped and released the siglock.
1683 * Returns zero if we didn't stop and still hold the siglock. 1683 * Returns zero if we didn't stop and still hold the siglock.
1684 */ 1684 */
1685static int 1685static int do_signal_stop(int signr)
1686do_signal_stop(int signr)
1687{ 1686{
1688 struct signal_struct *sig = current->signal; 1687 struct signal_struct *sig = current->signal;
1689 struct sighand_struct *sighand = current->sighand; 1688 struct sighand_struct *sighand = current->sighand;
@@ -1703,7 +1702,6 @@ do_signal_stop(int signr)
1703 set_current_state(TASK_STOPPED); 1702 set_current_state(TASK_STOPPED);
1704 if (stop_count == 0) 1703 if (stop_count == 0)
1705 sig->flags = SIGNAL_STOP_STOPPED; 1704 sig->flags = SIGNAL_STOP_STOPPED;
1706 spin_unlock_irq(&sighand->siglock);
1707 } 1705 }
1708 else if (thread_group_empty(current)) { 1706 else if (thread_group_empty(current)) {
1709 /* 1707 /*
@@ -1712,71 +1710,38 @@ do_signal_stop(int signr)
1712 current->exit_code = current->signal->group_exit_code = signr; 1710 current->exit_code = current->signal->group_exit_code = signr;
1713 set_current_state(TASK_STOPPED); 1711 set_current_state(TASK_STOPPED);
1714 sig->flags = SIGNAL_STOP_STOPPED; 1712 sig->flags = SIGNAL_STOP_STOPPED;
1715 spin_unlock_irq(&sighand->siglock);
1716 } 1713 }
1717 else { 1714 else {
1718 /* 1715 /*
1716 * (sig->group_stop_count == 0)
1719 * There is no group stop already in progress. 1717 * There is no group stop already in progress.
1720 * We must initiate one now, but that requires 1718 * We must initiate one now.
1721 * dropping siglock to get both the tasklist lock
1722 * and siglock again in the proper order. Note that
1723 * this allows an intervening SIGCONT to be posted.
1724 * We need to check for that and bail out if necessary.
1725 */ 1719 */
1726 struct task_struct *t; 1720 struct task_struct *t;
1727 1721
1728 spin_unlock_irq(&sighand->siglock); 1722 current->exit_code = signr;
1729 1723 sig->group_exit_code = signr;
1730 /* signals can be posted during this window */
1731
1732 read_lock(&tasklist_lock);
1733 spin_lock_irq(&sighand->siglock);
1734 1724
1735 if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED)) { 1725 stop_count = 0;
1726 for (t = next_thread(current); t != current; t = next_thread(t))
1736 /* 1727 /*
1737 * Another stop or continue happened while we 1728 * Setting state to TASK_STOPPED for a group
1738 * didn't have the lock. We can just swallow this 1729 * stop is always done with the siglock held,
1739 * signal now. If we raced with a SIGCONT, that 1730 * so this check has no races.
1740 * should have just cleared it now. If we raced
1741 * with another processor delivering a stop signal,
1742 * then the SIGCONT that wakes us up should clear it.
1743 */ 1731 */
1744 read_unlock(&tasklist_lock); 1732 if (!t->exit_state &&
1745 return 0; 1733 !(t->state & (TASK_STOPPED|TASK_TRACED))) {
1746 } 1734 stop_count++;
1747 1735 signal_wake_up(t, 0);
1748 if (sig->group_stop_count == 0) { 1736 }
1749 sig->group_exit_code = signr; 1737 sig->group_stop_count = stop_count;
1750 stop_count = 0;
1751 for (t = next_thread(current); t != current;
1752 t = next_thread(t))
1753 /*
1754 * Setting state to TASK_STOPPED for a group
1755 * stop is always done with the siglock held,
1756 * so this check has no races.
1757 */
1758 if (!t->exit_state &&
1759 !(t->state & (TASK_STOPPED|TASK_TRACED))) {
1760 stop_count++;
1761 signal_wake_up(t, 0);
1762 }
1763 sig->group_stop_count = stop_count;
1764 }
1765 else {
1766 /* A race with another thread while unlocked. */
1767 signr = sig->group_exit_code;
1768 stop_count = --sig->group_stop_count;
1769 }
1770 1738
1771 current->exit_code = signr;
1772 set_current_state(TASK_STOPPED); 1739 set_current_state(TASK_STOPPED);
1773 if (stop_count == 0) 1740 if (stop_count == 0)
1774 sig->flags = SIGNAL_STOP_STOPPED; 1741 sig->flags = SIGNAL_STOP_STOPPED;
1775
1776 spin_unlock_irq(&sighand->siglock);
1777 read_unlock(&tasklist_lock);
1778 } 1742 }
1779 1743
1744 spin_unlock_irq(&sighand->siglock);
1780 finish_stop(stop_count); 1745 finish_stop(stop_count);
1781 return 1; 1746 return 1;
1782} 1747}