From 126e46a1e7f7529c3508c32a19b2e0251a0a2095 Mon Sep 17 00:00:00 2001 From: patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> Date: Mon, 4 Feb 2013 22:38:59 +0000 Subject: [PATCH] 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 --- ChangeLog | 5 ++++ TODO | 44 +++++++++++++++++++++++++++++++++++- include/nuttx/sched.h | 37 +++++++++++++++++------------- sched/clock_abstime2ticks.c | 2 +- sched/clock_initialize.c | 2 +- sched/env_getenv.c | 4 +--- sched/env_getenvironptr.c | 4 +--- sched/env_setenv.c | 4 +--- sched/group_create.c | 33 +++++++++++++++++++-------- sched/group_internal.h | 12 ++++++---- sched/group_join.c | 20 ++++++++-------- sched/group_setupstreams.c | 3 ++- sched/group_setuptaskfiles.c | 3 ++- sched/os_start.c | 4 ++-- sched/pthread_create.c | 4 ++-- sched/sched_wait.c | 3 ++- sched/sched_waitid.c | 3 ++- sched/task_create.c | 4 ++-- sched/task_exithook.c | 11 ++++++++- sched/task_init.c | 4 ++-- 20 files changed, 140 insertions(+), 66 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1ec62c208a..980885b00c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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. diff --git a/TODO b/TODO index 3f26b852ba..3e2413ded8 100644 --- a/TODO +++ b/TODO @@ -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/) ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 02d44d8299..47910fabef 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -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 */ diff --git a/sched/clock_abstime2ticks.c b/sched/clock_abstime2ticks.c index 2d7f7f4806..c558656352 100644 --- a/sched/clock_abstime2ticks.c +++ b/sched/clock_abstime2ticks.c @@ -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); } diff --git a/sched/clock_initialize.c b/sched/clock_initialize.c index 2e146bb475..85a7294abb 100644 --- a/sched/clock_initialize.c +++ b/sched/clock_initialize.c @@ -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; diff --git a/sched/env_getenv.c b/sched/env_getenv.c index 0414e23aa7..0b847950a8 100644 --- a/sched/env_getenv.c +++ b/sched/env_getenv.c @@ -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 */ - - diff --git a/sched/env_getenvironptr.c b/sched/env_getenvironptr.c index 91f3940b6f..5808dc5dda 100644 --- a/sched/env_getenvironptr.c +++ b/sched/env_getenvironptr.c @@ -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 */ - - diff --git a/sched/env_setenv.c b/sched/env_setenv.c index 772b011604..7ce3e1a1f1 100644 --- a/sched/env_setenv.c +++ b/sched/env_setenv.c @@ -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 */ - - diff --git a/sched/group_create.c b/sched/group_create.c index 414fe18242..ccf2e75192 100644 --- a/sched/group_create.c +++ b/sched/group_create.c @@ -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 */ + diff --git a/sched/group_internal.h b/sched/group_internal.h index e79f96e8c4..f29cb53de9 100644 --- a/sched/group_internal.h +++ b/sched/group_internal.h @@ -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 */ diff --git a/sched/group_join.c b/sched/group_join.c index 564fbe7e99..f6babb871b 100644 --- a/sched/group_join.c +++ b/sched/group_join.c @@ -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 */ diff --git a/sched/group_setupstreams.c b/sched/group_setupstreams.c index 217decd573..4a9fa57627 100644 --- a/sched/group_setupstreams.c +++ b/sched/group_setupstreams.c @@ -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 */ + diff --git a/sched/group_setuptaskfiles.c b/sched/group_setuptaskfiles.c index 269485ea46..6809f97847 100644 --- a/sched/group_setuptaskfiles.c +++ b/sched/group_setuptaskfiles.c @@ -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 */ + diff --git a/sched/os_start.c b/sched/os_start.c index ace475ba12..86b40bfbba 100644 --- a/sched/os_start.c +++ b/sched/os_start.c @@ -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 diff --git a/sched/pthread_create.c b/sched/pthread_create.c index 70b5ceb493..696e2c06c1 100644 --- a/sched/pthread_create.c +++ b/sched/pthread_create.c @@ -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; diff --git a/sched/sched_wait.c b/sched/sched_wait.c index 813d4f8427..9a6265e700 100644 --- a/sched/sched_wait.c +++ b/sched/sched_wait.c @@ -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 */ + diff --git a/sched/sched_waitid.c b/sched/sched_waitid.c index e75cf49879..545353e8b5 100644 --- a/sched/sched_waitid.c +++ b/sched/sched_waitid.c @@ -405,4 +405,5 @@ errout: return ERROR; } -#endif /* CONFIG_SCHED_WAITPID && CONFIG_SCHED_HAVE_PARENT*/ +#endif /* CONFIG_SCHED_WAITPID && CONFIG_SCHED_HAVE_PARENT */ + diff --git a/sched/task_create.c b/sched/task_create.c index 30fc1354ff..15bdebdb90 100644 --- a/sched/task_create.c +++ b/sched/task_create.c @@ -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; diff --git a/sched/task_exithook.c b/sched/task_exithook.c index 1c2137545d..688c25c44a 100644 --- a/sched/task_exithook.c +++ b/sched/task_exithook.c @@ -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 diff --git a/sched/task_init.c b/sched/task_init.c index 802d0748d5..79189f6cc6 100644 --- a/sched/task_init.c +++ b/sched/task_init.c @@ -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; -- GitLab