summaryrefslogtreecommitdiff
path: root/nuttx/sched/group_signal.c
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/sched/group_signal.c
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/sched/group_signal.c')
-rw-r--r--nuttx/sched/group_signal.c176
1 files changed, 129 insertions, 47 deletions
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 */