summaryrefslogtreecommitdiff
path: root/nuttx/sched/task_exithook.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/sched/task_exithook.c')
-rw-r--r--nuttx/sched/task_exithook.c109
1 files changed, 75 insertions, 34 deletions
diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c
index 1106f2885..1813c12ed 100644
--- a/nuttx/sched/task_exithook.c
+++ b/nuttx/sched/task_exithook.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/task_exithook.c
*
- * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2011-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -202,51 +202,86 @@ static inline void task_sigchild(FAR _TCB *tcb, int status)
FAR _TCB *ptcb;
siginfo_t info;
- /* Keep things stationary through the following */
+ /* Only exiting tasks should generate SIGCHLD. pthreads use other
+ * mechansims.
+ */
- sched_lock();
+ if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK)
+ {
+ /* Keep things stationary through the following */
- /* Get the TCB of the receiving task */
+ sched_lock();
- ptcb = sched_gettcb(tcb->parent);
- if (!ptcb)
- {
- /* The parent no longer exists... bail */
+ /* Get the TCB of the receiving task */
- sched_unlock();
- return;
- }
+ ptcb = sched_gettcb(tcb->parent);
+ if (!ptcb)
+ {
+ /* The parent no longer exists... bail */
- /* Decrement the number of children from this parent */
+ sched_unlock();
+ return;
+ }
- DEBUGASSERT(ptcb->nchildren > 0);
- ptcb->nchildren--;
+#ifdef CONFIG_SCHED_CHILD_STATUS
+ /* Check if the parent task has suppressed retention of child exit
+ * status information. Only 'tasks' report exit status, not pthreads.
+ * pthreads have a different mechanism.
+ */
- /* Set the parent to an impossible PID. We do this because under certain
- * conditions, task_exithook() can be called multiple times. If this
- * function is called again, sched_gettcb() will fail on the invalid
- * parent PID above, nchildren will be decremented once and all will be
- * well.
- */
+ if ((ptcb->flags & TCB_FLAG_NOCLDWAIT) == 0)
+ {
+ FAR struct child_status_s *child;
- tcb->parent = INVALID_PROCESS_ID;
+ /* No.. Find the exit status entry for this task in the parent TCB */
- /* Create the siginfo structure. We don't actually know the cause. That
- * is a bug. Let's just say that the child task just exit-ted for now.
- */
+ child = task_findchild(ptcb, getpid());
+ DEBUGASSERT(child);
+ if (child)
+ {
+ /* Mark that the child has exit'ed */
- info.si_signo = SIGCHLD;
- info.si_code = CLD_EXITED;
- info.si_value.sival_ptr = NULL;
- info.si_pid = tcb->pid;
- info.si_status = status;
+ child->ch_flags |= CHILD_FLAG_EXITED;
- /* Send the signal. We need to use this internal interface so that we can
- * provide the correct si_code value with the signal.
- */
+ /* Save the exit status */
+
+ child->ch_status = status;
+ }
+ }
+#else
+ /* Decrement the number of children from this parent */
- (void)sig_received(ptcb, &info);
- sched_unlock();
+ DEBUGASSERT(ptcb->nchildren > 0);
+ ptcb->nchildren--;
+#endif
+
+ /* Set the parent to an impossible PID. We do this because under
+ * certain conditions, task_exithook() can be called multiple times.
+ * If this function is called again, sched_gettcb() will fail on the
+ * invalid parent PID above, nchildren will be decremented once and
+ * all will be well.
+ */
+
+ tcb->parent = INVALID_PROCESS_ID;
+
+ /* Create the siginfo structure. We don't actually know the cause.
+ * That is a bug. Let's just say that the child task just exit-ted
+ * for now.
+ */
+
+ info.si_signo = SIGCHLD;
+ info.si_code = CLD_EXITED;
+ info.si_value.sival_ptr = NULL;
+ info.si_pid = tcb->pid;
+ info.si_status = status;
+
+ /* Send the signal. We need to use this internal interface so that we
+ * can provide the correct si_code value with the signal.
+ */
+
+ (void)sig_received(ptcb, &info);
+ sched_unlock();
+ }
}
#else
# define task_sigchild(tcb,status)
@@ -344,6 +379,12 @@ void task_exithook(FAR _TCB *tcb, int status)
(void)lib_flushall(tcb->streams);
#endif
+ /* Discard any un-reaped child status (no zombies here!) */
+
+#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
+ task_removechildren(tcb);
+#endif
+
/* Free all file-related resources now. This gets called again
* just be be certain when the TCB is delallocated. However, we
* really need to close files as soon as possible while we still