summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2013-02-04 16:02:20 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2013-02-04 16:02:20 +0000
commitc94d7c870c456005b3e87d71acba8f7f9ea2b5ec (patch)
tree982d75559dbb2fc6f53a4e8d090d40ef5c9e0f80
parentc13bd69be3d117b359275bcf3b2d631bb19bd597 (diff)
downloadnuttx-c94d7c870c456005b3e87d71acba8f7f9ea2b5ec.tar.gz
nuttx-c94d7c870c456005b3e87d71acba8f7f9ea2b5ec.tar.bz2
nuttx-c94d7c870c456005b3e87d71acba8f7f9ea2b5ec.zip
Move waitpid() data structures to task group; The caller of waitpid() is now only awakened when the final thread of the task group exits
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5608 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/ChangeLog6
-rw-r--r--nuttx/include/nuttx/sched.h15
-rw-r--r--nuttx/sched/sched_waitpid.c18
-rw-r--r--nuttx/sched/task_exithook.c51
4 files changed, 66 insertions, 24 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index cc7b911ee..577e6473f 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -4109,7 +4109,11 @@
* sched/pthread* and include/nuttx/sched: Move pthread join data
and pthread key calculation data into the "task group" structure.
* sched/atexit.c, on_exit.c, task_exithook.c and include/nuttx/sched.h:
- Move atexit and on_exit data structure to task group. These
+ Move atexit and on_exit data structures to task group. These
callbacks are only issued now when the final member of the task
group exits.
+ * sched/waitpid.c, task_exithook.c and include/nuttx/sched.h:
+ Move waitpid data data structures to task group. Callers of
+ of waitpid() are now only awakened whent he final thread of the
+ task group exits.
diff --git a/nuttx/include/nuttx/sched.h b/nuttx/include/nuttx/sched.h
index 456135962..41715cb0a 100644
--- a/nuttx/include/nuttx/sched.h
+++ b/nuttx/include/nuttx/sched.h
@@ -83,6 +83,8 @@
# define HAVE_TASK_GROUP 1
# elif defined(CONFIG_SCHED_ONEXIT) /* Group on_exit() function */
# define HAVE_TASK_GROUP 1
+# elif defined(CONFIG_SCHED_WAITPID) /* Group waitpid() function */
+# define HAVE_TASK_GROUP 1
# elif CONFIG_NFILE_DESCRIPTORS > 0 /* File descriptors */
# define HAVE_TASK_GROUP 1
# elif CONFIG_NFILE_STREAMS > 0 /* Standard C buffered I/O */
@@ -326,6 +328,14 @@ struct task_group_s
FAR struct child_status_s *tg_children; /* Head of a list of child status */
#endif
+ /* waitpid support ************************************************************/
+ /* Simple mechanism used only when there is no support for SIGCHLD */
+
+#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT)
+ sem_t tg_exitsem; /* Support for waitpid */
+ int *tg_statloc; /* Location to return exit status */
+#endif
+
/* Pthreads *******************************************************************/
#ifndef CONFIG_DISABLE_PTHREAD
@@ -408,11 +418,6 @@ struct _TCB
FAR void *starthookarg; /* The argument passed to the function */
#endif
-#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT)
- sem_t exitsem; /* Support for waitpid */
- int *stat_loc; /* Location to return exit status */
-#endif
-
uint8_t sched_priority; /* Current priority of the thread */
#ifdef CONFIG_PRIORITY_INHERITANCE
diff --git a/nuttx/sched/sched_waitpid.c b/nuttx/sched/sched_waitpid.c
index e44ef6e21..e79dded4c 100644
--- a/nuttx/sched/sched_waitpid.c
+++ b/nuttx/sched/sched_waitpid.c
@@ -182,7 +182,8 @@
#ifndef CONFIG_SCHED_HAVE_PARENT
pid_t waitpid(pid_t pid, int *stat_loc, int options)
{
- _TCB *ctcb;
+ FAR _TCB *ctcb;
+ FAR struct task_group_s *group;
bool mystat;
int err;
int ret;
@@ -212,21 +213,26 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
goto errout_with_errno;
}
+ /* The the task group corresponding to this PID */
+
+ group = ctcb->group;
+ DEBUGASSERT(group);
+
/* "If more than one thread is suspended in waitpid() awaiting termination of
* the same process, exactly one thread will return the process status at the
* time of the target process termination." Hmmm.. what do we return to the
* others?
*/
- if (stat_loc != NULL && ctcb->stat_loc == NULL)
+ if (stat_loc != NULL && group->tg_statloc == NULL)
{
- ctcb->stat_loc = stat_loc;
- mystat = true;
+ group->tg_statloc = stat_loc;
+ mystat = true;
}
/* Then wait for the task to exit */
- ret = sem_wait(&ctcb->exitsem);
+ ret = sem_wait(&group->tg_exitsem);
if (ret < 0)
{
/* Unlock pre-emption and return the ERROR (sem_wait has already set
@@ -236,7 +242,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
if (mystat)
{
- ctcb->stat_loc = NULL;
+ group->tg_statloc = NULL;
}
goto errout;
diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c
index 20162c0d6..22a46613e 100644
--- a/nuttx/sched/task_exithook.c
+++ b/nuttx/sched/task_exithook.c
@@ -474,25 +474,52 @@ static inline void task_leavegroup(FAR _TCB *ctcb, int status)
#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT)
static inline void task_exitwakeup(FAR _TCB *tcb, int status)
{
- /* Wakeup any tasks waiting for this task to exit */
+ FAR struct task_group_s *group = tcb->group;
+
+ /* Have we already left the group? */
- while (tcb->exitsem.semcount < 0)
+ if (group)
{
- /* "If more than one thread is suspended in waitpid() awaiting
- * termination of the same process, exactly one thread will return
- * the process status at the time of the target process termination."
- * Hmmm.. what do we return to the others?
+ /* Only tasks return valid status. Record the exit status when the
+ * task exists. The group, however, may still be executing.
*/
- if (tcb->stat_loc)
+ if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK)
{
- *tcb->stat_loc = status << 8;
- tcb->stat_loc = NULL;
+ /* Report the exit status. We do not nullify tg_statloc here
+ * because we want to prent other tasks from registering for
+ * the return status. There is only one task per task group,
+ * there for, this logic should execute exactly once in the
+ * lifetime of the task group.
+ *
+ * "If more than one thread is suspended in waitpid() awaiting
+ * termination of the same process, exactly one thread will
+ * return the process status at the time of the target process
+ * termination."
+ *
+ * Hmmm.. what do we return to the others?
+ */
+
+ if (group->tg_statloc)
+ {
+ *group->tg_statloc = status << 8;
+ }
}
- /* Wake up the thread */
+ /* Is this the last thread in the group? */
+
+ if (group->tg_nmembers == 1)
+ {
+ /* Yes.. Wakeup any tasks waiting for this task to exit */
+
+ group->tg_statloc = NULL;
+ while (group->tg_exitsem.semcount < 0)
+ {
+ /* Wake up the thread */
- sem_post(&tcb->exitsem);
+ sem_post(&group->tg_exitsem);
+ }
+ }
}
}
#else
@@ -530,7 +557,7 @@ void task_exithook(FAR _TCB *tcb, int status)
{
/* Under certain conditions, task_exithook() can be called multiple times.
* A bit in the TCB was set the first time this function was called. If
- * that bit is set, then just ext doing nothing more..
+ * that bit is set, then just exit doing nothing more..
*/
if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0)