aboutsummaryrefslogtreecommitdiff
path: root/nuttx/sched/task_reparent.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/sched/task_reparent.c')
-rw-r--r--nuttx/sched/task_reparent.c177
1 files changed, 167 insertions, 10 deletions
diff --git a/nuttx/sched/task_reparent.c b/nuttx/sched/task_reparent.c
index 28d371bf1..5bb62893f 100644
--- a/nuttx/sched/task_reparent.c
+++ b/nuttx/sched/task_reparent.c
@@ -42,6 +42,7 @@
#include <errno.h>
#include "os_internal.h"
+#include "group_internal.h"
#ifdef CONFIG_SCHED_HAVE_PARENT
@@ -69,6 +70,141 @@
*
*****************************************************************************/
+#ifdef HAVE_GROUP_MEMBERS
+int task_reparent(pid_t ppid, pid_t chpid)
+{
+#ifdef CONFIG_SCHED_CHILD_STATUS
+ FAR struct child_status_s *child;
+#endif
+ FAR struct task_group_s *chgrp;
+ FAR struct task_group_s *ogrp;
+ FAR struct task_group_s *pgrp;
+ _TCB *tcb;
+ gid_t ogid;
+ gid_t pgid;
+ irqstate_t flags;
+ int ret;
+
+ /* Disable interrupts so that nothing can change in the relatinoship of
+ * the three task: Child, current parent, and new parent.
+ */
+
+ flags = irqsave();
+
+ /* Get the child tasks task group */
+
+ tcb = sched_gettcb(chpid);
+ if (!tcb)
+ {
+ ret = -ECHILD;
+ goto errout_with_ints;
+ }
+
+ DEBUGASSERT(tcb->group);
+ chgrp = tcb->group;
+
+ /* Get the GID of the old parent task's task group (ogid) */
+
+ ogid = chgrp->tg_pgid;
+
+ /* Get the old parent task's task group (ogrp) */
+
+ ogrp = group_find(ogid);
+ if (!ogrp)
+ {
+ ret = -ESRCH;
+ goto errout_with_ints;
+ }
+
+ /* If new parent task's PID (ppid) is zero, then new parent is the
+ * grandparent will be the new parent, i.e., the parent of the current
+ * parent task.
+ */
+
+ if (ppid == 0)
+ {
+ /* Get the grandparent task's task group (pgrp) */
+
+ pgid = ogrp->tg_pgid;
+ pgrp = group_find(pgid);
+ }
+ else
+ {
+ /* Get the new parent task's task group (pgrp) */
+
+ tcb = sched_gettcb(ppid);
+ if (!tcb)
+ {
+ ret = -ESRCH;
+ goto errout_with_ints;
+ }
+
+ pgrp = tcb->group;
+ pgid = pgrp->tg_gid;
+ }
+
+ if (!pgrp)
+ {
+ ret = -ESRCH;
+ goto errout_with_ints;
+ }
+
+ /* Then reparent the child. Notice that we don't actually change the
+ * parent of the task. Rather, we change the parent task group for
+ * all members of the child's task group.
+ */
+
+ chgrp->tg_pgid = pgid;
+
+#ifdef CONFIG_SCHED_CHILD_STATUS
+ /* Remove the child status entry from old parent task group */
+
+ child = group_removechild(ogrp, chpid);
+ if (child)
+ {
+ /* Has the new parent's task group supressed child exit status? */
+
+ if ((pgrp->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0)
+ {
+ /* No.. Add the child status entry to the new parent's task group */
+
+ group_addchild(pgrp, child);
+ }
+ else
+ {
+ /* Yes.. Discard the child status entry */
+
+ group_freechild(child);
+ }
+
+ /* Either case is a success */
+
+ ret = OK;
+ }
+ else
+ {
+ /* This would not be an error if the original parent's task group has
+ * suppressed child exit status.
+ */
+
+ ret = ((ogrp->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK;
+ }
+
+#else /* CONFIG_SCHED_CHILD_STATUS */
+
+ DEBUGASSERT(otcb->nchildren > 0);
+
+ otcb->nchildren--; /* The orignal parent now has one few children */
+ ptcb->nchildren++; /* The new parent has one additional child */
+ ret = OK;
+
+#endif /* CONFIG_SCHED_CHILD_STATUS */
+
+errout_with_ints:
+ irqrestore(flags);
+ return ret;
+}
+#else
int task_reparent(pid_t ppid, pid_t chpid)
{
#ifdef CONFIG_SCHED_CHILD_STATUS
@@ -98,7 +234,7 @@ int task_reparent(pid_t ppid, pid_t chpid)
/* Get the PID of the child task's parent (opid) */
- opid = chtcb->parent;
+ opid = chtcb->ppid;
/* Get the TCB of the child task's parent (otcb) */
@@ -116,7 +252,7 @@ int task_reparent(pid_t ppid, pid_t chpid)
if (ppid == 0)
{
- ppid = otcb->parent;
+ ppid = otcb->ppid;
}
/* Get the new parent task's TCB (ptcb) */
@@ -130,34 +266,55 @@ int task_reparent(pid_t ppid, pid_t chpid)
/* Then reparent the child */
- chtcb->parent = ppid; /* The task specified by ppid is the new parent */
+ chtcb->ppid = ppid; /* The task specified by ppid is the new parent */
#ifdef CONFIG_SCHED_CHILD_STATUS
/* Remove the child status entry from old parent TCB */
- child = task_removechild(otcb, chpid);
+ child = group_removechild(otcb->group, chpid);
if (child)
{
- /* Add the child status entry to the new parent TCB */
+ /* Has the new parent's task group supressed child exit status? */
+
+ if ((ptcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0)
+ {
+ /* No.. Add the child status entry to the new parent's task group */
+
+ group_addchild(ptcb->group, child);
+ }
+ else
+ {
+ /* Yes.. Discard the child status entry */
+
+ group_freechild(child);
+ }
+
+ /* Either case is a success */
- task_addchild(ptcb, child);
ret = OK;
}
else
{
- ret = -ENOENT;
+ /* This would not be an error if the original parent's task group has
+ * suppressed child exit status.
+ */
+
+ ret = ((otcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK;
}
-#else
+
+#else /* CONFIG_SCHED_CHILD_STATUS */
+
DEBUGASSERT(otcb->nchildren > 0);
otcb->nchildren--; /* The orignal parent now has one few children */
ptcb->nchildren++; /* The new parent has one additional child */
ret = OK;
-#endif
+
+#endif /* CONFIG_SCHED_CHILD_STATUS */
errout_with_ints:
irqrestore(flags);
return ret;
}
-
+#endif
#endif /* CONFIG_SCHED_HAVE_PARENT */