Bugfix: whenever a thread it must report the PID of the main task (even it is not the main task) with SIGCHLD

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5612 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2013-02-04 22:38:59 +00:00
parent 7b3ec4e146
commit 126e46a1e7
20 changed files with 140 additions and 66 deletions
+5
View File
@@ -4130,4 +4130,9 @@
for pthreads. By dividing the TCB structure into these variants,
pthreads do not have to be burdened by task-specific data structures
(and vice versa).
* sched/task_exithook.c adn group_create.c: Fix an error, the
task within the task group may exit early leaving a pthread to
exit the task group last. In this case, we need to remember the
the PID of the main task in the task group and use that PID for
signalling SIGCHILD to the parent task group.
+43 -1
View File
@@ -6,7 +6,7 @@ standards, things that could be improved, and ideas for enhancements.
nuttx/
(11) Task/Scheduler (sched/)
(12) Task/Scheduler (sched/)
(1) Memory Managment (mm/)
(3) Signals (sched/, arch/)
(2) pthreads (sched/)
@@ -204,6 +204,48 @@ o Task/Scheduler (sched/)
incompatibilities could show up in porting some code).
Priority: Low
Title: SIGNALS IN TASK GROUPS WITH MANY PTHREADS
Description: Presumably when you single the task group you would signal
using the task ID of the task that created the group (in
practice, a different task should not know the IDs of the
internal threads created within the task group).
Here are some of the things that should happen, but don't
as of this writing:
- If a task group receives a signal then one and only one
indeterminate thread in the process which is not blocking
the signal should receive the signal.
- If a task group receives a signal and more than one thread
is waiting on that signal, then one and only one
indeterminate thread out of that waiting group will receive
the signal.
- If any signal which would normally cause the termination of
a process is sent to a thread it will result in the parent
process and all threads being terminated. (NuttX does not
support these default signal actions... that is really
another topic).
On creation a thread does correctly inherits the signal mask of the thread that created it.
You should be able to control which thread receives the signal
by control the signal mask. You should, for example, be able
to create a seperate thread whose sole purpose it is to catch
signals and respond to them. You can mask out certain signals
using sigprocmask() (or pthread_sigmask()). These signals
will be effectively disabled and will never be received in
these contexts. In the "signal processing" thread, enable the
blocked signals. This should now be the only thread who
receives the signals.
At present, the signal APIs will attempt to signal only the
thread that is the main task of the task group.
Status: Open.
Priority: Medium-high for spec compliance; but probably low for everyday
embedded applications.
o Memory Managment (mm/)
^^^^^^^^^^^^^^^^^^^^^^
+21 -16
View File
@@ -77,22 +77,24 @@
*/
#else
# if !defined(CONFIG_DISABLE_ENVIRON) /* Environment variables */
# define HAVE_TASK_GROUP 1
# elif defined(CONFIG_SCHED_ATEXIT) /* Group atexit() function */
# 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 */
# define HAVE_TASK_GROUP 1
# elif CONFIG_NSOCKET_DESCRIPTORS > 0 /* Sockets */
# define HAVE_TASK_GROUP 1
# elif !defined(CONFIG_DISABLE_MQUEUE) /* Message queues */
# define HAVE_TASK_GROUP 1
# if !defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_SCHED_HAVE_PARENT)
# define HAVE_TASK_GROUP 1 /* pthreads with parent*/
# elif !defined(CONFIG_DISABLE_ENVIRON)
# define HAVE_TASK_GROUP 1 /* Environment variables */
# elif defined(CONFIG_SCHED_ATEXIT)
# define HAVE_TASK_GROUP 1 /* Group atexit() function */
# elif defined(CONFIG_SCHED_ONEXIT)
# define HAVE_TASK_GROUP 1 /* Group on_exit() function */
# elif defined(CONFIG_SCHED_WAITPID)
# define HAVE_TASK_GROUP 1 /* Group waitpid() function */
# elif CONFIG_NFILE_DESCRIPTORS > 0
# define HAVE_TASK_GROUP 1 /* File descriptors */
# elif CONFIG_NFILE_STREAMS > 0
# define HAVE_TASK_GROUP 1 /* Standard C buffered I/O */
# elif CONFIG_NSOCKET_DESCRIPTORS > 0
# define HAVE_TASK_GROUP 1 /* Sockets */
# elif !defined(CONFIG_DISABLE_MQUEUE)
# define HAVE_TASK_GROUP 1 /* Message queues */
# endif
#endif
@@ -293,6 +295,9 @@ struct task_group_s
struct task_group_s *flink; /* Supports a singly linked list */
gid_t tg_gid; /* The ID of this task group */
gid_t tg_pgid; /* The ID of the parent task group */
#endif
#if !defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_SCHED_HAVE_PARENT)
pid_t tg_task; /* The ID of the task within the group */
#endif
uint8_t tg_flags; /* See GROUP_FLAG_* definitions */
+1 -1
View File
@@ -120,7 +120,7 @@ int clock_abstime2ticks(clockid_t clockid, FAR const struct timespec *abstime,
reltime.tv_sec -= 1;
}
/* Convert this relative time into microseconds.*/
/* Convert this relative time into microseconds. */
return clock_time2ticks(&reltime, ticks);
}
+1 -1
View File
@@ -179,7 +179,7 @@ static inline void clock_basetime(FAR struct timespec *tp)
static void clock_inittime(void)
{
/* (Re-)initialize the time value to match the RTC*/
/* (Re-)initialize the time value to match the RTC */
clock_basetime(&g_basetime);
g_system_timer = 0;
+1 -3
View File
@@ -91,7 +91,7 @@ FAR char *getenv(const char *name)
goto errout;
}
/* Get a reference to the thread-private environ in the TCB.*/
/* Get a reference to the thread-private environ in the TCB. */
sched_lock();
rtcb = (FAR struct tcb_s*)g_readytorun.head;
@@ -131,5 +131,3 @@ errout:
#endif /* CONFIG_DISABLE_ENVIRON */
+1 -3
View File
@@ -83,7 +83,7 @@ FAR char **get_environ_ptr( void )
#else
/* Return a reference to the thread-private environ in the TCB.*/
/* Return a reference to the thread-private environ in the TCB. */
FAR struct tcb_s *ptcb = (FAR struct tcb_s*)g_readytorun.head;
if (ptcb->envp)
@@ -100,5 +100,3 @@ FAR char **get_environ_ptr( void )
#endif /* CONFIG_DISABLE_ENVIRON */
+1 -3
View File
@@ -121,7 +121,7 @@ int setenv(FAR const char *name, FAR const char *value, int overwrite)
}
}
/* Get a reference to the thread-private environ in the TCB.*/
/* Get a reference to the thread-private environ in the TCB. */
sched_lock();
rtcb = (FAR struct tcb_s*)g_readytorun.head;
@@ -203,5 +203,3 @@ errout:
#endif /* CONFIG_DISABLE_ENVIRON */
+23 -10
View File
@@ -174,12 +174,12 @@ void group_assigngid(FAR struct task_group_s *group)
*
*****************************************************************************/
int group_allocate(FAR struct tcb_s *tcb)
int group_allocate(FAR struct task_tcb_s *tcb)
{
FAR struct task_group_s *group;
int ret;
DEBUGASSERT(tcb && !tcb->group);
DEBUGASSERT(tcb && !tcb->cmn.group);
/* Allocate the group structure and assign it to the TCB */
@@ -191,7 +191,7 @@ int group_allocate(FAR struct tcb_s *tcb)
/* Attach the group to the TCB */
tcb->group = group;
tcb->cmn.group = group;
/* Assign the group a unique ID. If g_gidcounter were to wrap before we
* finish with task creation, that would be a problem.
@@ -207,7 +207,7 @@ int group_allocate(FAR struct tcb_s *tcb)
if (ret < 0)
{
kfree(group);
tcb->group = NULL;
tcb->cmn.group = NULL;
return ret;
}
@@ -241,15 +241,15 @@ int group_allocate(FAR struct tcb_s *tcb)
*
*****************************************************************************/
int group_initialize(FAR struct tcb_s *tcb)
int group_initialize(FAR struct task_tcb_s *tcb)
{
FAR struct task_group_s *group;
#ifdef HAVE_GROUP_MEMBERS
irqstate_t flags;
#endif
DEBUGASSERT(tcb && tcb->group);
group = tcb->group;
DEBUGASSERT(tcb && tcb->cmn.group);
group = tcb->cmn.group;
#ifdef HAVE_GROUP_MEMBERS
/* Allocate space to hold GROUP_INITIAL_MEMBERS members of the group */
@@ -261,9 +261,9 @@ int group_initialize(FAR struct tcb_s *tcb)
return -ENOMEM;
}
/* Assign the PID of this new task as a member of the group*/
/* Assign the PID of this new task as a member of the group. */
group->tg_members[0] = tcb->pid;
group->tg_members[0] = tcb->cmn.pid;
/* Initialize the non-zero elements of group structure and assign it to
* the tcb.
@@ -280,8 +280,21 @@ int group_initialize(FAR struct tcb_s *tcb)
#endif
group->tg_nmembers = 1; /* Number of members in the group */
/* Save the ID of the main task within the group of threads. This needed
* for things like SIGCHILD. It ID is also saved in the TCB of the main
* task but is also retained in the group which may persist after the main
* task has exited.
*/
#if !defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_SCHED_HAVE_PARENT)
group->tg_task = tcb->cmn.pid;
#endif
/* Mark that there is one member in the group, the main task */
group->tg_nmembers = 1;
return OK;
}
#endif /* HAVE_TASK_GROUP */
+7 -5
View File
@@ -76,16 +76,18 @@ extern FAR struct task_group_s *g_grouphead;
/* Task group data structure management */
#ifdef HAVE_TASK_GROUP
int group_allocate(FAR struct tcb_s *tcb);
int group_initialize(FAR struct tcb_s *tcb);
int group_bind(FAR struct tcb_s *tcb);
int group_join(FAR struct tcb_s *tcb);
int group_allocate(FAR struct task_tcb_s *tcb);
int group_initialize(FAR struct task_tcb_s *tcb);
#ifndef CONFIG_DISABLE_PTHREAD
int group_bind(FAR struct pthread_tcb_s *tcb);
int group_join(FAR struct pthread_tcb_s *tcb);
#endif
void group_leave(FAR struct tcb_s *tcb);
#ifdef HAVE_GROUP_MEMBERS
FAR struct task_group_s *group_find(gid_t gid);
int group_addmember(FAR struct task_group_s *group, pid_t pid);
int group_removemember(FAR struct task_group_s *group, pid_t pid);
int group_removemember(FAR struct task_group_s *group, pid_t pid);
#endif
/* Convenience functions */
+10 -10
View File
@@ -49,7 +49,7 @@
#include "group_internal.h"
#include "env_internal.h"
#ifdef HAVE_TASK_GROUP
#if defined(HAVE_TASK_GROUP) && !defined(CONFIG_DISABLE_PTHREAD)
/*****************************************************************************
* Pre-processor Definitions
@@ -99,15 +99,15 @@
*
*****************************************************************************/
int group_bind(FAR struct tcb_s *tcb)
int group_bind(FAR struct pthread_tcb_s *tcb)
{
FAR struct tcb_s *ptcb = (FAR struct tcb_s *)g_readytorun.head;
DEBUGASSERT(ptcb && tcb && ptcb->group && !tcb->group);
DEBUGASSERT(ptcb && tcb && ptcb->group && !tcb->cmn.group);
/* Copy the group reference from the parent to the child */
tcb->group = ptcb->group;
tcb->cmn.group = ptcb->group;
return OK;
}
@@ -136,24 +136,24 @@ int group_bind(FAR struct tcb_s *tcb)
*
*****************************************************************************/
int group_join(FAR struct tcb_s *tcb)
int group_join(FAR struct pthread_tcb_s *tcb)
{
FAR struct task_group_s *group;
#ifdef HAVE_GROUP_MEMBERS
int ret;
#endif
DEBUGASSERT(tcb && tcb->group &&
tcb->group->tg_nmembers < UINT8_MAX);
DEBUGASSERT(tcb && tcb->cmn.group &&
tcb->cmn.group->tg_nmembers < UINT8_MAX);
/* Get the group from the TCB */
group = tcb->group;
group = tcb->cmn.group;
#ifdef HAVE_GROUP_MEMBERS
/* Add the member to the group */
ret = group_addmember(group, tcb->pid);
ret = group_addmember(group, tcb->cmn.pid);
if (ret < 0)
{
return ret;
@@ -224,4 +224,4 @@ int group_addmember(FAR struct task_group_s *group, pid_t pid)
}
#endif /* HAVE_GROUP_MEMBERS */
#endif /* HAVE_TASK_GROUP */
#endif /* HAVE_TASK_GROUP && !CONFIG_DISABLE_PTHREAD */
+2 -1
View File
@@ -96,4 +96,5 @@ int group_setupstreams(FAR struct task_tcb_s *tcb)
}
#endif /* CONFIG_NFILE_STREAMS > 0 */
#endif /* CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0*/
#endif /* CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 */
+2 -1
View File
@@ -246,4 +246,5 @@ int group_setuptaskfiles(FAR struct task_tcb_s *tcb)
#endif
}
#endif /* CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0*/
#endif /* CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 */
+2 -2
View File
@@ -330,7 +330,7 @@ void os_start(void)
/* Allocate the IDLE group and suppress child status. */
#ifdef HAVE_TASK_GROUP
(void)group_allocate(&g_idletcb.cmn);
(void)group_allocate(&g_idletcb);
#endif
/* Initialize the interrupt handling subsystem (if included) */
@@ -456,7 +456,7 @@ void os_start(void)
*/
#ifdef HAVE_TASK_GROUP
(void)group_initialize(&g_idletcb.cmn);
(void)group_initialize(&g_idletcb);
g_idletcb.cmn.group->tg_flags = GROUP_FLAG_NOCLDWAIT;
#endif
+2 -2
View File
@@ -255,7 +255,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
*/
#ifdef HAVE_TASK_GROUP
ret = group_bind((FAR struct tcb_s *)ptcb);
ret = group_bind(ptcb);
if (ret < 0)
{
errcode = ENOMEM;
@@ -354,7 +354,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
/* Join the parent's task group */
#ifdef HAVE_TASK_GROUP
ret = group_join((FAR struct tcb_s *)ptcb);
ret = group_join(ptcb);
if (ret < 0)
{
errcode = ENOMEM;
+2 -1
View File
@@ -87,4 +87,5 @@ pid_t wait(FAR int *stat_loc)
return waitpid((pid_t)-1, stat_loc, 0);
}
#endif /* CONFIG_SCHED_WAITPID && CONFIG_SCHED_HAVE_PARENT*/
#endif /* CONFIG_SCHED_WAITPID && CONFIG_SCHED_HAVE_PARENT */
+2 -1
View File
@@ -405,4 +405,5 @@ errout:
return ERROR;
}
#endif /* CONFIG_SCHED_WAITPID && CONFIG_SCHED_HAVE_PARENT*/
#endif /* CONFIG_SCHED_WAITPID && CONFIG_SCHED_HAVE_PARENT */
+2 -2
View File
@@ -123,7 +123,7 @@ static int thread_create(const char *name, uint8_t ttype, int priority,
/* Allocate a new task group */
#ifdef HAVE_TASK_GROUP
ret = group_allocate((FAR struct tcb_s *)tcb);
ret = group_allocate(tcb);
if (ret < 0)
{
errcode = -ret;
@@ -169,7 +169,7 @@ static int thread_create(const char *name, uint8_t ttype, int priority,
/* Now we have enough in place that we can join the group */
#ifdef HAVE_TASK_GROUP
ret = group_initialize((FAR struct tcb_s *)tcb);
ret = group_initialize(tcb);
if (ret < 0)
{
errcode = -ret;
+10 -1
View File
@@ -343,7 +343,11 @@ static inline void task_sigchild(gid_t pgid, FAR struct tcb_s *ctcb, int status)
info.si_signo = SIGCHLD;
info.si_code = CLD_EXITED;
info.si_value.sival_ptr = NULL;
#ifndef CONFIG_DISABLE_PTHREAD
info.si_pid = chgrp->tg_task;
#else
info.si_pid = ctcb->pid;
#endif
info.si_status = status;
/* Send the signal. We need to use this internal interface so that we
@@ -356,7 +360,8 @@ static inline void task_sigchild(gid_t pgid, FAR struct tcb_s *ctcb, int status)
#else /* HAVE_GROUP_MEMBERS */
static inline void task_sigchild(FAR struct tcb_s *ptcb, FAR struct tcb_s *ctcb, int status)
static inline void task_sigchild(FAR struct tcb_s *ptcb,
FAR struct tcb_s *ctcb, int status)
{
siginfo_t info;
@@ -391,7 +396,11 @@ static inline void task_sigchild(FAR struct tcb_s *ptcb, FAR struct tcb_s *ctcb,
info.si_signo = SIGCHLD;
info.si_code = CLD_EXITED;
info.si_value.sival_ptr = NULL;
#ifndef CONFIG_DISABLE_PTHREAD
info.si_pid = chgrp->tg_task;
#else
info.si_pid = ctcb->pid;
#endif
info.si_status = status;
/* Send the signal. We need to use this internal interface so that we
+2 -2
View File
@@ -134,7 +134,7 @@ int task_init(FAR struct tcb_s *tcb, const char *name, int priority,
/* Create a new task group */
#ifdef HAVE_TASK_GROUP
ret = group_allocate(tcb);
ret = group_allocate(ttcb);
if (ret < 0)
{
errcode = -ret;
@@ -176,7 +176,7 @@ int task_init(FAR struct tcb_s *tcb, const char *name, int priority,
/* Now we have enough in place that we can join the group */
#ifdef HAVE_TASK_GROUP
ret = group_initialize(tcb);
ret = group_initialize(ttcb);
if (ret < 0)
{
errcode = -ret;