summaryrefslogtreecommitdiff
path: root/nuttx
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2013-02-05 19:50:37 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2013-02-05 19:50:37 +0000
commit0d9fb476ea6f347c48a3ac8c2d98251467421203 (patch)
treee98b731e1ff4298ed906fde23198fb4d9a9d61a9 /nuttx
parent70121d6ca8fd0e48f35b3ccb52e3b960e64df6c2 (diff)
downloadpx4-nuttx-0d9fb476ea6f347c48a3ac8c2d98251467421203.tar.gz
px4-nuttx-0d9fb476ea6f347c48a3ac8c2d98251467421203.tar.bz2
px4-nuttx-0d9fb476ea6f347c48a3ac8c2d98251467421203.zip
Moving pending signals to task group; Logic to recover some MQ resources on pthread_cacancel or task_delete; Now obeys rules for delivering signals to a process with threads
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5613 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx')
-rw-r--r--nuttx/ChangeLog9
-rw-r--r--nuttx/TODO46
-rw-r--r--nuttx/include/nuttx/sched.h21
-rw-r--r--nuttx/sched/Makefile4
-rw-r--r--nuttx/sched/group_create.c2
-rw-r--r--nuttx/sched/group_find.c52
-rw-r--r--nuttx/sched/group_internal.h7
-rw-r--r--nuttx/sched/group_join.c129
-rw-r--r--nuttx/sched/group_leave.c137
-rw-r--r--nuttx/sched/group_signal.c176
-rw-r--r--nuttx/sched/mq_internal.h4
-rw-r--r--nuttx/sched/mq_recover.c117
-rw-r--r--nuttx/sched/pthread_condtimedwait.c45
-rw-r--r--nuttx/sched/pthread_internal.h2
-rw-r--r--nuttx/sched/sig_cleanup.c32
-rw-r--r--nuttx/sched/sig_dispatch.c (renamed from nuttx/sched/sig_received.c)385
-rw-r--r--nuttx/sched/sig_internal.h14
-rw-r--r--nuttx/sched/sig_kill.c38
-rw-r--r--nuttx/sched/sig_mqnotempty.c37
-rw-r--r--nuttx/sched/sig_pending.c7
-rw-r--r--nuttx/sched/sig_queue.c47
-rw-r--r--nuttx/sched/sig_removependingsignal.c11
-rw-r--r--nuttx/sched/sig_unmaskpendingsignal.c11
-rw-r--r--nuttx/sched/task_exithook.c17
-rw-r--r--nuttx/sched/task_reparent.c4
-rw-r--r--nuttx/sched/task_setup.c6
-rw-r--r--nuttx/sched/timer_settime.c30
27 files changed, 908 insertions, 482 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 980885b00..cd9d7b474 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -4135,4 +4135,13 @@
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.
+ * included/nuttx/sched.h and sched/sig*.c: Numerous changes to the
+ signal deliver logic so that the delivery of signals to threads
+ within a task group will be compliant with delivery of signals
+ to threads within a POSIX process.
+ * sched/mq_recover.c and task_exithook.c: Add logic to handle the
+ case where a task is deleted (or pthread canceled) while it is
+ waiting on a message queue. task_delete() and pthread_cancel()
+ are dangerous interfaces. This is only one feeble recover measure
+ of *many* that would be needed to do this safely.
diff --git a/nuttx/TODO b/nuttx/TODO
index 3e2413ded..ac2afa775 100644
--- a/nuttx/TODO
+++ b/nuttx/TODO
@@ -1,4 +1,4 @@
-NuttX TODO List (Last updated February 2, 2013)
+NuttX TODO List (Last updated February 5, 2013)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This file summarizes known NuttX bugs, limitations, inconsistencies with
@@ -6,7 +6,7 @@ standards, things that could be improved, and ideas for enhancements.
nuttx/
- (12) Task/Scheduler (sched/)
+ (11) Task/Scheduler (sched/)
(1) Memory Managment (mm/)
(3) Signals (sched/, arch/)
(2) pthreads (sched/)
@@ -204,48 +204,6 @@ 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/nuttx/include/nuttx/sched.h b/nuttx/include/nuttx/sched.h
index 47910fabe..69ed689b8 100644
--- a/nuttx/include/nuttx/sched.h
+++ b/nuttx/include/nuttx/sched.h
@@ -73,7 +73,9 @@
# define HAVE_GROUP_MEMBERS 1
/* We need a group (but not members) if any other resources are shared within
- * a task group.
+ * a task group. NOTE: that we essentially always need a task group and that
+ * managing this definition adds a lot of overhead just to handle a corner-
+ * case very minimal system!
*/
#else
@@ -81,6 +83,8 @@
# define HAVE_TASK_GROUP 1 /* pthreads with parent*/
# elif !defined(CONFIG_DISABLE_ENVIRON)
# define HAVE_TASK_GROUP 1 /* Environment variables */
+# elif !defined(CONFIG_DISABLE_SIGNALS)
+# define HAVE_TASK_GROUP 1 /* Signals */
# elif defined(CONFIG_SCHED_ATEXIT)
# define HAVE_TASK_GROUP 1 /* Group atexit() function */
# elif defined(CONFIG_SCHED_ONEXIT)
@@ -293,13 +297,13 @@ struct task_group_s
{
#ifdef HAVE_GROUP_MEMBERS
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 */
+ 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 */
+ pid_t tg_task; /* The ID of the task within the group */
#endif
- uint8_t tg_flags; /* See GROUP_FLAG_* definitions */
+ uint8_t tg_flags; /* See GROUP_FLAG_* definitions */
/* Group membership ***********************************************************/
@@ -353,6 +357,12 @@ struct task_group_s
uint8_t tg_nkeys; /* Number pthread keys allocated */
#endif
+ /* POSIX Signal Control Fields ************************************************/
+
+#ifndef CONFIG_DISABLE_SIGNALS
+ sq_queue_t sigpendingq; /* List of pending signals */
+#endif
+
/* Environment variables ******************************************************/
#ifndef CONFIG_DISABLE_ENVIRON
@@ -471,7 +481,6 @@ struct tcb_s
sigset_t sigprocmask; /* Signals that are blocked */
sigset_t sigwaitmask; /* Waiting for pending signals */
sq_queue_t sigactionq; /* List of actions for signals */
- sq_queue_t sigpendingq; /* List of Pending Signals */
sq_queue_t sigpendactionq; /* List of pending signal actions */
sq_queue_t sigpostedq; /* List of posted signals */
siginfo_t sigunbinfo; /* Signal info when task unblocked */
diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile
index 488943688..8866e5d87 100644
--- a/nuttx/sched/Makefile
+++ b/nuttx/sched/Makefile
@@ -122,13 +122,13 @@ SIGNAL_SRCS += sig_kill.c sig_queue.c sig_waitinfo.c sig_timedwait.c
SIGNAL_SRCS += sig_findaction.c sig_allocatependingsigaction.c
SIGNAL_SRCS += sig_releasependingsigaction.c sig_unmaskpendingsignal.c
SIGNAL_SRCS += sig_removependingsignal.c sig_releasependingsignal.c sig_lowest.c
-SIGNAL_SRCS += sig_mqnotempty.c sig_cleanup.c sig_received.c sig_deliver.c
+SIGNAL_SRCS += sig_mqnotempty.c sig_cleanup.c sig_dispatch.c sig_deliver.c
SIGNAL_SRCS += pause.c
MQUEUE_SRCS = mq_open.c mq_close.c mq_unlink.c mq_send.c mq_timedsend.c
MQUEUE_SRCS += mq_sndinternal.c mq_receive.c mq_timedreceive.c mq_rcvinternal.c
MQUEUE_SRCS += mq_initialize.c mq_descreate.c mq_findnamed.c mq_msgfree.c
-MQUEUE_SRCS += mq_msgqfree.c mq_release.c
+MQUEUE_SRCS += mq_msgqfree.c mq_release.c mq_recover.c
ifneq ($(CONFIG_DISABLE_SIGNALS),y)
MQUEUE_SRCS += mq_waitirq.c
diff --git a/nuttx/sched/group_create.c b/nuttx/sched/group_create.c
index ccf2e7519..5f3867b72 100644
--- a/nuttx/sched/group_create.c
+++ b/nuttx/sched/group_create.c
@@ -133,7 +133,7 @@ void group_assigngid(FAR struct task_group_s *group)
/* Does a task group with this ID already exist? */
irqrestore(flags);
- if (group_find(gid) == NULL)
+ if (group_findbygid(gid) == NULL)
{
/* Now assign this ID to the group and return */
diff --git a/nuttx/sched/group_find.c b/nuttx/sched/group_find.c
index 8683990dd..d7e82d1f9 100644
--- a/nuttx/sched/group_find.c
+++ b/nuttx/sched/group_find.c
@@ -76,7 +76,7 @@
*****************************************************************************/
/*****************************************************************************
- * Name: group_find
+ * Name: group_findbygid
*
* Description:
* Given a group ID, find the group task structure with that ID. IDs are
@@ -100,12 +100,12 @@
*****************************************************************************/
#ifdef HAVE_GROUP_MEMBERS
-FAR struct task_group_s *group_find(gid_t gid)
+FAR struct task_group_s *group_findbygid(gid_t gid)
{
FAR struct task_group_s *group;
irqstate_t flags;
- /* Find the status structure with the matching PID */
+ /* Find the status structure with the matching GID */
flags = irqsave();
for (group = g_grouphead; group; group = group->flink)
@@ -122,4 +122,50 @@ FAR struct task_group_s *group_find(gid_t gid)
}
#endif
+/*****************************************************************************
+ * Name: group_findbygid
+ *
+ * Description:
+ * Given a task ID, find the group task structure with was started by that
+ * task ID. That task's ID is retained in the group as tg_task and will
+ * be remember even if the main task thread leaves the group.
+ *
+ * Parameters:
+ * pid - The task ID of the main task thread.
+ *
+ * Return Value:
+ * On success, a pointer to the group task structure is returned. This
+ * function can fail only if there is no group that corresponds to the
+ * task ID.
+ *
+ * Assumptions:
+ * Called during when signally tasks in a safe context. No special
+ * precautions should be required here. However, extra care is taken when
+ * accessing the global g_grouphead list.
+ *
+ *****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_SCHED_HAVE_PARENT)
+FAR struct task_group_s *group_findbypid(pid_t pid)
+{
+ FAR struct task_group_s *group;
+ irqstate_t flags;
+
+ /* Find the status structure with the matching PID */
+
+ flags = irqsave();
+ for (group = g_grouphead; group; group = group->flink)
+ {
+ if (group->tg_task == pid)
+ {
+ irqrestore(flags);
+ return group;
+ }
+ }
+
+ irqrestore(flags);
+ return NULL;
+}
+#endif
+
#endif /* HAVE_TASK_GROUP */
diff --git a/nuttx/sched/group_internal.h b/nuttx/sched/group_internal.h
index f29cb53de..520a9544b 100644
--- a/nuttx/sched/group_internal.h
+++ b/nuttx/sched/group_internal.h
@@ -85,9 +85,10 @@ int group_join(FAR struct pthread_tcb_s *tcb);
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);
+FAR struct task_group_s *group_findbygid(gid_t gid);
+#endif
+#if !defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_SCHED_HAVE_PARENT)
+FAR struct task_group_s *group_findbypid(pid_t pid);
#endif
/* Convenience functions */
diff --git a/nuttx/sched/group_join.c b/nuttx/sched/group_join.c
index f6babb871..d6ca6d498 100644
--- a/nuttx/sched/group_join.c
+++ b/nuttx/sched/group_join.c
@@ -71,6 +71,75 @@
*****************************************************************************/
/*****************************************************************************
+ * Name: group_addmember
+ *
+ * Description:
+ * Add a new member to a group.
+ *
+ * Parameters:
+ * group - The task group to add the new member
+ * pid - The new member
+ *
+ * Return Value:
+ * 0 (OK) on success; a negated errno value on failure.
+ *
+ * Assumptions:
+ * Called during thread creation and during reparenting in a safe context.
+ * No special precautions are required here.
+ *
+ *****************************************************************************/
+
+#ifdef HAVE_GROUP_MEMBERS
+static inline int group_addmember(FAR struct task_group_s *group, pid_t pid)
+{
+ irqstate_t flags;
+
+ DEBUGASSERT(group && group->tg_nmembers < UINT8_MAX);
+
+ /* Will we need to extend the size of the array of groups? */
+
+ if (group->tg_nmembers >= group->tg_mxmembers)
+ {
+ FAR pid_t *newmembers;
+ unsigned int newmax;
+
+ /* Yes... reallocate the array of members */
+
+ newmax = group->tg_mxmembers + GROUP_REALLOC_MEMBERS;
+ if (newmax > UINT8_MAX)
+ {
+ newmax = UINT8_MAX;
+ }
+
+ newmembers = (FAR pid_t *)
+ krealloc(group->tg_members, sizeof(pid_t) * newmax);
+
+ if (!newmembers)
+ {
+ return -ENOMEM;
+ }
+
+ /* Save the new number of members in the reallocated members array.
+ * We need to make the following atomic because the member list
+ * may be traversed from an interrupt handler (read-only).
+ */
+
+ flags = irqsave();
+ group->tg_members = newmembers;
+ group->tg_mxmembers = newmax;
+ irqrestore(flags);
+ }
+
+ /* Assign this new pid to the group; group->tg_nmembers will be incremented
+ * by the caller.
+ */
+
+ group->tg_members[group->tg_nmembers] = pid;
+ return OK;
+}
+#endif /* HAVE_GROUP_MEMBERS */
+
+/*****************************************************************************
* Public Functions
*****************************************************************************/
@@ -164,64 +233,4 @@ int group_join(FAR struct pthread_tcb_s *tcb)
return OK;
}
-/*****************************************************************************
- * Name: group_addmember
- *
- * Description:
- * Add a new member to a group.
- *
- * Parameters:
- * group - The task group to add the new member
- * pid - The new member
- *
- * Return Value:
- * 0 (OK) on success; a negated errno value on failure.
- *
- * Assumptions:
- * Called during thread creation and during reparenting in a safe context.
- * No special precautions are required here.
- *
- *****************************************************************************/
-
-#ifdef HAVE_GROUP_MEMBERS
-int group_addmember(FAR struct task_group_s *group, pid_t pid)
-{
- DEBUGASSERT(group && group->tg_nmembers < UINT8_MAX);
-
- /* Will we need to extend the size of the array of groups? */
-
- if (group->tg_nmembers >= group->tg_mxmembers)
- {
- FAR pid_t *newmembers;
- unsigned int newmax;
-
- /* Yes... reallocate the array of members */
-
- newmax = group->tg_mxmembers + GROUP_REALLOC_MEMBERS;
- if (newmax > UINT8_MAX)
- {
- newmax = UINT8_MAX;
- }
-
- newmembers = (FAR pid_t *)
- krealloc(group->tg_members, sizeof(pid_t) * newmax);
-
- if (!newmembers)
- {
- return -ENOMEM;
- }
-
- /* Save the new number of members in the reallocated members array */
-
- group->tg_members = newmembers;
- group->tg_mxmembers = newmax;
- }
-
- /* Assign this new pid to the group. */
-
- group->tg_members[group->tg_nmembers] = pid;
- return OK;
-}
-#endif /* HAVE_GROUP_MEMBERS */
-
#endif /* HAVE_TASK_GROUP && !CONFIG_DISABLE_PTHREAD */
diff --git a/nuttx/sched/group_leave.c b/nuttx/sched/group_leave.c
index 43a79c9bb..b3d2f20f8 100644
--- a/nuttx/sched/group_leave.c
+++ b/nuttx/sched/group_leave.c
@@ -49,6 +49,7 @@
#include <nuttx/lib.h>
#include "env_internal.h"
+#include "sig_internal.h"
#include "pthread_internal.h"
#include "mq_internal.h"
#include "group_internal.h"
@@ -156,6 +157,12 @@ static inline void group_release(FAR struct task_group_s *group)
group_removechildren(group);
#endif
+#ifndef CONFIG_DISABLE_SIGNALS
+ /* Release pending signals */
+
+ sig_release(group);
+#endif
+
#ifndef CONFIG_DISABLE_PTHREAD
/* Release pthread resources */
@@ -217,6 +224,74 @@ static inline void group_release(FAR struct task_group_s *group)
}
/*****************************************************************************
+ * Name: group_removemember
+ *
+ * Description:
+ * Remove a member from a group.
+ *
+ * Parameters:
+ * group - The group from which to remove the member.
+ * pid - The member to be removed.
+ *
+ * Return Value:
+ * On success, returns the number of members remaining in the group (>=0).
+ * Can fail only if the member is not found in the group. On failure,
+ * returns -ENOENT
+ *
+ * Assumptions:
+ * Called during task deletion and also from the reparenting logic, both
+ * in a safe context. No special precautions are required here.
+ *
+ *****************************************************************************/
+
+#ifdef HAVE_GROUP_MEMBERS
+static inline int group_removemember(FAR struct task_group_s *group, pid_t pid)
+{
+ irqstate_t flags;
+ int i;
+
+ DEBUGASSERT(group);
+
+ /* Find the member in the array of members and remove it */
+
+ for (i = 0; i < group->tg_nmembers; i++)
+ {
+ /* Does this member have the matching pid */
+
+ if (group->tg_members[i] == pid)
+ {
+ /* Yes.. break out of the loop. We don't do the actual
+ * removal here, instead we re-test i and do the adjustments
+ * outside of the loop. We do this because we want the
+ * DEBUGASSERT to work properly.
+ */
+
+ break;
+ }
+ }
+
+ /* Now, test if we found the task in the array of members. */
+
+ if (i < group->tg_nmembers)
+ {
+ /* Remove the member from the array of members. This must be an
+ * atomic operation because the member array may be accessed from
+ * interrupt handlers (read-only).
+ */
+
+ flags = irqsave();
+ group->tg_members[i] = group->tg_members[group->tg_nmembers - 1];
+ group->tg_nmembers--;
+ irqrestore(flags);
+
+ return group->tg_nmembers;
+ }
+
+ return -ENOENT;
+}
+#endif /* HAVE_GROUP_MEMBERS */
+
+/*****************************************************************************
* Public Functions
*****************************************************************************/
@@ -315,66 +390,4 @@ void group_leave(FAR struct tcb_s *tcb)
}
#endif /* HAVE_GROUP_MEMBERS */
-
-/*****************************************************************************
- * Name: group_removemember
- *
- * Description:
- * Remove a member from a group.
- *
- * Parameters:
- * group - The group from which to remove the member.
- * pid - The member to be removed.
- *
- * Return Value:
- * On success, returns the number of members remaining in the group (>=0).
- * Can fail only if the member is not found in the group. On failure,
- * returns -ENOENT
- *
- * Assumptions:
- * Called during task deletion and also from the reparenting logic, both
- * in a safe context. No special precautions are required here.
- *
- *****************************************************************************/
-
-#ifdef HAVE_GROUP_MEMBERS
-int group_removemember(FAR struct task_group_s *group, pid_t pid)
-{
- int i;
-
- DEBUGASSERT(group);
-
- /* Find the member in the array of members and remove it */
-
- for (i = 0; i < group->tg_nmembers; i++)
- {
- /* Does this member have the matching pid */
-
- if (group->tg_members[i] == pid)
- {
- /* Yes.. break out of the loop. We don't do the actual
- * removal here, instead we re-test i and do the adjustments
- * outside of the loop. We do this because we want the
- * DEBUGASSERT to work properly.
- */
-
- break;
- }
- }
-
- /* Now, test if we found the task in the array of members. */
-
- if (i < group->tg_nmembers)
- {
- /* Remove the member from the array of members */
-
- group->tg_members[i] = group->tg_members[group->tg_nmembers - 1];
- group->tg_nmembers--;
- return group->tg_nmembers;
- }
-
- return -ENOENT;
-}
-#endif /* HAVE_GROUP_MEMBERS */
-
#endif /* HAVE_TASK_GROUP */
diff --git a/nuttx/sched/group_signal.c b/nuttx/sched/group_signal.c
index dcea62eb7..0dc41be1c 100644
--- a/nuttx/sched/group_signal.c
+++ b/nuttx/sched/group_signal.c
@@ -84,80 +84,162 @@
* 0 (OK) on success; a negated errno value on failure.
*
* Assumptions:
- * Called during task terminatino in a safe context. No special precautions
- * are required here.
+ * Called during task termination in a safe context. No special precautions
+ * are required here. Because signals can be sent from interrupt handlers,
+ * this function may be called indirectly in the context of an interrupt
+ * handler.
*
*****************************************************************************/
int group_signal(FAR struct task_group_s *group, FAR siginfo_t *info)
{
#ifdef HAVE_GROUP_MEMBERS
- FAR struct tcb_s *gtcb;
+ FAR struct tcb_s *tcb; /* Working TCB */
+ FAR struct tcb_s *dtcb = NULL; /* Default, valid TCB */
+ FAR struct tcb_s *utcb = NULL; /* TCB with this signal unblocked */
+ FAR struct tcb_s *atcb = NULL; /* This TCB was awakened */
+ FAR struct tcb_s *ptcb = NULL; /* This TCB received the signal */
+ FAR sigactq_t *sigact;
+ bool dispatched = false;
+ bool done = false;
+ int ret;
int i;
DEBUGASSERT(group && info);
- /* Make sure that pre-emption is disabled to that we signal all of teh
- * members of the group before any of them actually run.
+ /* Make sure that pre-emption is disabled to that we signal all of the
+ * members of the group before any of them actually run. (This does
+ * nothing if were were called from an interrupt handler).
*/
sched_lock();
- /* Send the signal to each member of the group */
+ /* Now visit each member of the group and do the same checks. The main
+ * task is always the first member in the member array (unless it has
+ * already exited). So the main task will get predence in the following
+ * search algorithm.
+ */
- for (i = 0; i < group->tg_nmembers; i++)
+ for (i = 0; i < group->tg_nmembers && !done; i++)
{
- gtcb = sched_gettcb(group->tg_members[i]);
- DEBUGASSERT(gtcb);
- if (gtcb)
+ tcb = sched_gettcb(group->tg_members[i]);
+ DEBUGASSERT(tcb);
+ if (tcb)
{
- /* Use the sig_received interface so that it does not muck with
- * the siginfo_t.
+ /* Set this one as the default if we have not already set the
+ * default.
*/
-#ifdef CONFIG_DEBUG
- int ret = sig_received(gtcb, info);
- DEBUGASSERT(ret == 0);
-#else
- (void)sig_received(gtcb, info);
-#endif
+ if (!dtcb)
+ {
+ dtcb = tcb;
+ }
+
+ /* Is the thread waiting for this signal (in this case, the
+ * signal is probably blocked).
+ */
+
+ if (sigismember(&tcb->sigwaitmask, info->si_signo) && !atcb)
+ {
+ /* Yes.. This means that the task is suspended, waiting
+ * for this signal to occur. Stop looking and use this TCB.
+ * The requirement is this: 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.
+ */
+
+ ret = sig_tcbdispatch(tcb, info);
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ /* Limit to one thread */
+
+ atcb = tcb;
+ done = dispatched;
+ }
+
+ /* Is this signal unblocked on this thread? */
+
+ if (!sigismember(&tcb->sigprocmask, info->si_signo) &&
+ !dispatched && tcb != atcb)
+ {
+ /* Yes.. remember this TCB if we have not encountered any
+ * other threads that have the signal unblocked.
+ */
+
+ if (!utcb)
+ {
+ utcb = tcb;
+ }
+
+ /* Is there also an action associated with the task? */
+
+ sigact = sig_findaction(tcb, info->si_signo);
+ if (sigact)
+ {
+ /* Yes.. then use this thread. The requirement is this:
+ * If a task group receives a signal then one and only one
+ * indeterminate thread in the task group which is not
+ * blocking the signal will receive the signal.
+ */
+
+ ret = sig_tcbdispatch(tcb, info);
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ /* Limit to one thread */
+
+ dispatched = true;
+ done = (atcb != NULL);
+ }
+ }
}
}
-
+
+ /* We need to dispatch the signal in any event (if nothing else so that it
+ * can be added to the pending signal list). If we found a thread with the
+ * signal unblocked, then use that thread.
+ */
+
+ if (!dispatched && atcb == NULL)
+ {
+ if (utcb)
+ {
+ tcb = utcb;
+ }
+
+ /* Otherwise use the default TCB. There should always be a default
+ * TCB. It will have the signal blocked, but can be used to get the
+ * signal to a pending state.
+ */
+
+ else /* if (dtcb) */
+ {
+ DEBUGASSERT(dtcb);
+ tcb = dtcb;
+ }
+
+ /* Now deliver the signal to the selected group member */
+
+ ret = sig_tcbdispatch(tcb, info);
+ }
+
/* Re-enable pre-emption an return success */
+errout:
sched_unlock();
- return OK;
+ return ret;
+
#else
+
return -ENOSYS;
+
#endif
}
-/*****************************************************************************
- * Name: group_signalmember
- *
- * Description:
- * Send a signal to every member of the group to which task belongs.
- *
- * Parameters:
- * tcb - The tcb of one task in the task group that needs to be signalled.
- *
- * Return Value:
- * 0 (OK) on success; a negated errno value on failure.
- *
- * Assumptions:
- * Called during task terminatino in a safe context. No special precautions
- * are required here.
- *
- *****************************************************************************/
-
-int group_signalmember(FAR struct tcb_s *tcb, FAR siginfo_t *info)
-{
-#ifdef HAVE_GROUP_MEMBERS
- DEBUGASSERT(tcb);
- return group_signal(tcb->group, info);
-#else
- return sig_received(tcb, info);
-#endif
-}
#endif /* HAVE_TASK_GROUP && !CONFIG_DISABLE_SIGNALS */
diff --git a/nuttx/sched/mq_internal.h b/nuttx/sched/mq_internal.h
index 5a05d9da8..8196b573b 100644
--- a/nuttx/sched/mq_internal.h
+++ b/nuttx/sched/mq_internal.h
@@ -177,6 +177,10 @@ int mq_dosend(mqd_t mqdes, FAR mqmsg_t *mqmsg, const void *msg,
struct task_group_s; /* Forward reference */
void mq_release(FAR struct task_group_s *group);
+/* mq_recover.c ************************************************************/
+
+void mq_recover(FAR struct tcb_s *tcb);
+
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/nuttx/sched/mq_recover.c b/nuttx/sched/mq_recover.c
new file mode 100644
index 000000000..040ded64c
--- /dev/null
+++ b/nuttx/sched/mq_recover.c
@@ -0,0 +1,117 @@
+/************************************************************************
+ * sched/mq_recover.c
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************/
+
+/************************************************************************
+ * Included Files
+ ************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+
+#include <nuttx/mqueue.h>
+#include <nuttx/sched.h>
+
+#include "mq_internal.h"
+
+/************************************************************************
+ * Definitions
+ ************************************************************************/
+
+/************************************************************************
+ * Private Type Declarations
+ ************************************************************************/
+
+/************************************************************************
+ * Global Variables
+ ************************************************************************/
+
+/************************************************************************
+ * Private Variables
+ ************************************************************************/
+
+/************************************************************************
+ * Private Functions
+ ************************************************************************/
+
+/************************************************************************
+ * Public Functions
+ ************************************************************************/
+
+/************************************************************************
+ * Name: mq_recover
+ *
+ * Description:
+ * This function is called when a task is deleted via task_deleted or
+ * via pthread_cancel. I checks if the task was waiting for a message
+ * queue event and adjusts counts appropriately.
+ *
+ * Inputs:
+ * tcb - The TCB of the terminated task or thread
+ *
+ * Return Value:
+ * None.
+ *
+ * Assumptions:
+ * This function is called from task deletion logic in a safe context.
+ *
+ ************************************************************************/
+
+void mq_recover(FAR struct tcb_s *tcb)
+{
+ /* TODO: What if it was waiting for a timed message queue event?
+ * We might need the wdog in the TCB so that we can cancel timeouts.
+ */
+
+ /* Was the task waiting for a message queue to become non-empty? */
+
+ if (tcb->task_state == TSTATE_WAIT_MQNOTEMPTY)
+ {
+ /* Decrement the count of waiters */
+
+ DEBUGASSERT(tcb->msgwaitq && tcb->msgwaitq->nwaitnotempty > 0);
+ tcb->msgwaitq->nwaitnotempty--;
+ }
+
+ /* Was the task waiting for a message queue to become non-full? */
+
+ else if (tcb->task_state == TSTATE_WAIT_MQNOTFULL)
+ {
+ /* Decrement the count of waiters */
+
+ DEBUGASSERT(tcb->msgwaitq && tcb->msgwaitq->nwaitnotfull > 0);
+ tcb->msgwaitq->nwaitnotfull--;
+ }
+}
diff --git a/nuttx/sched/pthread_condtimedwait.c b/nuttx/sched/pthread_condtimedwait.c
index 25f86d813..3914f40ff 100644
--- a/nuttx/sched/pthread_condtimedwait.c
+++ b/nuttx/sched/pthread_condtimedwait.c
@@ -52,6 +52,7 @@
#include "os_internal.h"
#include "pthread_internal.h"
#include "clock_internal.h"
+#include "sig_internal.h"
/****************************************************************************
* Definitions
@@ -94,6 +95,48 @@
static void pthread_condtimedout(int argc, uint32_t pid, uint32_t signo)
{
+#ifdef HAVE_GROUP_MEMBERS
+
+ FAR struct tcb_s *tcb;
+ siginfo_t info;
+
+ /* The logic below if equivalent to sigqueue(), but uses sig_tcbdispatch()
+ * instead of sig_dispatch(). This avoids the group signal deliver logic
+ * and assures, instead, that the signal is delivered specifically to this
+ * thread that is known to be waiting on the signal.
+ */
+
+ /* Get the waiting TCB. sched_gettcb() might return NULL if the task has
+ * exited for some reason.
+ */
+
+ tcb = sched_gettcb((pid_t)pid);
+ if (tcb)
+ {
+ /* Create the siginfo structure */
+
+ info.si_signo = signo;
+ info.si_code = SI_QUEUE;
+ info.si_value.sival_ptr = NULL;
+#ifdef CONFIG_SCHED_HAVE_PARENT
+ info.si_pid = (pid_t)pid;
+ info.si_status = OK;
+#endif
+
+ /* Process the receipt of the signal. The scheduler is not locked as
+ * is normally the case when this function is called because we are in
+ * a watchdog timer interrupt handler.
+ */
+
+ (void)sig_tcbdispatch(tcb, &info);
+ }
+
+#else /* HAVE_GROUP_MEMBERS */
+
+ /* Things are a little easier if there are not group members. We can just
+ * use sigqueue().
+ */
+
#ifdef CONFIG_CAN_PASS_STRUCTS
union sigval value;
@@ -104,6 +147,8 @@ static void pthread_condtimedout(int argc, uint32_t pid, uint32_t signo)
#else
(void)sigqueue((int)pid, (int)signo, NULL);
#endif
+
+#endif /* HAVE_GROUP_MEMBERS */
}
/****************************************************************************
diff --git a/nuttx/sched/pthread_internal.h b/nuttx/sched/pthread_internal.h
index aa0e8ba15..1a1c2282a 100644
--- a/nuttx/sched/pthread_internal.h
+++ b/nuttx/sched/pthread_internal.h
@@ -97,7 +97,7 @@ extern "C"
struct task_group_s; /* Forward reference */
void weak_function pthread_initialize(void);
-int pthread_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start,
+int pthread_schedsetup(FAR struct pthread_tcb_s *tcb, int priority, start_t start,
pthread_startroutine_t entry);
int pthread_completejoin(pid_t pid, FAR void *exit_value);
void pthread_destroyjoin(FAR struct task_group_s *group,
diff --git a/nuttx/sched/sig_cleanup.c b/nuttx/sched/sig_cleanup.c
index a421f3a59..46b3cb584 100644
--- a/nuttx/sched/sig_cleanup.c
+++ b/nuttx/sched/sig_cleanup.c
@@ -81,7 +81,6 @@ void sig_cleanup(FAR struct tcb_s *stcb)
{
FAR sigactq_t *sigact;
FAR sigq_t *sigq;
- FAR sigpendq_t *sigpend;
/* Deallocate all entries in the list of signal actions */
@@ -90,13 +89,6 @@ void sig_cleanup(FAR struct tcb_s *stcb)
sig_releaseaction(sigact);
}
- /* Deallocate all entries in the list of pending signals */
-
- while ((sigpend = (FAR sigpendq_t*)sq_remfirst(&stcb->sigpendingq)) != NULL)
- {
- sig_releasependingsignal(sigpend);
- }
-
/* Deallocate all entries in the list of pending signal actions */
while ((sigq = (FAR sigq_t*)sq_remfirst(&stcb->sigpendactionq)) != NULL)
@@ -116,3 +108,27 @@ void sig_cleanup(FAR struct tcb_s *stcb)
stcb->sigprocmask = ALL_SIGNAL_SET;
stcb->sigwaitmask = NULL_SIGNAL_SET;
}
+
+/************************************************************************
+ * Name: sig_release
+ *
+ * Description:
+ * Deallocate all signal-related lists in a group. This function is
+ * called only when the last thread leaves the group. The caller is
+ * expected to have assured the critical section necessary to perform
+ * this action.
+ *
+ ************************************************************************/
+
+void sig_release(FAR struct task_group_s *group)
+{
+ FAR sigpendq_t *sigpend;
+
+ /* Deallocate all entries in the list of pending signals */
+
+ while ((sigpend = (FAR sigpendq_t*)sq_remfirst(&group->sigpendingq)) != NULL)
+ {
+ sig_releasependingsignal(sigpend);
+ }
+}
+
diff --git a/nuttx/sched/sig_received.c b/nuttx/sched/sig_dispatch.c
index 4cfb10d06..7c4d34138 100644
--- a/nuttx/sched/sig_received.c
+++ b/nuttx/sched/sig_dispatch.c
@@ -1,5 +1,5 @@
-/************************************************************************
- * sched/sig_received.c
+/****************************************************************************
+ * sched/sig_dispatch.c
*
* Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
@@ -31,11 +31,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Included Files
- ************************************************************************/
+ ****************************************************************************/
#include <nuttx/config.h>
@@ -49,37 +49,41 @@
#include <nuttx/arch.h>
#include "os_internal.h"
+#include "group_internal.h"
#include "sem_internal.h"
#include "sig_internal.h"
#include "mq_internal.h"
-/************************************************************************
+/****************************************************************************
* Definitions
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Type Declarations
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Global Variables
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Variables
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Functions
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Name: sig_queueaction
*
* Description:
* Queue a signal action for delivery to a task.
*
- ************************************************************************/
+ * Returned Value:
+ * Returns 0 (OK) on success or a negated errno value on failure.
+ *
+ ****************************************************************************/
static int sig_queueaction(FAR struct tcb_s *stcb, siginfo_t *info)
{
@@ -100,12 +104,15 @@ static int sig_queueaction(FAR struct tcb_s *stcb, siginfo_t *info)
if ((sigact) && (sigact->act.sa_u._sa_sigaction))
{
- /* Allocate a new element for the signal queue. NOTE: sig_allocatependingsigaction
- * will force a system crash if it is unable to allocate memory for the
- * signal data */
+ /* Allocate a new element for the signal queue. NOTE:
+ * sig_allocatependingsigaction will force a system crash if it is
+ * unable to allocate memory for the signal data */
sigq = sig_allocatependingsigaction();
- if (!sigq) ret = ERROR;
+ if (!sigq)
+ {
+ ret = -ENOMEM;
+ }
else
{
/* Populate the new signal queue element */
@@ -126,45 +133,13 @@ static int sig_queueaction(FAR struct tcb_s *stcb, siginfo_t *info)
return ret;
}
-/************************************************************************
- * Name: sig_findpendingsignal
- *
- * Description:
- * Find a specified element in the pending signal list
- *
- ************************************************************************/
-
-static FAR sigpendq_t *sig_findpendingsignal(FAR struct tcb_s *stcb, int signo)
-{
- FAR sigpendq_t *sigpend = NULL;
- irqstate_t saved_state;
-
- /* Verify the caller's sanity */
-
- if (stcb)
- {
- /* Pending sigals can be added from interrupt level. */
-
- saved_state = irqsave();
-
- /* Seach the list for a sigpendion on this signal */
-
- for(sigpend = (FAR sigpendq_t*)stcb->sigpendingq.head;
- (sigpend && sigpend->info.si_signo != signo);
- sigpend = sigpend->flink);
- irqrestore(saved_state);
- }
-
- return sigpend;
-}
-
-/************************************************************************
+/****************************************************************************
* Name: sig_allocatependingsignal
*
* Description:
* Allocate a pending signal list entry
*
- ************************************************************************/
+ ****************************************************************************/
static FAR sigpendq_t *sig_allocatependingsignal(void)
{
@@ -223,7 +198,37 @@ static FAR sigpendq_t *sig_allocatependingsignal(void)
return sigpend;
}
-/************************************************************************
+/****************************************************************************
+ * Name: sig_findpendingsignal
+ *
+ * Description:
+ * Find a specified element in the pending signal list
+ *
+ ****************************************************************************/
+
+static FAR sigpendq_t *sig_findpendingsignal(FAR struct task_group_s *group,
+ int signo)
+{
+ FAR sigpendq_t *sigpend = NULL;
+ irqstate_t saved_state;
+
+ DEBUGASSERT(group);
+
+ /* Pending sigals can be added from interrupt level. */
+
+ saved_state = irqsave();
+
+ /* Seach the list for a sigpendion on this signal */
+
+ for(sigpend = (FAR sigpendq_t*)group->sigpendingq.head;
+ (sigpend && sigpend->info.si_signo != signo);
+ sigpend = sigpend->flink);
+
+ irqrestore(saved_state);
+ return sigpend;
+}
+
+/****************************************************************************
* Name: sig_addpendingsignal
*
* Description:
@@ -232,17 +237,20 @@ static FAR sigpendq_t *sig_allocatependingsignal(void)
* was done intentionally so that a run-away sender cannot consume
* all of memory.
*
- ************************************************************************/
+ ****************************************************************************/
static FAR sigpendq_t *sig_addpendingsignal(FAR struct tcb_s *stcb,
- siginfo_t *info)
+ FAR siginfo_t *info)
{
+ FAR struct task_group_s *group = stcb->group;
FAR sigpendq_t *sigpend;
- irqstate_t saved_state;
+ irqstate_t saved_state;
+
+ DEBUGASSERT(group);
/* Check if the signal is already pending */
- sigpend = sig_findpendingsignal(stcb, info->si_signo);
+ sigpend = sig_findpendingsignal(group, info->si_signo);
if (sigpend)
{
/* The signal is already pending... retain only one copy */
@@ -266,7 +274,7 @@ static FAR sigpendq_t *sig_addpendingsignal(FAR struct tcb_s *stcb,
/* Add the structure to the pending signal list */
saved_state = irqsave();
- sq_addlast((FAR sq_entry_t*)sigpend, &stcb->sigpendingq);
+ sq_addlast((FAR sq_entry_t*)sigpend, &group->sigpendingq);
irqrestore(saved_state);
}
}
@@ -274,12 +282,12 @@ static FAR sigpendq_t *sig_addpendingsignal(FAR struct tcb_s *stcb,
return sigpend;
}
-/************************************************************************
+/****************************************************************************
* Public Functions
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
- * Name: sig_received
+/****************************************************************************
+ * Name: sig_tcbdispatch
*
* Description:
* All signals received the task (whatever the source) go through this
@@ -290,115 +298,210 @@ static FAR sigpendq_t *sig_addpendingsignal(FAR struct tcb_s *stcb,
* - Unblocking tasks that are waiting for signals
* - Queuing pending signals.
*
- ************************************************************************/
+ * This function will deliver the signal to the task associated with
+ * the specified TCB. This function should *not* typically be used
+ * to dispatch signals since it will *not* follow the group signal
+ * deliver algorithms.
+ *
+ * Returned Value:
+ * Returns 0 (OK) on success or a negated errno value on failure.
+ *
+ ****************************************************************************/
-int sig_received(FAR struct tcb_s *stcb, siginfo_t *info)
+int sig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info)
{
irqstate_t saved_state;
- int ret = ERROR;
+ int ret = OK;
sdbg("TCB=0x%08x signo=%d code=%d value=%d mask=%08x\n",
stcb, info->si_signo, info->si_code,
info->si_value.sival_int, stcb->sigprocmask);
- if (stcb && info)
- {
- ret = OK;
+ DEBUGASSERT(stcb && info);
- /****************** MASKED SIGNAL HANDLING ******************/
+ /************************* MASKED SIGNAL HANDLING ************************/
+
+ /* Check if the signal is masked -- if it is, it will be added to the list
+ * of pending signals.
+ */
- /* Check if the signal is masked -- if it is, it will be added to the
- * list of pending signals.
+ if (sigismember(&stcb->sigprocmask, info->si_signo))
+ {
+ /* Check if the task is waiting for this pending signal. If so, then unblock it.
+ * This must be performed in a critical section because signals can be queued
+ * from the interrupt level.
*/
- if (sigismember(&stcb->sigprocmask, info->si_signo))
+ saved_state = irqsave();
+ if (stcb->task_state == TSTATE_WAIT_SIG &&
+ sigismember(&stcb->sigwaitmask, info->si_signo))
{
- /* Check if the task is waiting for this pending signal. If so,
- * then unblock it. This must be performed in a critical section
- * because signals can be queued from the interrupt level.
- */
-
- saved_state = irqsave();
- if (stcb->task_state == TSTATE_WAIT_SIG &&
- sigismember(&stcb->sigwaitmask, info->si_signo))
- {
- memcpy(&stcb->sigunbinfo, info, sizeof(siginfo_t));
- stcb->sigwaitmask = NULL_SIGNAL_SET;
- up_unblock_task(stcb);
- irqrestore(saved_state);
- }
+ memcpy(&stcb->sigunbinfo, info, sizeof(siginfo_t));
+ stcb->sigwaitmask = NULL_SIGNAL_SET;
+ up_unblock_task(stcb);
+ irqrestore(saved_state);
+ }
- /* Its not one we are waiting for... Add it to the list of pending
- * signals.
- */
+ /* Its not one we are waiting for... Add it to the list of pending
+ * signals.
+ */
- else
+ else
+ {
+ irqrestore(saved_state);
+ if (!sig_addpendingsignal(stcb, info))
{
- irqrestore(saved_state);
- if (!sig_addpendingsignal(stcb, info))
- {
- PANIC(OSERR_FAILEDTOADDSIGNAL);
- }
+ PANIC(OSERR_FAILEDTOADDSIGNAL);
}
}
+ }
- /****************** UNMASKED SIGNAL HANDLING ******************/
+ /************************ UNMASKED SIGNAL HANDLING ***********************/
- else
- {
- /* Queue any sigaction's requested by this task. */
+ else
+ {
+ /* Queue any sigaction's requested by this task. */
- ret = sig_queueaction(stcb, info);
+ ret = sig_queueaction(stcb, info);
- /* Then schedule execution of the signal handling action on
- * the recipients thread.
- */
+ /* Then schedule execution of the signal handling action on the
+ * recipient's thread.
+ */
- up_schedule_sigaction(stcb, sig_deliver);
+ up_schedule_sigaction(stcb, sig_deliver);
- /* Check if the task is waiting for an unmasked signal. If so,
- * then unblock it. This must be performed in a critical section
- * because signals can be queued from the interrupt level.
- */
+ /* Check if the task is waiting for an unmasked signal. If so, then
+ * unblock it. This must be performed in a critical section because
+ * signals can be queued from the interrupt level.
+ */
- saved_state = irqsave();
- if (stcb->task_state == TSTATE_WAIT_SIG)
- {
- memcpy(&stcb->sigunbinfo, info, sizeof(siginfo_t));
- stcb->sigwaitmask = NULL_SIGNAL_SET;
- up_unblock_task(stcb);
- }
- irqrestore(saved_state);
+ saved_state = irqsave();
+ if (stcb->task_state == TSTATE_WAIT_SIG)
+ {
+ memcpy(&stcb->sigunbinfo, info, sizeof(siginfo_t));
+ stcb->sigwaitmask = NULL_SIGNAL_SET;
+ up_unblock_task(stcb);
+ }
- /* If the task neither was waiting for the signal nor had a signal
- * handler attached to the signal, then the default action is
- * simply to ignore the signal
- */
+ irqrestore(saved_state);
+
+ /* If the task neither was waiting for the signal nor had a signal
+ * handler attached to the signal, then the default action is
+ * simply to ignore the signal
+ */
- /****************** OTHER SIGNAL HANDLING ******************/
+ /*********************** OTHER SIGNAL HANDLING ***********************/
- /* If the task is blocked waiting for a semaphore, then that
- * task must be unblocked when a signal is received.
- */
+ /* If the task is blocked waiting for a semaphore, then that task must
+ * be unblocked when a signal is received.
+ */
- if (stcb->task_state == TSTATE_WAIT_SEM)
- {
- sem_waitirq(stcb, EINTR);
- }
+ if (stcb->task_state == TSTATE_WAIT_SEM)
+ {
+ sem_waitirq(stcb, EINTR);
+ }
- /* If the task is blocked waiting on a message queue, then that
- * task must be unblocked when a signal is received.
- */
+ /* If the task is blocked waiting on a message queue, then that task
+ * must be unblocked when a signal is received.
+ */
#ifndef CONFIG_DISABLE_MQUEUE
- if (stcb->task_state == TSTATE_WAIT_MQNOTEMPTY ||
- stcb->task_state == TSTATE_WAIT_MQNOTFULL)
- {
- mq_waitirq(stcb, EINTR);
- }
+ if (stcb->task_state == TSTATE_WAIT_MQNOTEMPTY ||
+ stcb->task_state == TSTATE_WAIT_MQNOTFULL)
+ {
+ mq_waitirq(stcb, EINTR);
+ }
#endif
- }
- }
+ }
return ret;
}
+
+/****************************************************************************
+ * Name: sig_dispatch
+ *
+ * Description:
+ * This is the front-end for sig_tcbdispatch that should be typically
+ * be used to dispatch a signal. If HAVE_GROUP_MEMBERS is defined,
+ * then function will follow the group signal delivery algorthrims:
+ *
+ * This front-end does the following things before calling
+ * sig_tcbdispatch.
+ *
+ * With HAVE_GROUP_MEMBERS defined:
+ * - Get the TCB associated with the pid.
+ * - If the TCB was found, get the group from the TCB.
+ * - If the PID has already exited, lookup the group that that was
+ * started by this task.
+ * - Use the group to pick the TCB to receive the signal
+ * - Call sig_tcbdispatch with the TCB
+ *
+ * With HAVE_GROUP_MEMBERS *not* defined
+ * - Get the TCB associated with the pid.
+ * - Call sig_tcbdispatch with the TCB
+ *
+ * Returned Value:
+ * Returns 0 (OK) on success or a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int sig_dispatch(pid_t pid, FAR siginfo_t *info)
+{
+#ifdef HAVE_GROUP_MEMBERS
+
+ FAR struct tcb_s *stcb;
+ FAR struct task_group_s *group;
+
+ /* Get the TCB associated with the pid */
+
+ stcb = sched_gettcb(pid);
+ if (stcb)
+ {
+ /* The task/thread associated with this PID is still active. Get its
+ * task group.
+ */
+
+ group = stcb->group;
+ }
+ else
+ {
+ /* The task/thread associated with this PID has exited. In the normal
+ * usage model, the PID should correspond to the PID of the task that
+ * created the task group. Try looking it up.
+ */
+
+ group = group_findbypid(pid);
+ }
+
+ /* Did we locate the group? */
+
+ if (group)
+ {
+ /* Yes.. call group_signal() to send the signal to the correct group
+ * member.
+ */
+
+ return group_signal(group, info);
+ }
+ else
+ {
+ return -ESRCH;
+ }
+
+#else
+
+ FAR struct tcb_s *stcb;
+
+ /* Get the TCB associated with the pid */
+
+ stcb = sched_gettcb(pid);
+ if (!stcb)
+ {
+ return -ESRCH;
+ }
+
+ return sig_tcbdispatch(stcb, info);
+
+#endif
+}
+
diff --git a/nuttx/sched/sig_internal.h b/nuttx/sched/sig_internal.h
index f9c672278..178ff54b9 100644
--- a/nuttx/sched/sig_internal.h
+++ b/nuttx/sched/sig_internal.h
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/sig_internal.h
*
- * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2009, 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -169,10 +169,19 @@ void sig_releaseaction(FAR sigactq_t *sigact);
sigset_t sig_pendingset(FAR struct tcb_s *stcb);
+/* sig_dispatch.c */
+
+int sig_tcbdispatch(FAR struct tcb_s *stcb, FAR siginfo_t *info);
+int sig_dispatch(pid_t pid, FAR siginfo_t *info);
+
+/* sig_cleanup.c */
+
+void sig_cleanup(FAR struct tcb_s *stcb);
+void sig_release(FAR struct task_group_s *group);
+
/* In files of the same name */
FAR sigq_t *sig_allocatependingsigaction(void);
-void sig_cleanup(FAR struct tcb_s *stcb);
void sig_deliver(FAR struct tcb_s *stcb);
FAR sigactq_t *sig_findaction(FAR struct tcb_s *stcb, int signo);
int sig_lowest(FAR sigset_t *set);
@@ -181,7 +190,6 @@ int sig_mqnotempty(int tid, int signo, union sigval value);
#else
int sig_mqnotempty(int tid, int signo, FAR void *sival_ptr);
#endif
-int sig_received(FAR struct tcb_s *stcb, FAR siginfo_t *info);
void sig_releasependingsigaction(FAR sigq_t *sigq);
void sig_releasependingsignal(FAR sigpendq_t *sigpend);
FAR sigpendq_t *sig_removependingsignal(FAR struct tcb_s *stcb, int signo);
diff --git a/nuttx/sched/sig_kill.c b/nuttx/sched/sig_kill.c
index e9d2d7d5d..90ac918f3 100644
--- a/nuttx/sched/sig_kill.c
+++ b/nuttx/sched/sig_kill.c
@@ -1,7 +1,7 @@
/************************************************************************
* sched/sig_kill.c
*
- * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2009, 2011, 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -87,41 +87,29 @@ int kill(pid_t pid, int signo)
#ifdef CONFIG_SCHED_HAVE_PARENT
FAR struct tcb_s *rtcb = (FAR struct tcb_s *)g_readytorun.head;
#endif
- FAR struct tcb_s *stcb;
siginfo_t info;
- int ret = ERROR;
+ int ret;
/* We do not support sending signals to process groups */
if (pid <= 0)
{
- errno = ENOSYS;
- return ERROR;
+ ret = -ENOSYS;
+ goto errout;
}
/* Make sure that the signal is valid */
if (!GOOD_SIGNO(signo))
{
- errno = EINVAL;
- return ERROR;
+ ret = -EINVAL;
+ goto errout;
}
/* Keep things stationary through the following */
sched_lock();
- /* Get the TCB of the receiving task */
-
- stcb = sched_gettcb(pid);
- sdbg("TCB=0x%08x signo=%d\n", stcb, signo);
- if (!stcb)
- {
- errno = ESRCH;
- sched_unlock();
- return ERROR;
- }
-
/* Create the siginfo structure */
info.si_signo = signo;
@@ -134,9 +122,19 @@ int kill(pid_t pid, int signo)
/* Send the signal */
- ret = sig_received(stcb, &info);
+ ret = sig_dispatch(pid, &info);
sched_unlock();
- return ret;
+
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ return OK;
+
+errout:
+ set_errno(-ret);
+ return ERROR;
}
diff --git a/nuttx/sched/sig_mqnotempty.c b/nuttx/sched/sig_mqnotempty.c
index 6eb434813..54ea2f9aa 100644
--- a/nuttx/sched/sig_mqnotempty.c
+++ b/nuttx/sched/sig_mqnotempty.c
@@ -42,6 +42,7 @@
#include <signal.h>
#include <sched.h>
+#include <errno.h>
#include <debug.h>
#include "os_internal.h"
@@ -83,30 +84,30 @@
****************************************************************************/
#ifdef CONFIG_CAN_PASS_STRUCTS
-int sig_mqnotempty (int pid, int signo, union sigval value)
+int sig_mqnotempty(int pid, int signo, union sigval value)
#else
-int sig_mqnotempty (int pid, int signo, void *sival_ptr)
+int sig_mqnotempty(int pid, int signo, void *sival_ptr)
#endif
{
#ifdef CONFIG_SCHED_HAVE_PARENT
FAR struct tcb_s *rtcb = (FAR struct tcb_s *)g_readytorun.head;
#endif
- FAR struct tcb_s *stcb;
siginfo_t info;
- int ret = ERROR;
-
- sched_lock();
-
- /* Get the TCB of the receiving task */
-
- stcb = sched_gettcb(pid);
+ int ret;
#ifdef CONFIG_CAN_PASS_STRUCTS
- sdbg("TCB=%p signo=%d value=%d\n", stcb, signo, value.sival_int);
+ sdbg("pid=%p signo=%d value=%d\n", pid, signo, value.sival_int);
#else
- sdbg("TCB=%p signo=%d sival_ptr=%p\n", stcb, signo, sival_ptr);
+ sdbg("pid=%p signo=%d sival_ptr=%p\n", pid, signo, sival_ptr);
#endif
+ /* Verify that we can perform the signalling operation */
+
+ if (GOOD_SIGNO(signo))
+ {
+ return -EINVAL;
+ }
+
/* Create the siginfo structure */
info.si_signo = signo;
@@ -121,15 +122,11 @@ int sig_mqnotempty (int pid, int signo, void *sival_ptr)
info.si_status = OK;
#endif
- /* Verify that we can perform the signalling operation */
-
- if ((stcb) && (GOOD_SIGNO(signo)))
- {
- /* Process the receipt of the signal */
-
- ret = sig_received(stcb, &info);
- }
+ /* Process the receipt of the signal */
+ sched_lock();
+ ret = sig_dispatch(pid, &info);
sched_unlock();
+
return ret;
}
diff --git a/nuttx/sched/sig_pending.c b/nuttx/sched/sig_pending.c
index d6f72cd99..8d39f19a4 100644
--- a/nuttx/sched/sig_pending.c
+++ b/nuttx/sched/sig_pending.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/sig_pending.c
*
- * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2009, 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -111,14 +111,17 @@ int sigpending(FAR sigset_t *set)
sigset_t sig_pendingset(FAR struct tcb_s *stcb)
{
+ FAR struct task_group_s *group = stcb->group;
sigset_t sigpendset;
FAR sigpendq_t *sigpend;
irqstate_t saved_state;
+ DEBUGASSERT(group);
+
sigpendset = NULL_SIGNAL_SET;
saved_state = irqsave();
- for (sigpend = (FAR sigpendq_t*)stcb->sigpendingq.head;
+ for (sigpend = (FAR sigpendq_t*)group->sigpendingq.head;
(sigpend); sigpend = sigpend->flink)
{
sigaddset(&sigpendset, sigpend->info.si_signo);
diff --git a/nuttx/sched/sig_queue.c b/nuttx/sched/sig_queue.c
index 6dca15704..8174fe1fa 100644
--- a/nuttx/sched/sig_queue.c
+++ b/nuttx/sched/sig_queue.c
@@ -114,33 +114,21 @@ int sigqueue(int pid, int signo, void *sival_ptr)
#ifdef CONFIG_SCHED_HAVE_PARENT
FAR struct tcb_s *rtcb = (FAR struct tcb_s *)g_readytorun.head;
#endif
- FAR struct tcb_s *stcb;
siginfo_t info;
- int ret = ERROR;
+ int ret;
- /* Sanity checks */
-
- if (!GOOD_SIGNO(signo))
- {
- set_errno(EINVAL);
- return ERROR;
- }
-
- sched_lock();
-
- /* Get the TCB of the receiving task */
-
- stcb = sched_gettcb(pid);
#ifdef CONFIG_CAN_PASS_STRUCTS
- sdbg("TCB=0x%08x signo=%d value=%d\n", stcb, signo, value.sival_int);
+ sdbg("pid=0x%08x signo=%d value=%d\n", pid, signo, value.sival_int);
#else
- sdbg("TCB=0x%08x signo=%d value=%p\n", stcb, signo, sival_ptr);
+ sdbg("pid=0x%08x signo=%d value=%p\n", pid, signo, sival_ptr);
#endif
- if (pid == 0 || !stcb)
+
+ /* Sanity checks */
+
+ if (!GOOD_SIGNO(signo))
{
- set_errno(ESRCH);
- sched_unlock();
- return ERROR;
+ ret = -EINVAL;
+ goto errout;
}
/* Create the siginfo structure */
@@ -159,8 +147,21 @@ int sigqueue(int pid, int signo, void *sival_ptr)
/* Send the signal */
- ret = sig_received(stcb, &info);
+ sched_lock();
+ ret = sig_dispatch(pid, &info);
sched_unlock();
- return ret;
+
+ /* Check for errors */
+
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ return OK;
+
+errout:
+ set_errno(-ret);
+ return ERROR;
}
diff --git a/nuttx/sched/sig_removependingsignal.c b/nuttx/sched/sig_removependingsignal.c
index d1f2995e8..9e9711b09 100644
--- a/nuttx/sched/sig_removependingsignal.c
+++ b/nuttx/sched/sig_removependingsignal.c
@@ -1,7 +1,7 @@
/************************************************************************
* sched/sig_removependingsignal.c
*
- * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2009, 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -87,13 +87,16 @@
FAR sigpendq_t *sig_removependingsignal(FAR struct tcb_s *stcb, int signo)
{
+ FAR struct task_group_s *group = stcb->group;
FAR sigpendq_t *currsig;
FAR sigpendq_t *prevsig;
irqstate_t saved_state;
+ DEBUGASSERT(group);
+
saved_state = irqsave();
- for (prevsig = NULL, currsig = (FAR sigpendq_t*)stcb->sigpendingq.head;
+ for (prevsig = NULL, currsig = (FAR sigpendq_t*)group->sigpendingq.head;
(currsig && currsig->info.si_signo != signo);
prevsig = currsig, currsig = currsig->flink);
@@ -101,11 +104,11 @@ FAR sigpendq_t *sig_removependingsignal(FAR struct tcb_s *stcb, int signo)
{
if (prevsig)
{
- sq_remafter((FAR sq_entry_t*)prevsig, &stcb->sigpendingq);
+ sq_remafter((FAR sq_entry_t*)prevsig, &group->sigpendingq);
}
else
{
- sq_remfirst(&stcb->sigpendingq);
+ sq_remfirst(&group->sigpendingq);
}
}
diff --git a/nuttx/sched/sig_unmaskpendingsignal.c b/nuttx/sched/sig_unmaskpendingsignal.c
index c4d80de17..c9326e306 100644
--- a/nuttx/sched/sig_unmaskpendingsignal.c
+++ b/nuttx/sched/sig_unmaskpendingsignal.c
@@ -122,9 +122,14 @@ void sig_unmaskpendingsignal(void)
if ((pendingsig = sig_removependingsignal(rtcb, signo)) != NULL)
{
- /* If there is one, then process it like a normal signal */
-
- sig_received(rtcb, &pendingsig->info);
+ /* If there is one, then process it like a normal signal.
+ * Since the signal was pending, then unblocked on this
+ * thread, we can skip the normal group signal dispatching
+ * rules; there can be no other recipient for the signal
+ * other than this thread.
+ */
+
+ sig_tcbdispatch(rtcb, &pendingsig->info);
/* Then remove it from the pending signal list */
diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c
index 688c25c44..444bfee9c 100644
--- a/nuttx/sched/task_exithook.c
+++ b/nuttx/sched/task_exithook.c
@@ -51,6 +51,7 @@
#include "os_internal.h"
#include "group_internal.h"
#include "sig_internal.h"
+#include "mq_internal.h"
/****************************************************************************
* Definitions
@@ -302,7 +303,7 @@ static inline void task_sigchild(gid_t pgid, FAR struct tcb_s *ctcb, int status)
* this case, the child task group has been orphaned.
*/
- pgrp = group_find(chgrp->tg_pgid);
+ pgrp = group_findbygid(pgid);
if (!pgrp)
{
/* Set the task group ID to an invalid group ID. The dead parent
@@ -350,9 +351,7 @@ static inline void task_sigchild(gid_t pgid, FAR struct tcb_s *ctcb, int status)
#endif
info.si_status = status;
- /* Send the signal. We need to use this internal interface so that we
- * can provide the correct si_code value with the signal.
- */
+ /* Send the signal to one thread in the group */
(void)group_signal(pgrp, &info);
}
@@ -407,7 +406,7 @@ static inline void task_sigchild(FAR struct tcb_s *ptcb,
* can provide the correct si_code value with the signal.
*/
- (void)sig_received(ptcb, &info);
+ (void)sig_tcbdispatch(ptcb, &info);
}
}
@@ -592,6 +591,14 @@ void task_exithook(FAR struct tcb_s *tcb, int status)
task_onexit(tcb, status);
+ /* If the task was terminated by another task, it may be in an unknown
+ * state. Make some feed effort to recover the state.
+ */
+
+#ifndef CONFIG_DISABLE_MQUEUE
+ mq_recover(tcb);
+#endif
+
/* Leave the task group */
task_leavegroup(tcb, status);
diff --git a/nuttx/sched/task_reparent.c b/nuttx/sched/task_reparent.c
index f32d011e9..e47fbfee5 100644
--- a/nuttx/sched/task_reparent.c
+++ b/nuttx/sched/task_reparent.c
@@ -109,7 +109,7 @@ int task_reparent(pid_t ppid, pid_t chpid)
/* Get the old parent task's task group (ogrp) */
- ogrp = group_find(ogid);
+ ogrp = group_findbygid(ogid);
if (!ogrp)
{
ret = -ESRCH;
@@ -126,7 +126,7 @@ int task_reparent(pid_t ppid, pid_t chpid)
/* Get the grandparent task's task group (pgrp) */
pgid = ogrp->tg_pgid;
- pgrp = group_find(pgid);
+ pgrp = group_findbygid(pgid);
}
else
{
diff --git a/nuttx/sched/task_setup.c b/nuttx/sched/task_setup.c
index a7b634dd7..cbc3582a5 100644
--- a/nuttx/sched/task_setup.c
+++ b/nuttx/sched/task_setup.c
@@ -458,13 +458,13 @@ int task_schedsetup(FAR struct task_tcb_s *tcb, int priority, start_t start,
****************************************************************************/
#ifndef CONFIG_DISABLE_PTHREAD
-int pthread_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start,
+int pthread_schedsetup(FAR struct pthread_tcb_s *tcb, int priority, start_t start,
pthread_startroutine_t entry)
{
/* Perform common thread setup */
- return thread_schedsetup(tcb, priority, start, (FAR void *)entry,
- TCB_FLAG_TTYPE_PTHREAD);
+ return thread_schedsetup((FAR struct tcb_s *)tcb, priority, start,
+ (FAR void *)entry, TCB_FLAG_TTYPE_PTHREAD);
}
#endif
diff --git a/nuttx/sched/timer_settime.c b/nuttx/sched/timer_settime.c
index d588939ab..45fd17ded 100644
--- a/nuttx/sched/timer_settime.c
+++ b/nuttx/sched/timer_settime.c
@@ -1,7 +1,7 @@
/********************************************************************************
* sched/timer_settime.c
*
- * Copyright (C) 2007-2010 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2010, 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -95,33 +95,25 @@ static void timer_timeout(int argc, uint32_t itimer);
static void inline timer_sigqueue(FAR struct posix_timer_s *timer)
{
- FAR struct tcb_s *tcb;
+ siginfo_t info;
- /* Get the TCB of the receiving task */
+ /* Create the siginfo structure */
- tcb = sched_gettcb(timer->pt_owner);
- if (tcb)
- {
- siginfo_t info;
-
- /* Create the siginfo structure */
-
- info.si_signo = timer->pt_signo;
- info.si_code = SI_TIMER;
+ info.si_signo = timer->pt_signo;
+ info.si_code = SI_TIMER;
#ifdef CONFIG_CAN_PASS_STRUCTS
- info.si_value = timer->pt_value;
+ info.si_value = timer->pt_value;
#else
- info.si_value.sival_ptr = timer->pt_value.sival_ptr;
+ info.si_value.sival_ptr = timer->pt_value.sival_ptr;
#endif
#ifdef CONFIG_SCHED_HAVE_PARENT
- info.si_pid = 0; /* Not applicable */
- info.si_status = OK;
+ info.si_pid = 0; /* Not applicable */
+ info.si_status = OK;
#endif
- /* Send the signal */
+ /* Send the signal */
- (void)sig_received(tcb, &info);
- }
+ (void)sig_dispatch(timer->pt_owner, &info);
}
/********************************************************************************