summaryrefslogtreecommitdiff
path: root/nuttx/sched
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2013-01-12 19:58:45 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2013-01-12 19:58:45 +0000
commit499c8c86de6757b39eaaf0f2b96a5b070f085b9b (patch)
tree84c6da5c61268158365bdafe58f546b34a0b8a91 /nuttx/sched
parent5a180ec4940c993311eedddaa13194f9977968f1 (diff)
downloadpx4-nuttx-499c8c86de6757b39eaaf0f2b96a5b070f085b9b.tar.gz
px4-nuttx-499c8c86de6757b39eaaf0f2b96a5b070f085b9b.tar.bz2
px4-nuttx-499c8c86de6757b39eaaf0f2b96a5b070f085b9b.zip
Fix a *critical* bug in the task exit logic. Implements SIGCHILD
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5513 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/sched')
-rw-r--r--nuttx/sched/Kconfig69
-rw-r--r--nuttx/sched/sched_unlock.c1
-rw-r--r--nuttx/sched/sig_kill.c7
-rw-r--r--nuttx/sched/sig_mqnotempty.c7
-rw-r--r--nuttx/sched/sig_queue.c13
-rw-r--r--nuttx/sched/sig_timedwait.c4
-rw-r--r--nuttx/sched/task_deletecurrent.c16
-rw-r--r--nuttx/sched/task_exithook.c55
-rw-r--r--nuttx/sched/task_setup.c36
-rw-r--r--nuttx/sched/timer_settime.c4
10 files changed, 197 insertions, 15 deletions
diff --git a/nuttx/sched/Kconfig b/nuttx/sched/Kconfig
index bfaec3b5d..69621a1fa 100644
--- a/nuttx/sched/Kconfig
+++ b/nuttx/sched/Kconfig
@@ -38,6 +38,16 @@ config TASK_NAME_SIZE
Useful if scheduler instrumentation is selected. Set to zero to
disable.
+config SCHED_HAVE_PARENT
+ bool "Remember Parent"
+ default n
+ ---help---
+ Remember the ID of the parent thread when a new child thread is
+ created. This support enables a few minor features (such as
+ SIGCHLD) and slightly increases the size of the Task Control Block
+ (TCB) of every task to hold the ID of the parent thread. Default:
+ disabled.
+
config JULIAN_TIME
bool "Enables Julian time conversions"
default n
@@ -127,6 +137,7 @@ config SDCLONE_DISABLE
config SCHED_WORKQUEUE
bool "Enable worker thread"
default n
+ depends on !DISABLE_SIGNALS
---help---
Create a dedicated "worker" thread to handle delayed processing from interrupt
handlers. This feature is required for some drivers but, if there are no
@@ -158,14 +169,6 @@ config SCHED_WORKSTACKSIZE
---help---
The stack size allocated for the worker thread. Default: 2K.
-config SIG_SIGWORK
- int "Worker thread wakeup signal"
- default 4
- depends on SCHED_WORKQUEUE
- ---help---
- The signal number that will be used to wake-up the worker thread.
- Default: 4
-
config SCHED_LPWORK
bool "Enable a lower priority worker thread"
default n
@@ -310,6 +313,56 @@ config DISABLE_POLL
depends on DISABLE_OS_API
default n
+if !DISABLE_SIGNALS
+comment "Signal Numbers"
+
+config SIG_SIGUSR1
+ int "SIGUSR1"
+ default 1
+ ---help---
+ Value of standard user signal 1 (SIGUSR1). Default: 1
+
+config SIG_SIGUSR2
+ int "SIGUSR2"
+ default 2
+ ---help---
+ Value of standard user signal 2 (SIGUSR2). Default: 2
+
+config SIG_SIGALARM
+ int "SIGALRM"
+ default 3
+ ---help---
+ Default the signal number used with POSIX timers (SIGALRM).
+ Default: 3
+
+config SIG_SIGCHLD
+ int "SIGCHLD"
+ default 4
+ depends on SCHED_HAVE_PARENT
+ ---help---
+ The SIGCHLD signal is sent to the parent of a child process when it
+ exits, is interrupted (stopped), or resumes after being interrupted.
+ Default: 4
+
+config SIG_SIGCONDTIMEDOUT
+ int "SIGCONDTIMEDOUT"
+ default 16
+ depends on !DISABLE_PTHREAD
+ ---help---
+ This non-standard signal number is used the implementation of
+ pthread_cond_timedwait(). Default 16.
+
+config SIG_SIGWORK
+ int "SIGWORK"
+ default 17
+ depends on SCHED_WORKQUEUE
+ ---help---
+ SIGWORK is a non-standard signal used to wake up the internal NuttX
+ worker thread. This setting specifies the signal number that will be
+ used for SIGWORK. Default: 17
+
+endif
+
comment "Sizes of configurable things (0 disables)"
config MAX_TASKS
diff --git a/nuttx/sched/sched_unlock.c b/nuttx/sched/sched_unlock.c
index 9a52e8358..5eafcfc9e 100644
--- a/nuttx/sched/sched_unlock.c
+++ b/nuttx/sched/sched_unlock.c
@@ -126,5 +126,6 @@ int sched_unlock(void)
irqrestore(flags);
}
+
return OK;
}
diff --git a/nuttx/sched/sig_kill.c b/nuttx/sched/sig_kill.c
index 17921015f..b3d74d8a1 100644
--- a/nuttx/sched/sig_kill.c
+++ b/nuttx/sched/sig_kill.c
@@ -84,6 +84,9 @@
int kill(pid_t pid, int signo)
{
+#ifdef CONFIG_SCHED_HAVE_PARENT
+ FAR _TCB *rtcb = (FAR _TCB *)g_readytorun.head;
+#endif
FAR _TCB *stcb;
siginfo_t info;
int ret = ERROR;
@@ -124,6 +127,10 @@ int kill(pid_t pid, int signo)
info.si_signo = signo;
info.si_code = SI_USER;
info.si_value.sival_ptr = NULL;
+#ifdef CONFIG_SCHED_HAVE_PARENT
+ info.si_pid = rtcb->pid;
+ info.si_status = OK;
+#endif
/* Send the signal */
diff --git a/nuttx/sched/sig_mqnotempty.c b/nuttx/sched/sig_mqnotempty.c
index 9a1fd7243..f7ae6fd0d 100644
--- a/nuttx/sched/sig_mqnotempty.c
+++ b/nuttx/sched/sig_mqnotempty.c
@@ -88,6 +88,9 @@ int sig_mqnotempty (int pid, int signo, union sigval value)
int sig_mqnotempty (int pid, int signo, void *sival_ptr)
#endif
{
+#ifdef CONFIG_SCHED_HAVE_PARENT
+ FAR _TCB *rtcb = (FAR _TCB *)g_readytorun.head;
+#endif
FAR _TCB *stcb;
siginfo_t info;
int ret = ERROR;
@@ -113,6 +116,10 @@ int sig_mqnotempty (int pid, int signo, void *sival_ptr)
#else
info.si_value.sival_ptr = sival_ptr;
#endif
+#ifdef CONFIG_SCHED_HAVE_PARENT
+ info.si_pid = rtcb->pid;
+ info.si_status = OK;
+#endif
/* Verify that we can perform the signalling operation */
diff --git a/nuttx/sched/sig_queue.c b/nuttx/sched/sig_queue.c
index dee1c798a..db404238e 100644
--- a/nuttx/sched/sig_queue.c
+++ b/nuttx/sched/sig_queue.c
@@ -111,6 +111,9 @@ int sigqueue (int pid, int signo, union sigval value)
int sigqueue(int pid, int signo, void *sival_ptr)
#endif
{
+#ifdef CONFIG_SCHED_HAVE_PARENT
+ FAR _TCB *rtcb = (FAR _TCB *)g_readytorun.head;
+#endif
FAR _TCB *stcb;
siginfo_t info;
int ret = ERROR;
@@ -142,13 +145,17 @@ int sigqueue(int pid, int signo, void *sival_ptr)
/* Create the siginfo structure */
- info.si_signo = signo;
- info.si_code = SI_QUEUE;
+ info.si_signo = signo;
+ info.si_code = SI_QUEUE;
#ifdef CONFIG_CAN_PASS_STRUCTS
- info.si_value = value;
+ info.si_value = value;
#else
info.si_value.sival_ptr = sival_ptr;
#endif
+#ifdef CONFIG_SCHED_HAVE_PARENT
+ info.si_pid = rtcb->pid;
+ info.si_status = OK;
+#endif
/* Send the signal */
diff --git a/nuttx/sched/sig_timedwait.c b/nuttx/sched/sig_timedwait.c
index d7610cd49..b07b8f2a1 100644
--- a/nuttx/sched/sig_timedwait.c
+++ b/nuttx/sched/sig_timedwait.c
@@ -120,6 +120,10 @@ static void sig_timeout(int argc, uint32_t itcb)
u.wtcb->sigunbinfo.si_signo = SIG_WAIT_TIMEOUT;
u.wtcb->sigunbinfo.si_code = SI_TIMER;
u.wtcb->sigunbinfo.si_value.sival_int = 0;
+#ifdef CONFIG_SCHED_HAVE_PARENT
+ u.wtcb->sigunbinfo.si_pid = 0; /* Not applicable */
+ u.wtcb->sigunbinfo.si_status = OK;
+#endif
up_unblock_task(u.wtcb);
}
}
diff --git a/nuttx/sched/task_deletecurrent.c b/nuttx/sched/task_deletecurrent.c
index 77025f5e0..7ecfb26cc 100644
--- a/nuttx/sched/task_deletecurrent.c
+++ b/nuttx/sched/task_deletecurrent.c
@@ -90,6 +90,9 @@
* Return Value:
* OK on success; or ERROR on failure
*
+ * Assumeptions:
+ * Interrupts are disabled.
+ *
****************************************************************************/
int task_deletecurrent(void)
@@ -108,7 +111,7 @@ int task_deletecurrent(void)
(void)sched_removereadytorun(dtcb);
rtcb = (FAR _TCB*)g_readytorun.head;
- /* We are not in a bad state -- the head of the ready to run task list
+ /* We are now in a bad state -- the head of the ready to run task list
* does not correspond to the thread that is running. Disabling pre-
* emption on this TCB and marking the new ready-to-run task as not
* running (see, for example, get_errno_ptr()).
@@ -132,9 +135,16 @@ int task_deletecurrent(void)
(void)sched_mergepending();
}
- /* Now calling sched_unlock() should have no effect */
+ /* We can't use sched_unlock() to decrement the lock count because the
+ * sched_mergepending() call above might have changed the task at the
+ * head of the ready-to-run list. Furthermore, we should not need to
+ * perform the unlock action anyway because we know that the pending
+ * task list is empty. So all we really need to do is to decrement
+ * the lockcount on rctb.
+ */
- sched_unlock();
+ DEBUGASSERT(rtcb->lockcount > 0);
+ rtcb->lockcount--;
return OK;
}
diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c
index 3bde8fb7a..9ce2e5899 100644
--- a/nuttx/sched/task_exithook.c
+++ b/nuttx/sched/task_exithook.c
@@ -41,6 +41,7 @@
#include <stdlib.h>
#include <unistd.h>
+#include <signal.h>
#include <debug.h>
#include <errno.h>
@@ -188,6 +189,56 @@ static inline void task_onexit(FAR _TCB *tcb, int status)
#endif
/****************************************************************************
+ * Name: task_sigchild
+ *
+ * Description:
+ * Send the SIGCHILD signal to the parent thread
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_HAVE_PARENT
+static inline void task_sigchild(FAR _TCB *tcb, int status)
+{
+ FAR _TCB *ptcb;
+ siginfo_t info;
+
+ /* Keep things stationary through the following */
+
+ sched_lock();
+
+ /* Get the TCB of the receiving task */
+
+ ptcb = sched_gettcb(tcb->parent);
+ if (!ptcb)
+ {
+ /* The parent no longer exists... bail */
+
+ sched_unlock();
+ return;
+ }
+
+ /* Create the siginfo structure. We don't actually know the cause. That
+ * is a bug. Let's just say that the child task just exit-ted for now.
+ */
+
+ info.si_signo = SIGCHLD;
+ info.si_code = CLD_EXITED;
+ info.si_value.sival_ptr = NULL;
+ info.si_pid = tcb->pid;
+ 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.
+ */
+
+ (void)sig_received(ptcb, &info);
+ sched_unlock();
+}
+#else
+# define task_sigchild(tcb,status)
+#endif
+
+/****************************************************************************
* Name: task_exitwakeup
*
* Description:
@@ -259,6 +310,10 @@ void task_exithook(FAR _TCB *tcb, int status)
task_atexit(tcb);
+ /* Send SIGCHLD to the parent of the exiting task */
+
+ task_sigchild(tcb, status);
+
/* Call any registered on_exit function(s) */
task_onexit(tcb, status);
diff --git a/nuttx/sched/task_setup.c b/nuttx/sched/task_setup.c
index 8721b39ec..c5dd8ca3a 100644
--- a/nuttx/sched/task_setup.c
+++ b/nuttx/sched/task_setup.c
@@ -147,6 +147,34 @@ static int task_assignpid(FAR _TCB *tcb)
}
/****************************************************************************
+ * Name: task_saveparent
+ *
+ * Description:
+ * Save the task ID of the parent task in the child task's TCB.
+ *
+ * Parameters:
+ * tcb - The TCB of the new, child task.
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The parent of the new task is the task at the head of the ready-to-run
+ * list.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_HAVE_PARENT
+static inline void task_saveparent(FAR _TCB *tcb)
+{
+ FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head;
+ tcb->parent = rtcb->pid;
+}
+#else
+# define task_saveparent(tcb)
+#endif
+
+/****************************************************************************
* Name: task_dupdspace
*
* Description:
@@ -161,6 +189,8 @@ static int task_assignpid(FAR _TCB *tcb)
* None
*
* Assumptions:
+ * The parent of the new task is the task at the head of the ready-to-run
+ * list.
*
****************************************************************************/
@@ -231,6 +261,10 @@ int task_schedsetup(FAR _TCB *tcb, int priority, start_t start, main_t main)
tcb->start = start;
tcb->entry.main = main;
+ /* Save the task ID of the parent task in the TCB */
+
+ task_saveparent(tcb);
+
/* exec(), pthread_create(), task_create(), and vfork() all
* inherit the signal mask of the parent thread.
*/
@@ -243,7 +277,7 @@ int task_schedsetup(FAR _TCB *tcb, int priority, start_t start, main_t main)
* until it is activated.
*/
- tcb->task_state = TSTATE_TASK_INVALID;
+ tcb->task_state = TSTATE_TASK_INVALID;
/* Clone the parent tasks D-Space (if it was running PIC). This
* must be done before calling up_initial_state() so that the
diff --git a/nuttx/sched/timer_settime.c b/nuttx/sched/timer_settime.c
index 1814ba898..f09842ad4 100644
--- a/nuttx/sched/timer_settime.c
+++ b/nuttx/sched/timer_settime.c
@@ -113,6 +113,10 @@ static void inline timer_sigqueue(FAR struct posix_timer_s *timer)
#else
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;
+#endif
/* Send the signal */