diff options
| author | Oleg Nesterov <oleg@tv-sign.ru> | 2006-03-28 19:11:22 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-28 21:36:43 -0500 |
| commit | a122b341b74c08020f6521b615acca6a692aac79 (patch) | |
| tree | d2e679f11f805a2817de127f195cf1a61ca22b98 /kernel | |
| parent | 6108ccd3e2f3012d5eec582e0af4d75e693824da (diff) | |
[PATCH] do_signal_stop: don't take tasklist_lock
do_signal_stop() does not need tasklist_lock anymore. So it does not need to
do misc re-checks, and we can simplify the code.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
| -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 | } |
