diff options
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 41 |
1 files changed, 33 insertions, 8 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 84d13d6bb30b..1a0f10f0a4db 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -1541,17 +1541,19 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, | |||
1541 | if (p->exit_state == EXIT_DEAD) | 1541 | if (p->exit_state == EXIT_DEAD) |
1542 | return 0; | 1542 | return 0; |
1543 | 1543 | ||
1544 | if (likely(!ptrace) && unlikely(task_ptrace(p))) { | 1544 | /* slay zombie? */ |
1545 | if (p->exit_state == EXIT_ZOMBIE) { | ||
1545 | /* | 1546 | /* |
1546 | * This child is hidden by ptrace. | 1547 | * A zombie ptracee is only visible to its ptracer. |
1547 | * We aren't allowed to see it now, but eventually we will. | 1548 | * Notification and reaping will be cascaded to the real |
1549 | * parent when the ptracer detaches. | ||
1548 | */ | 1550 | */ |
1549 | wo->notask_error = 0; | 1551 | if (likely(!ptrace) && unlikely(task_ptrace(p))) { |
1550 | return 0; | 1552 | /* it will become visible, clear notask_error */ |
1551 | } | 1553 | wo->notask_error = 0; |
1554 | return 0; | ||
1555 | } | ||
1552 | 1556 | ||
1553 | /* slay zombie? */ | ||
1554 | if (p->exit_state == EXIT_ZOMBIE) { | ||
1555 | /* we don't reap group leaders with subthreads */ | 1557 | /* we don't reap group leaders with subthreads */ |
1556 | if (!delay_group_leader(p)) | 1558 | if (!delay_group_leader(p)) |
1557 | return wait_task_zombie(wo, p); | 1559 | return wait_task_zombie(wo, p); |
@@ -1580,15 +1582,38 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, | |||
1580 | wo->notask_error = 0; | 1582 | wo->notask_error = 0; |
1581 | } else { | 1583 | } else { |
1582 | /* | 1584 | /* |
1585 | * If @p is ptraced by a task in its real parent's group, | ||
1586 | * hide group stop/continued state when looking at @p as | ||
1587 | * the real parent; otherwise, a single stop can be | ||
1588 | * reported twice as group and ptrace stops. | ||
1589 | * | ||
1590 | * If a ptracer wants to distinguish the two events for its | ||
1591 | * own children, it should create a separate process which | ||
1592 | * takes the role of real parent. | ||
1593 | */ | ||
1594 | if (likely(!ptrace) && task_ptrace(p) && | ||
1595 | same_thread_group(p->parent, p->real_parent)) | ||
1596 | return 0; | ||
1597 | |||
1598 | /* | ||
1583 | * @p is alive and it's gonna stop, continue or exit, so | 1599 | * @p is alive and it's gonna stop, continue or exit, so |
1584 | * there always is something to wait for. | 1600 | * there always is something to wait for. |
1585 | */ | 1601 | */ |
1586 | wo->notask_error = 0; | 1602 | wo->notask_error = 0; |
1587 | } | 1603 | } |
1588 | 1604 | ||
1605 | /* | ||
1606 | * Wait for stopped. Depending on @ptrace, different stopped state | ||
1607 | * is used and the two don't interact with each other. | ||
1608 | */ | ||
1589 | if (task_stopped_code(p, ptrace)) | 1609 | if (task_stopped_code(p, ptrace)) |
1590 | return wait_task_stopped(wo, ptrace, p); | 1610 | return wait_task_stopped(wo, ptrace, p); |
1591 | 1611 | ||
1612 | /* | ||
1613 | * Wait for continued. There's only one continued state and the | ||
1614 | * ptracer can consume it which can confuse the real parent. Don't | ||
1615 | * use WCONTINUED from ptracer. You don't need or want it. | ||
1616 | */ | ||
1592 | return wait_task_continued(wo, p); | 1617 | return wait_task_continued(wo, p); |
1593 | } | 1618 | } |
1594 | 1619 | ||