summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/examples/ostest/cond.c13
-rw-r--r--apps/examples/ostest/mqueue.c62
-rw-r--r--apps/examples/ostest/timedmqueue.c65
-rw-r--r--nuttx/Documentation/NuttxUserGuide.html59
-rw-r--r--nuttx/sched/group_find.c2
-rw-r--r--nuttx/sched/group_internal.h2
-rw-r--r--nuttx/sched/task_exithook.c2
7 files changed, 154 insertions, 51 deletions
diff --git a/apps/examples/ostest/cond.c b/apps/examples/ostest/cond.c
index 96468c3e4..35456efc1 100644
--- a/apps/examples/ostest/cond.c
+++ b/apps/examples/ostest/cond.c
@@ -1,7 +1,7 @@
/***********************************************************************
* cond.c
*
- * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2008, 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -97,6 +97,7 @@ static void *thread_waiter(void *parameter)
printf("waiter_thread: ERROR pthread_cond_wait failed, status=%d\n", status);
waiter_nerrors++;
}
+
waiter_waits++;
}
@@ -123,6 +124,7 @@ static void *thread_waiter(void *parameter)
waiter_nloops++;
}
+
return NULL;
}
@@ -288,7 +290,10 @@ void cond_test(void)
printf("cond_test: Loops\t%d\t%d\n", waiter_nloops, signaler_nloops);
printf("cond_test: Errors\t%d\t%d\n", waiter_nerrors, signaler_nerrors);
printf("cond_test:\n");
- printf("cond_test: %d times, waiter did not have to wait for data\n", waiter_nloops - waiter_waits);
- printf("cond_test: %d times, data was already available when the signaler run\n", signaler_already);
- printf("cond_test: %d times, the waiter was in an unexpected state when the signaler ran\n", signaler_state);
+ printf("cond_test: %d times, waiter did not have to wait for data\n",
+ waiter_nloops - waiter_waits);
+ printf("cond_test: %d times, data was already available when the signaler run\n",
+ signaler_already);
+ printf("cond_test: %d times, the waiter was in an unexpected state when the signaler ran\n",
+ signaler_state);
}
diff --git a/apps/examples/ostest/mqueue.c b/apps/examples/ostest/mqueue.c
index 54e84ca45..0bb3473dc 100644
--- a/apps/examples/ostest/mqueue.c
+++ b/apps/examples/ostest/mqueue.c
@@ -92,6 +92,7 @@
**************************************************************************/
static mqd_t g_send_mqfd;
+static mqd_t g_recv_mqfd;
/**************************************************************************
* Private Functions
@@ -128,7 +129,7 @@ static void *sender_thread(void *arg)
* already created it.
*/
- g_send_mqfd = mq_open("testmq", O_WRONLY|O_CREAT, 0666, &attr);
+ g_send_mqfd = mq_open("mqueue", O_WRONLY|O_CREAT, 0666, &attr);
if (g_send_mqfd < 0)
{
printf("sender_thread: ERROR mq_open failed\n");
@@ -161,6 +162,10 @@ static void *sender_thread(void *arg)
{
printf("sender_thread: ERROR mq_close failed\n");
}
+ else
+ {
+ g_send_mqfd = NULL;
+ }
printf("sender_thread: returning nerrors=%d\n", nerrors);
return (pthread_addr_t)nerrors;
@@ -168,7 +173,6 @@ static void *sender_thread(void *arg)
static void *receiver_thread(void *arg)
{
- mqd_t mqfd;
char msg_buffer[TEST_MSGLEN];
struct mq_attr attr;
int nbytes;
@@ -194,8 +198,8 @@ static void *receiver_thread(void *arg)
* already created it.
*/
- mqfd = mq_open("testmq", O_RDONLY|O_CREAT, 0666, &attr);
- if (mqfd < 0)
+ g_recv_mqfd = mq_open("mqueue", O_RDONLY|O_CREAT, 0666, &attr);
+ if (g_recv_mqfd < 0)
{
printf("receiver_thread: ERROR mq_open failed\n");
pthread_exit((pthread_addr_t)1);
@@ -206,7 +210,7 @@ static void *receiver_thread(void *arg)
for (i = 0; i < TEST_RECEIVE_NMSGS; i++)
{
memset(msg_buffer, 0xaa, TEST_MSGLEN);
- nbytes = mq_receive(mqfd, msg_buffer, TEST_MSGLEN, 0);
+ nbytes = mq_receive(g_recv_mqfd, msg_buffer, TEST_MSGLEN, 0);
if (nbytes < 0)
{
/* mq_receive failed. If the error is because of EINTR then
@@ -260,18 +264,14 @@ static void *receiver_thread(void *arg)
/* Close the queue and return success */
- if (mq_close(mqfd) < 0)
+ if (mq_close(g_recv_mqfd) < 0)
{
printf("receiver_thread: ERROR mq_close failed\n");
nerrors++;
}
-
- /* Destroy the queue */
-
- if (mq_unlink("testmq") < 0)
+ else
{
- printf("receiver_thread: ERROR mq_close failed\n");
- nerrors++;
+ g_recv_mqfd = NULL;
}
printf("receiver_thread: returning nerrors=%d\n", nerrors);
@@ -292,6 +292,11 @@ void mqueue_test(void)
int prio_mid;
int status;
+ /* Reset globals for the beginning of the test */
+
+ g_send_mqfd = NULL;
+ g_recv_mqfd = NULL;
+
/* Start the sending thread at higher priority */
printf("mqueue_test: Starting receiver\n");
@@ -410,9 +415,38 @@ void mqueue_test(void)
* message queue open.
*/
- if (mq_close(g_send_mqfd) < 0)
+ if (result == PTHREAD_CANCELED && g_send_mqfd)
{
- printf("sender_thread: ERROR mq_close failed\n");
+ if (mq_close(g_send_mqfd) < 0)
+ {
+ printf("mqueue_test: ERROR mq_close failed\n");
+ }
+ }
+ else if (result != PTHREAD_CANCELED && g_send_mqfd)
+ {
+ printf("mqueue_test: ERROR send mqd_t left open\n");
+ if (mq_close(g_send_mqfd) < 0)
+ {
+ printf("mqueue_test: ERROR mq_close failed\n");
+ }
+ }
+
+ /* Make sure that the receive queue is closed as well */
+
+ if (g_recv_mqfd)
+ {
+ printf("mqueue_test: ERROR receive mqd_t left open\n");
+ if (mq_close(g_recv_mqfd) < 0)
+ {
+ printf("sender_thread: ERROR mq_close failed\n");
+ }
+ }
+
+ /* Destroy the message queue */
+
+ if (mq_unlink("mqueue") < 0)
+ {
+ printf("mqueue_test: ERROR mq_unlink failed\n");
}
}
diff --git a/apps/examples/ostest/timedmqueue.c b/apps/examples/ostest/timedmqueue.c
index 6c3269e84..24dd0bc34 100644
--- a/apps/examples/ostest/timedmqueue.c
+++ b/apps/examples/ostest/timedmqueue.c
@@ -85,6 +85,9 @@
* Private Variables
**************************************************************************/
+static mqd_t g_send_mqfd;
+static mqd_t g_recv_mqfd;
+
/**************************************************************************
* Private Functions
**************************************************************************/
@@ -95,7 +98,6 @@
static void *sender_thread(void *arg)
{
- mqd_t mqfd;
char msg_buffer[TEST_MSGLEN];
struct mq_attr attr;
int status = 0;
@@ -121,8 +123,8 @@ 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("timedmq", 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);
@@ -148,7 +150,7 @@ static void *sender_thread(void *arg)
* one should fail with errno == ETIMEDOUT
*/
- status = mq_timedsend(mqfd, msg_buffer, TEST_MSGLEN, 42, &ts);
+ status = mq_timedsend(g_send_mqfd, msg_buffer, TEST_MSGLEN, 42, &ts);
if (status < 0)
{
if (i == TEST_SEND_NMSGS-1 && errno == ETIMEDOUT)
@@ -177,10 +179,14 @@ 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");
}
+ else
+ {
+ g_send_mqfd = NULL;
+ }
printf("sender_thread: returning nerrors=%d\n", nerrors);
FFLUSH();
@@ -189,7 +195,6 @@ static void *sender_thread(void *arg)
static void *receiver_thread(void *arg)
{
- mqd_t mqfd;
char msg_buffer[TEST_MSGLEN];
struct mq_attr attr;
int nbytes;
@@ -215,8 +220,8 @@ static void *receiver_thread(void *arg)
* already created it.
*/
- mqfd = mq_open("testmq", O_RDONLY|O_CREAT, 0666, &attr);
- if (mqfd < 0)
+ g_recv_mqfd = mq_open("timedmq", O_RDONLY|O_CREAT, 0666, &attr);
+ if (g_recv_mqfd < 0)
{
printf("receiver_thread: ERROR mq_open failed\n");
pthread_exit((pthread_addr_t)1);
@@ -239,7 +244,7 @@ static void *receiver_thread(void *arg)
*/
memset(msg_buffer, 0xaa, TEST_MSGLEN);
- nbytes = mq_timedreceive(mqfd, msg_buffer, TEST_MSGLEN, 0, &ts);
+ nbytes = mq_timedreceive(g_recv_mqfd, msg_buffer, TEST_MSGLEN, 0, &ts);
if (nbytes < 0)
{
if (i == TEST_SEND_NMSGS-1 && errno == ETIMEDOUT)
@@ -293,18 +298,14 @@ static void *receiver_thread(void *arg)
/* Close the queue and return success */
- if (mq_close(mqfd) < 0)
+ if (mq_close(g_recv_mqfd) < 0)
{
printf("receiver_thread: ERROR mq_close failed\n");
nerrors++;
}
-
- /* Destroy the queue */
-
- if (mq_unlink("testmq") < 0)
+ else
{
- printf("receiver_thread: ERROR mq_close failed\n");
- nerrors++;
+ g_recv_mqfd = NULL;
}
printf("receiver_thread: returning nerrors=%d\n", nerrors);
@@ -378,7 +379,37 @@ void timedmqueue_test(void)
pthread_join(receiver, &result);
if (result != (void*)0)
{
- printf("timedmqueue_test: ERROR receiver thread exited with %d errors\n", (int)result);
+ printf("timedmqueue_test: ERROR receiver thread exited with %d errors\n",
+ (int)result);
+ }
+
+ /* Make sure that the message queues were properly closed (otherwise, we
+ * might have problems the next time in the test loop.
+ */
+
+ if (g_send_mqfd)
+ {
+ printf("timedmqueue_test: ERROR send mqd_t left open\n");
+ if (mq_close(g_send_mqfd) < 0)
+ {
+ printf("timedmqueue_test: ERROR mq_close failed\n");
+ }
+ }
+
+ if (g_recv_mqfd)
+ {
+ printf("timedmqueue_test: ERROR receive mqd_t left open\n");
+ if (mq_close(g_recv_mqfd) < 0)
+ {
+ printf("timedmqueue_test: ERROR mq_close failed\n");
+ }
+ }
+
+ /* Destroy the message queue */
+
+ if (mq_unlink("timedmq") < 0)
+ {
+ printf("timedmqueue_test: ERROR mq_unlink failed\n");
}
printf("timedmqueue_test: Test complete\n");
diff --git a/nuttx/Documentation/NuttxUserGuide.html b/nuttx/Documentation/NuttxUserGuide.html
index 3aeb30788..34e6fe442 100644
--- a/nuttx/Documentation/NuttxUserGuide.html
+++ b/nuttx/Documentation/NuttxUserGuide.html
@@ -13,7 +13,7 @@
<h1><big><font color="#3c34ec"><i>NuttX Operating System<p>User's Manual</i></font></big></h1>
<p><small>by</small></p>
<p>Gregory Nutt<p>
- <p>Last Updated: February 4, 2013</p>
+ <p>Last Updated: February 5, 2013</p>
</td>
</tr>
</table>
@@ -4629,26 +4629,61 @@ interface of the same name.
</table>
<p>
- NuttX provides signal interfaces for tasks. Signals are used to
- alter the flow control of tasks by communicating asynchronous events
- within or between task contexts.
- Any task or interrupt handler can post (or send) a signal to a particular task.
- The task being signaled will execute task-specified signal handler
- function the next time that the task has priority.
- The signal handler is a user-supplied function that is bound to
- a specific signal and performs whatever actions are necessary
- whenever the signal is received.
+ <b>Tasks and Signals</b>.
+ NuttX provides signal interfaces for tasks and pthreads.
+ Signals are used toalter the flow control of tasks by communicating asynchronous events within or between task contexts.
+ Any task or interrupt handler can post (or send) a signal to a particular task using its task ID.
+ The task being signaled will execute task-specified signal handler function the next time that the task has priority.
+ The signal handler is a user-supplied function that is bound to a specific signal and performs whatever actions are necessary whenever the signal is received.
</p>
<p>
There are no predefined actions for any signal.
- The default action for all signals (i.e., when no signal handler has
- been supplied by the user) is to ignore the signal.
+ The default action for all signals (i.e., when no signal handler has been supplied by the user) is to ignore the signal.
In this sense, all NuttX are <i>real time</i> signals.
</p>
<p>
Tasks may also suspend themselves and wait until a signal is received.
</p>
<p>
+ <b>Tasks Groups</b>.
+ NuttX supports both tasks and pthreads.
+ The primary difference between tasks and pthreads is the tasks are much more independent.
+ Tasks can create pthreads and those pthreads will share the resources of the task.
+ The main task and its children pthreads together are referred as a "task group."
+ A task group is used in NuttX to emulate a POSIX <i>process</i>.
+</p>
+<p>
+ See the <a href="http://www.nuttx.org/doku.php?id=wiki:nxinternal:nxtasking">NuttX Threading Wiki</a> page and the <a href="http://www.nuttx.org/doku.php?id=wiki:nxinternal:tasksnthreads">Tasks vs. Threads FAQ</a> for additional information on tasks and threads in NuttX.
+</p>
+<p>
+ <b>Signalling Multi-threaded Task Groups</b>.
+ The behavior of signals in the multi-thread task group is complex.
+ NuttX emulates a process model with task groups and follows the POSIX rules for signalling behavior.
+ Normally when you signal the task group you would signal using the task ID of the main task that created the group (in practice, a different task should not know the IDs of the internal threads created within the task group); that ID is remembered by the task group (even if the main task thread exits).
+</p>
+<p>
+ Here are some of the things that should happen when you signal a multi-threaded task group:
+</p>
+<ul>
+ <li>
+ 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.
+ </li>
+ <li>
+ 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.
+ </li>
+</ul>
+<p>
+ You can mask out that signal using ''sigprocmask()'' (or ''pthread_sigmask()'').
+ That signal will then be effectively disabled and will never be received in those threads that have the signal masked.
+ On creation of a new thread, the new thread will inherit the signal mask of the parent thread that created it.
+ So you if block signal signals on one thread then create new threads, those signals will also be blocked in the new threads as well.
+</p>
+<p>
+ You can control which thread receives the signal by controlling the signal mask.
+ You should, for example, be able to create a separate thread whose sole purpose it is to catch a particular signal and respond to it. Simply block the thread in the main task; then the signal will be blocked in all of the pthreads in the group too. In the one "signal processing" pthread, enable the blocked signal. This thread will then be only thread that will receive the signal.
+</p>
+<p>
+ <b>Signal Interfaces</b>.
The following signal handling interfaces are provided by NuttX:
</p>
<ul>
diff --git a/nuttx/sched/group_find.c b/nuttx/sched/group_find.c
index d7e82d1f9..4c1205bea 100644
--- a/nuttx/sched/group_find.c
+++ b/nuttx/sched/group_find.c
@@ -145,7 +145,7 @@ FAR struct task_group_s *group_findbygid(gid_t gid)
*
*****************************************************************************/
-#if !defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_SCHED_HAVE_PARENT)
+#ifdef HAVE_GROUP_MEMBERS
FAR struct task_group_s *group_findbypid(pid_t pid)
{
FAR struct task_group_s *group;
diff --git a/nuttx/sched/group_internal.h b/nuttx/sched/group_internal.h
index 520a9544b..f97f07d95 100644
--- a/nuttx/sched/group_internal.h
+++ b/nuttx/sched/group_internal.h
@@ -86,8 +86,6 @@ void group_leave(FAR struct tcb_s *tcb);
#ifdef HAVE_GROUP_MEMBERS
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
diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c
index 444bfee9c..5633786aa 100644
--- a/nuttx/sched/task_exithook.c
+++ b/nuttx/sched/task_exithook.c
@@ -396,7 +396,7 @@ static inline void task_sigchild(FAR struct tcb_s *ptcb,
info.si_code = CLD_EXITED;
info.si_value.sival_ptr = NULL;
#ifndef CONFIG_DISABLE_PTHREAD
- info.si_pid = chgrp->tg_task;
+ info.si_pid = ctcb->group->tg_task;
#else
info.si_pid = ctcb->pid;
#endif