diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 69 |
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 | */ |
1685 | static int | 1685 | static int do_signal_stop(int signr) |
1686 | do_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 | } |