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:
parent
b1bf234bf3
commit
ce722fd1e3
@ -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.
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user