mirror of
https://github.com/apache/nuttx.git
synced 2026-05-25 18:27:56 +08:00
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
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -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/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
+15
-6
@@ -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 */
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
+49
-3
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+69
-60
@@ -70,6 +70,75 @@
|
||||
* Private Functions
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* 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 */
|
||||
|
||||
+75
-62
@@ -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 */
|
||||
|
||||
@@ -216,6 +223,74 @@ static inline void group_release(FAR struct task_group_s *group)
|
||||
sched_free(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 */
|
||||
|
||||
+129
-47
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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--;
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@@ -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,
|
||||
|
||||
+24
-8
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+11
-3
@@ -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);
|
||||
|
||||
+18
-20
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+17
-20
@@ -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;
|
||||
}
|
||||
|
||||
+5
-2
@@ -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);
|
||||
|
||||
+24
-23
@@ -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;
|
||||
|
||||
#ifdef CONFIG_CAN_PASS_STRUCTS
|
||||
sdbg("pid=0x%08x signo=%d value=%d\n", pid, signo, value.sival_int);
|
||||
#else
|
||||
sdbg("pid=0x%08x signo=%d value=%p\n", pid, signo, sival_ptr);
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
#else
|
||||
sdbg("TCB=0x%08x signo=%d value=%p\n", stcb, signo, sival_ptr);
|
||||
#endif
|
||||
if (pid == 0 || !stcb)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
/* 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_received(rtcb, &pendingsig->info);
|
||||
sig_tcbdispatch(rtcb, &pendingsig->info);
|
||||
|
||||
/* Then remove it from the pending signal list */
|
||||
|
||||
|
||||
+12
-5
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
|
||||
+11
-19
@@ -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);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
|
||||
Reference in New Issue
Block a user