9
0
Fork 0

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:
patacongo 2013-02-05 19:50:37 +00:00
parent 70121d6ca8
commit 0d9fb476ea
28 changed files with 948 additions and 497 deletions

View File

@ -91,6 +91,8 @@
* Private Variables
**************************************************************************/
static mqd_t g_send_mqfd;
/**************************************************************************
* Private Functions
**************************************************************************/
@ -101,7 +103,6 @@
static void *sender_thread(void *arg)
{
mqd_t mqfd;
char msg_buffer[TEST_MSGLEN];
struct mq_attr attr;
int status = 0;
@ -127,11 +128,11 @@ static void *sender_thread(void *arg)
* already created it.
*/
mqfd = mq_open("testmq", O_WRONLY|O_CREAT, 0666, &attr);
if (mqfd < 0)
g_send_mqfd = mq_open("testmq", O_WRONLY|O_CREAT, 0666, &attr);
if (g_send_mqfd < 0)
{
printf("sender_thread: ERROR mq_open failed\n");
pthread_exit((pthread_addr_t)1);
printf("sender_thread: ERROR mq_open failed\n");
pthread_exit((pthread_addr_t)1);
}
/* Fill in a test message buffer to send */
@ -142,7 +143,7 @@ static void *sender_thread(void *arg)
for (i = 0; i < TEST_SEND_NMSGS; i++)
{
status = mq_send(mqfd, msg_buffer, TEST_MSGLEN, 42);
status = mq_send(g_send_mqfd, msg_buffer, TEST_MSGLEN, 42);
if (status < 0)
{
printf("sender_thread: ERROR mq_send failure=%d on msg %d\n", status, i);
@ -156,7 +157,7 @@ static void *sender_thread(void *arg)
/* Close the queue and return success */
if (mq_close(mqfd) < 0)
if (mq_close(g_send_mqfd) < 0)
{
printf("sender_thread: ERROR mq_close failed\n");
}
@ -247,6 +248,7 @@ static void *receiver_thread(void *arg)
j, TEST_MESSAGE[j], TEST_MESSAGE[j], msg_buffer[j]);
}
}
printf("receiver_thread: %2d 00 %02x\n",
j, msg_buffer[j]);
}
@ -284,6 +286,7 @@ void mqueue_test(void)
void *result;
pthread_attr_t attr;
struct sched_param sparam;
FAR void *expected;
int prio_min;
int prio_max;
int prio_mid;
@ -378,16 +381,38 @@ void mqueue_test(void)
/* Then cancel the thread and see if it did */
printf("mqueue_test: Canceling receiver\n");
expected = PTHREAD_CANCELED;
status = pthread_cancel(receiver);
if (status == ESRCH)
{
printf("mqueue_test: receiver has already terminated\n");
expected = (FAR void *)0;
}
/* Check the result. If the pthread was canceled, PTHREAD_CANCELED is the
* correct result. Zero might be returned if the thread ran to completion
* before it was canceled.
*/
pthread_join(receiver, &result);
if (result != (void*)0)
if (result != expected)
{
printf("mqueue_test: ERROR receiver thread exited with %d errors\n", (int)result);
printf("mqueue_test: ERROR receiver thread should have exited with %d\n",
expected);
printf(" ERROR Instead exited with nerrors=%d\n",
(int)result);
}
/* Message queues are global resources and persist for the life the the
* task group. The message queue opened by the sender_thread must be closed
* since the sender pthread may have been canceled and may have left the
* message queue open.
*/
if (mq_close(g_send_mqfd) < 0)
{
printf("sender_thread: ERROR mq_close failed\n");
}
}

View File

@ -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.

View File

@ -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/)
^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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
nuttx/sched/mq_recover.c Normal file
View 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--;
}
}

View File

@ -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 */
}
/****************************************************************************

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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);

View File

@ -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
{

View File

@ -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

View File

@ -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);
}
/********************************************************************************