diff options
author | Oleg Nesterov <oleg@redhat.com> | 2011-04-07 14:44:11 -0400 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2011-04-07 14:44:11 -0400 |
commit | e46bc9b6fd65bc9f406a4211fbf95683cc9c2937 (patch) | |
tree | 57046f6b2f4674a0c9048ab1ad1ff50fae7e373a /kernel/exit.c | |
parent | 2b9accbee563f535046ff2cd382d0acaa92e130c (diff) | |
parent | 321fb561971ba0f10ce18c0f8a4b9fbfc7cef4b9 (diff) |
Merge branch 'ptrace' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/misc into ptrace
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 84 |
1 files changed, 67 insertions, 17 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 6a488ad2dce5..5cbc83e83a5d 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -1538,33 +1538,83 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, | |||
1538 | return 0; | 1538 | return 0; |
1539 | } | 1539 | } |
1540 | 1540 | ||
1541 | if (likely(!ptrace) && unlikely(task_ptrace(p))) { | 1541 | /* dead body doesn't have much to contribute */ |
1542 | if (p->exit_state == EXIT_DEAD) | ||
1543 | return 0; | ||
1544 | |||
1545 | /* slay zombie? */ | ||
1546 | if (p->exit_state == EXIT_ZOMBIE) { | ||
1542 | /* | 1547 | /* |
1543 | * This child is hidden by ptrace. | 1548 | * A zombie ptracee is only visible to its ptracer. |
1544 | * We aren't allowed to see it now, but eventually we will. | 1549 | * Notification and reaping will be cascaded to the real |
1550 | * parent when the ptracer detaches. | ||
1545 | */ | 1551 | */ |
1546 | wo->notask_error = 0; | 1552 | if (likely(!ptrace) && unlikely(task_ptrace(p))) { |
1547 | return 0; | 1553 | /* it will become visible, clear notask_error */ |
1548 | } | 1554 | wo->notask_error = 0; |
1555 | return 0; | ||
1556 | } | ||
1549 | 1557 | ||
1550 | if (p->exit_state == EXIT_DEAD) | 1558 | /* we don't reap group leaders with subthreads */ |
1551 | return 0; | 1559 | if (!delay_group_leader(p)) |
1560 | return wait_task_zombie(wo, p); | ||
1552 | 1561 | ||
1553 | /* | 1562 | /* |
1554 | * We don't reap group leaders with subthreads. | 1563 | * Allow access to stopped/continued state via zombie by |
1555 | */ | 1564 | * falling through. Clearing of notask_error is complex. |
1556 | if (p->exit_state == EXIT_ZOMBIE && !delay_group_leader(p)) | 1565 | * |
1557 | return wait_task_zombie(wo, p); | 1566 | * When !@ptrace: |
1567 | * | ||
1568 | * If WEXITED is set, notask_error should naturally be | ||
1569 | * cleared. If not, subset of WSTOPPED|WCONTINUED is set, | ||
1570 | * so, if there are live subthreads, there are events to | ||
1571 | * wait for. If all subthreads are dead, it's still safe | ||
1572 | * to clear - this function will be called again in finite | ||
1573 | * amount time once all the subthreads are released and | ||
1574 | * will then return without clearing. | ||
1575 | * | ||
1576 | * When @ptrace: | ||
1577 | * | ||
1578 | * Stopped state is per-task and thus can't change once the | ||
1579 | * target task dies. Only continued and exited can happen. | ||
1580 | * Clear notask_error if WCONTINUED | WEXITED. | ||
1581 | */ | ||
1582 | if (likely(!ptrace) || (wo->wo_flags & (WCONTINUED | WEXITED))) | ||
1583 | wo->notask_error = 0; | ||
1584 | } else { | ||
1585 | /* | ||
1586 | * If @p is ptraced by a task in its real parent's group, | ||
1587 | * hide group stop/continued state when looking at @p as | ||
1588 | * the real parent; otherwise, a single stop can be | ||
1589 | * reported twice as group and ptrace stops. | ||
1590 | * | ||
1591 | * If a ptracer wants to distinguish the two events for its | ||
1592 | * own children, it should create a separate process which | ||
1593 | * takes the role of real parent. | ||
1594 | */ | ||
1595 | if (likely(!ptrace) && task_ptrace(p) && | ||
1596 | same_thread_group(p->parent, p->real_parent)) | ||
1597 | return 0; | ||
1598 | |||
1599 | /* | ||
1600 | * @p is alive and it's gonna stop, continue or exit, so | ||
1601 | * there always is something to wait for. | ||
1602 | */ | ||
1603 | wo->notask_error = 0; | ||
1604 | } | ||
1558 | 1605 | ||
1559 | /* | 1606 | /* |
1560 | * It's stopped or running now, so it might | 1607 | * Wait for stopped. Depending on @ptrace, different stopped state |
1561 | * later continue, exit, or stop again. | 1608 | * is used and the two don't interact with each other. |
1562 | */ | 1609 | */ |
1563 | wo->notask_error = 0; | ||
1564 | |||
1565 | if (task_stopped_code(p, ptrace)) | 1610 | if (task_stopped_code(p, ptrace)) |
1566 | return wait_task_stopped(wo, ptrace, p); | 1611 | return wait_task_stopped(wo, ptrace, p); |
1567 | 1612 | ||
1613 | /* | ||
1614 | * Wait for continued. There's only one continued state and the | ||
1615 | * ptracer can consume it which can confuse the real parent. Don't | ||
1616 | * use WCONTINUED from ptracer. You don't need or want it. | ||
1617 | */ | ||
1568 | return wait_task_continued(wo, p); | 1618 | return wait_task_continued(wo, p); |
1569 | } | 1619 | } |
1570 | 1620 | ||