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:
parent
126e46a1e7
commit
bbf990f417
@ -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.
|
||||
|
||||
|
46
TODO
46
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/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
}
|
||||
|
117
sched/mq_recover.c
Normal file
117
sched/mq_recover.c
Normal file
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
DEBUGASSERT(stcb && info);
|
||||
|
||||
/************************* MASKED SIGNAL HANDLING ************************/
|
||||
|
||||
/* 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))
|
||||
{
|
||||
ret = OK;
|
||||
|
||||
/****************** 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 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);
|
||||
}
|
||||
|
||||
/* Its not one we are waiting for... Add it to the list of pending
|
||||
* signals.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
irqrestore(saved_state);
|
||||
if (!sig_addpendingsignal(stcb, info))
|
||||
{
|
||||
PANIC(OSERR_FAILEDTOADDSIGNAL);
|
||||
}
|
||||
}
|
||||
memcpy(&stcb->sigunbinfo, info, sizeof(siginfo_t));
|
||||
stcb->sigwaitmask = NULL_SIGNAL_SET;
|
||||
up_unblock_task(stcb);
|
||||
irqrestore(saved_state);
|
||||
}
|
||||
|
||||
/****************** UNMASKED SIGNAL HANDLING ******************/
|
||||
/* Its not one we are waiting for... Add it to the list of pending
|
||||
* signals.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Queue any sigaction's requested by this task. */
|
||||
|
||||
ret = sig_queueaction(stcb, info);
|
||||
|
||||
/* Then schedule execution of the signal handling action on
|
||||
* the recipients thread.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
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);
|
||||
if (!sig_addpendingsignal(stcb, info))
|
||||
{
|
||||
PANIC(OSERR_FAILEDTOADDSIGNAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
/************************ UNMASKED SIGNAL HANDLING ***********************/
|
||||
|
||||
/****************** OTHER SIGNAL HANDLING ******************/
|
||||
else
|
||||
{
|
||||
/* Queue any sigaction's requested by this task. */
|
||||
|
||||
/* If the task is blocked waiting for a semaphore, then that
|
||||
* task must be unblocked when a signal is received.
|
||||
*/
|
||||
ret = sig_queueaction(stcb, info);
|
||||
|
||||
if (stcb->task_state == TSTATE_WAIT_SEM)
|
||||
{
|
||||
sem_waitirq(stcb, EINTR);
|
||||
}
|
||||
/* Then schedule execution of the signal handling action on the
|
||||
* recipient's thread.
|
||||
*/
|
||||
|
||||
/* If the task is blocked waiting on a message queue, then that
|
||||
* task must be unblocked when a signal is received.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
/* 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 ***********************/
|
||||
|
||||
/* 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 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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
|
Loading…
Reference in New Issue
Block a user