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
This commit is contained in:
patacongo 2013-02-04 16:02:20 +00:00
parent b1bf234bf3
commit ce722fd1e3
4 changed files with 66 additions and 24 deletions

View File

@ -4109,7 +4109,11 @@
* sched/pthread* and include/nuttx/sched: Move pthread join data * sched/pthread* and include/nuttx/sched: Move pthread join data
and pthread key calculation data into the "task group" structure. and pthread key calculation data into the "task group" structure.
* sched/atexit.c, on_exit.c, task_exithook.c and include/nuttx/sched.h: * 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 callbacks are only issued now when the final member of the task
group exits. 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.

View File

@ -83,6 +83,8 @@
# define HAVE_TASK_GROUP 1 # define HAVE_TASK_GROUP 1
# elif defined(CONFIG_SCHED_ONEXIT) /* Group on_exit() function */ # elif defined(CONFIG_SCHED_ONEXIT) /* Group on_exit() function */
# define HAVE_TASK_GROUP 1 # 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 */ # elif CONFIG_NFILE_DESCRIPTORS > 0 /* File descriptors */
# define HAVE_TASK_GROUP 1 # define HAVE_TASK_GROUP 1
# elif CONFIG_NFILE_STREAMS > 0 /* Standard C buffered I/O */ # 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 */ FAR struct child_status_s *tg_children; /* Head of a list of child status */
#endif #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 *******************************************************************/ /* Pthreads *******************************************************************/
#ifndef CONFIG_DISABLE_PTHREAD #ifndef CONFIG_DISABLE_PTHREAD
@ -408,11 +418,6 @@ struct _TCB
FAR void *starthookarg; /* The argument passed to the function */ FAR void *starthookarg; /* The argument passed to the function */
#endif #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 */ uint8_t sched_priority; /* Current priority of the thread */
#ifdef CONFIG_PRIORITY_INHERITANCE #ifdef CONFIG_PRIORITY_INHERITANCE

View File

@ -182,7 +182,8 @@
#ifndef CONFIG_SCHED_HAVE_PARENT #ifndef CONFIG_SCHED_HAVE_PARENT
pid_t waitpid(pid_t pid, int *stat_loc, int options) pid_t waitpid(pid_t pid, int *stat_loc, int options)
{ {
_TCB *ctcb; FAR _TCB *ctcb;
FAR struct task_group_s *group;
bool mystat; bool mystat;
int err; int err;
int ret; int ret;
@ -212,21 +213,26 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
goto errout_with_errno; 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 /* "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 * 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 * time of the target process termination." Hmmm.. what do we return to the
* others? * others?
*/ */
if (stat_loc != NULL && ctcb->stat_loc == NULL) if (stat_loc != NULL && group->tg_statloc == NULL)
{ {
ctcb->stat_loc = stat_loc; group->tg_statloc = stat_loc;
mystat = true; mystat = true;
} }
/* Then wait for the task to exit */ /* Then wait for the task to exit */
ret = sem_wait(&ctcb->exitsem); ret = sem_wait(&group->tg_exitsem);
if (ret < 0) if (ret < 0)
{ {
/* Unlock pre-emption and return the ERROR (sem_wait has already set /* 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) if (mystat)
{ {
ctcb->stat_loc = NULL; group->tg_statloc = NULL;
} }
goto errout; goto errout;

View File

@ -474,25 +474,52 @@ static inline void task_leavegroup(FAR _TCB *ctcb, int status)
#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT) #if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT)
static inline void task_exitwakeup(FAR _TCB *tcb, int status) 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;
while (tcb->exitsem.semcount < 0) /* Have we already left the group? */
if (group)
{ {
/* "If more than one thread is suspended in waitpid() awaiting /* Only tasks return valid status. Record the exit status when the
* termination of the same process, exactly one thread will return * task exists. The group, however, may still be executing.
* the process status at the time of the target process termination."
* Hmmm.. what do we return to the others?
*/ */
if (tcb->stat_loc) if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK)
{ {
*tcb->stat_loc = status << 8; /* Report the exit status. We do not nullify tg_statloc here
tcb->stat_loc = NULL; * 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? */
sem_post(&tcb->exitsem); 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(&group->tg_exitsem);
}
}
} }
} }
#else #else
@ -530,7 +557,7 @@ void task_exithook(FAR _TCB *tcb, int status)
{ {
/* Under certain conditions, task_exithook() can be called multiple times. /* 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 * 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) if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0)