1. SMP: Fix an assertion. SMP-specific change accidentally made in non-SMP code

2. Move list of signal actions from the task TCB to the task group.  Signal handlers are a property of the entire task group and not of individual threads in the group.  I know, I preferred it the other way too but this is more compliant with POSIX.
This commit is contained in:
Gregory Nutt 2016-02-18 08:34:11 -06:00
parent c4493528a1
commit 52fbbaf778
12 changed files with 157 additions and 40 deletions

View File

@ -11491,5 +11491,8 @@
your code still uses them, please switch to enter_critical_section() your code still uses them, please switch to enter_critical_section()
and leave_critical_section() (2016-02-14). and leave_critical_section() (2016-02-14).
* Also rename irqdisable() and irqenable() to up_irq_disable() and * Also rename irqdisable() and irqenable() to up_irq_disable() and
up_irq_enable (2016-02-14). up_irq_enable() (2016-02-14).
* sched/signal and include/nuttx/sched.h: Move the list of signal
actions from the TCB to the group structure. Signal handlers are not
per thread but, rather, per task group. I know, I preferred it the
other way too, but this is more compliant with POSIX (2016-02-18).

106
TODO
View File

@ -1,4 +1,4 @@
NuttX TODO List (Last updated February 8, 2016) NuttX TODO List (Last updated February 18, 2016)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This file summarizes known NuttX bugs, limitations, inconsistencies with This file summarizes known NuttX bugs, limitations, inconsistencies with
@ -25,7 +25,7 @@ nuttx/
(8) Graphics subsystem (graphics/) (8) Graphics subsystem (graphics/)
(1) Pascal add-on (pcode/) (1) Pascal add-on (pcode/)
(1) Build system / Toolchains (1) Build system / Toolchains
(3) Linux/Cywgin simulation (arch/sim) (4) Linux/Cywgin simulation (arch/sim)
(4) ARM (arch/arm/) (4) ARM (arch/arm/)
apps/ apps/
@ -1620,6 +1620,108 @@ o Linux/Cywgin simulation (arch/sim)
Status: Open Status: Open
Priority: Low Priority: Low
Title: SMP SIMULATION INCOMPLETE
Description: The configuration has basic support SMP testing. The simulation
supports the emulation of multiple CPUs by creating multiple
pthreads, each run a copy of the simulation in the same process
address space.
The simulation SMP implemention is incomplete, however. Two
critical SMP functions are not implemented:
- int up_cpu_pause(void)
- int up_cpu_resume(void)
These are used to start a new task on a different CPU: (1)
the other CPU is stopped or paused, (2) the OS datastructures
for that CPU are modified, then (2) the other CPU is resumed.
Unfortunately, I have not yet thought of a way to implement
them in the simulation.
Currently, for example, you can enable SMP for ostest
configuration by enabling:
-# CONFIG_EXPERIMENTAL is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_SPINLOCK=y
+CONFIG_SMP=y
+CONFIG_SMP_NCPUS=2
+CONFIG_SMP_IDLETHREAD_STACKSIZE=2048
And you can enable some additional debug output with:
-# CONFIG_DEBUG_SCHED is not set
+CONFIG_DEBUG_SCHED=y
-# CONFIG_SCHED_INSTRUMENTATION is not set
+CONFIG_SCHED_INSTRUMENTATION=y
The result should be as follows:
- CPU0 initializes and starts CPU1. CPU1 is running an
executing the IDLE task.
os_start: Entry
os_idletask: CPU1: Beginning Idle Loop
- CPU0 brings up the the OS test application on CPU0
os_do_appstart: Starting init thread
CPU0: Start init, TCB@42f490, state=5
up_unblock_task: Unblocking TCB=42f490
CPU0: Suspend CPU0 IDLE, TCB@42c180, state=4
CPU0: Resume init, TCB@42f490, state=0
up_unblock_task: New Active Task TCB=42f490
- OS test runs and performs some basic checks.
stdio_test: write fd=1
stdio_test: Standard I/O Check: printf
stdio_test: write fd=2
stdio_test: Standard I/O Check: fprintf to stderr
ostest_main: putenv(Variable1=BadValue3)
up_block_task: Blocking TCB=42f490
CPU0: Suspend init, TCB@42f490, state=4
CPU0: Resume CPU0 IDLE, TCB@42c180, state=3
up_block_task: New Active Task TCB=42c180
up_unblock_task: Unblocking TCB=42f490
CPU0: Suspend CPU0 IDLE, TCB@42c180, state=4
CPU0: Resume init, TCB@42f490, state=0
up_unblock_task: New Active Task TCB=42f490
ostest_main: setenv(Variable1, GoodValue1, TRUE)
ostest_main: setenv(Variable2, BadValue1, FALSE)
ostest_main: setenv(Variable2, GoodValue2, TRUE)
ostest_main: setenv(Variable3, Variable3, FALSE)
ostest_main: setenv(Variable3, Variable3, FALSE)
show_variable: Variable=Variable1 has value=GoodValue1
show_variable: Variable=Variable2 has value=GoodValue2
show_variable: Variable=Variable3 has value=GoodValue3
- Then OS test tries to start the task ostest on CPU1
CPU0: Start ostest, TCB@430e90, state=5
up_unblock_task: Unblocking TCB=430e90
CPU1: Suspend CPU1 IDLE, TCB@42c2c0, state=4
CPU0: Resume ostest, TCB@430e90, state=0
ostest_main: Started user_main at PID=4
There is no failure but, of course, the task on CPU1 does not
run, i.e., it does not replace the IDLE task running on CPU1.
2016-02-16: The NSH configuration can be forced to run, but
only if (1) You don't try to execute built-in commands or to
execute commands in the background. Those thoses cases, it
will try to start the command on CPU1 and the same problem
as for the ostest case occurs.
Also, for NSH you have to modify arch/sim/src/up_idle.c so
that the IDLE loop only runfs for CPU0. Otherwise, often
simuart_post() will be called from CPU1 and it will try to
restart NSH on CPU0 and, again, the same problem occurs.
o ARM (arch/arm/) o ARM (arch/arm/)
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^

View File

@ -445,7 +445,8 @@ struct task_group_s
#ifndef CONFIG_DISABLE_SIGNALS #ifndef CONFIG_DISABLE_SIGNALS
/* POSIX Signal Control Fields ************************************************/ /* POSIX Signal Control Fields ************************************************/
sq_queue_t sigpendingq; /* List of pending signals */ sq_queue_t tg_sigactionq; /* List of actions for signals */
sq_queue_t tg_sigpendingq; /* List of pending signals */
#endif #endif
#ifndef CONFIG_DISABLE_ENVIRON #ifndef CONFIG_DISABLE_ENVIRON
@ -599,7 +600,6 @@ struct tcb_s
#ifndef CONFIG_DISABLE_SIGNALS #ifndef CONFIG_DISABLE_SIGNALS
sigset_t sigprocmask; /* Signals that are blocked */ sigset_t sigprocmask; /* Signals that are blocked */
sigset_t sigwaitmask; /* Waiting for pending signals */ sigset_t sigwaitmask; /* Waiting for pending signals */
sq_queue_t sigactionq; /* List of actions for signals */
sq_queue_t sigpendactionq; /* List of pending signal actions */ sq_queue_t sigpendactionq; /* List of pending signal actions */
sq_queue_t sigpostedq; /* List of posted signals */ sq_queue_t sigpostedq; /* List of posted signals */
siginfo_t sigunbinfo; /* Signal info when task unblocked */ siginfo_t sigunbinfo; /* Signal info when task unblocked */

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* sched/group/group_signal.c * sched/group/group_signal.c
* *
* Copyright (C) 2013 Gregory Nutt. All rights reserved. * Copyright (C) 2013, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -89,6 +89,7 @@ struct group_signal_s
static int group_signal_handler(pid_t pid, FAR void *arg) static int group_signal_handler(pid_t pid, FAR void *arg)
{ {
FAR struct group_signal_s *info = (FAR struct group_signal_s *)arg; FAR struct group_signal_s *info = (FAR struct group_signal_s *)arg;
FAR struct task_group_s *group;
FAR struct tcb_s *tcb; FAR struct tcb_s *tcb;
FAR sigactq_t *sigact; FAR sigactq_t *sigact;
int ret; int ret;
@ -98,7 +99,7 @@ static int group_signal_handler(pid_t pid, FAR void *arg)
/* Get the TCB associated with the group member */ /* Get the TCB associated with the group member */
tcb = sched_gettcb(pid); tcb = sched_gettcb(pid);
DEBUGASSERT(tcb); DEBUGASSERT(tcb ! = NULL);
if (tcb) if (tcb)
{ {
/* Set this one as the default if we have not already set the default. */ /* Set this one as the default if we have not already set the default. */
@ -151,9 +152,12 @@ static int group_signal_handler(pid_t pid, FAR void *arg)
info->utcb = tcb; info->utcb = tcb;
} }
/* Is there also an action associated with the task? */ /* Is there also a action associated with the task group? */
sigact = sig_findaction(tcb, info->siginfo->si_signo); group = tcb->group;
DEBUGASSERT(group != NULL);
sigact = sig_findaction(group, info->siginfo->si_signo);
if (sigact) if (sigact)
{ {
/* Yes.. then use this thread. The requirement is this: /* Yes.. then use this thread. The requirement is this:

View File

@ -113,7 +113,7 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
* is now the new active task! * is now the new active task!
*/ */
ASSERT(!spin_islocked(&g_cpu_schedlock) && btcb->flink != NULL); DEBUGASSERT(rtcb->lockcount == 0 && btcb->flink != NULL);
btcb->task_state = TSTATE_TASK_RUNNING; btcb->task_state = TSTATE_TASK_RUNNING;
btcb->flink->task_state = TSTATE_TASK_READYTORUN; btcb->flink->task_state = TSTATE_TASK_READYTORUN;

View File

@ -156,12 +156,16 @@ static FAR sigactq_t *sig_allocateaction(void)
int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *oact) int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *oact)
{ {
FAR struct tcb_s *rtcb = this_task(); FAR struct tcb_s *rtcb = this_task();
FAR struct task_group_s *group;
FAR sigactq_t *sigact; FAR sigactq_t *sigact;
/* Since sigactions can only be installed from the running thread of /* Since sigactions can only be installed from the running thread of
* execution, no special precautions should be necessary. * execution, no special precautions should be necessary.
*/ */
DEBUGASSERT(rtcb != NULL && rtcb->group != NULL);
group = rtcb->group;
/* Verify the signal number */ /* Verify the signal number */
if (!GOOD_SIGNO(signo)) if (!GOOD_SIGNO(signo))
@ -170,9 +174,9 @@ int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *
return ERROR; return ERROR;
} }
/* Find the signal in the sigactionq */ /* Find the signal in the signal action queue */
sigact = sig_findaction(rtcb, signo); sigact = sig_findaction(group, signo);
/* Return the old sigaction value if so requested */ /* Return the old sigaction value if so requested */
@ -242,9 +246,9 @@ int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *
if (sigact) if (sigact)
{ {
/* Yes.. Remove it from sigactionq */ /* Yes.. Remove it from signal action queue */
sq_rem((FAR sq_entry_t *)sigact, &rtcb->sigactionq); sq_rem((FAR sq_entry_t *)sigact, &group->tg_sigactionq);
/* And deallocate it */ /* And deallocate it */
@ -278,9 +282,9 @@ int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *
sigact->signo = (uint8_t)signo; sigact->signo = (uint8_t)signo;
/* Add the new sigaction to sigactionq */ /* Add the new sigaction to signal action queue */
sq_addlast((FAR sq_entry_t *)sigact, &rtcb->sigactionq); sq_addlast((FAR sq_entry_t *)sigact, &group->tg_sigactionq);
} }
/* Set the new sigaction */ /* Set the new sigaction */

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* sched/signal/sig_cleanup.c * sched/signal/sig_cleanup.c
* *
* Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. * Copyright (C) 2007, 2009, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -58,16 +58,8 @@
void sig_cleanup(FAR struct tcb_s *stcb) void sig_cleanup(FAR struct tcb_s *stcb)
{ {
FAR sigactq_t *sigact;
FAR sigq_t *sigq; FAR sigq_t *sigq;
/* Deallocate all entries in the list of signal actions */
while ((sigact = (FAR sigactq_t *)sq_remfirst(&stcb->sigactionq)) != NULL)
{
sig_releaseaction(sigact);
}
/* Deallocate all entries in the list of pending signal actions */ /* Deallocate all entries in the list of pending signal actions */
while ((sigq = (FAR sigq_t *)sq_remfirst(&stcb->sigpendactionq)) != NULL) while ((sigq = (FAR sigq_t *)sq_remfirst(&stcb->sigpendactionq)) != NULL)
@ -101,11 +93,19 @@ void sig_cleanup(FAR struct tcb_s *stcb)
void sig_release(FAR struct task_group_s *group) void sig_release(FAR struct task_group_s *group)
{ {
FAR sigactq_t *sigact;
FAR sigpendq_t *sigpend; FAR sigpendq_t *sigpend;
/* Deallocate all entries in the list of signal actions */
while ((sigact = (FAR sigactq_t *)sq_remfirst(&group->tg_sigactionq)) != NULL)
{
sig_releaseaction(sigact);
}
/* Deallocate all entries in the list of pending signals */ /* Deallocate all entries in the list of pending signals */
while ((sigpend = (FAR sigpendq_t *)sq_remfirst(&group->sigpendingq)) != NULL) while ((sigpend = (FAR sigpendq_t *)sq_remfirst(&group->tg_sigpendingq)) != NULL)
{ {
sig_releasependingsignal(sigpend); sig_releasependingsignal(sigpend);
} }

View File

@ -72,6 +72,7 @@
static int sig_queueaction(FAR struct tcb_s *stcb, siginfo_t *info) static int sig_queueaction(FAR struct tcb_s *stcb, siginfo_t *info)
{ {
FAR struct task_group_s *group;
FAR sigactq_t *sigact; FAR sigactq_t *sigact;
FAR sigq_t *sigq; FAR sigq_t *sigq;
irqstate_t flags; irqstate_t flags;
@ -79,9 +80,12 @@ static int sig_queueaction(FAR struct tcb_s *stcb, siginfo_t *info)
sched_lock(); sched_lock();
/* Find the sigaction associated with this signal */ /* Find the group sigaction associated with this signal */
sigact = sig_findaction(stcb, info->si_signo); DEBUGASSERT(stcb != NULL && stcb->group != NULL);
group = stcb->group;
sigact = sig_findaction(group, info->si_signo);
/* Check if a valid signal handler is available and if the signal is /* Check if a valid signal handler is available and if the signal is
* unblocked. NOTE: There is no default action. * unblocked. NOTE: There is no default action.
@ -206,7 +210,7 @@ static FAR sigpendq_t *sig_findpendingsignal(FAR struct task_group_s *group,
/* Seach the list for a sigpendion on this signal */ /* Seach the list for a sigpendion on this signal */
for (sigpend = (FAR sigpendq_t *)group->sigpendingq.head; for (sigpend = (FAR sigpendq_t *)group->tg_sigpendingq.head;
(sigpend && sigpend->info.si_signo != signo); (sigpend && sigpend->info.si_signo != signo);
sigpend = sigpend->flink); sigpend = sigpend->flink);
@ -260,7 +264,7 @@ static FAR sigpendq_t *sig_addpendingsignal(FAR struct tcb_s *stcb,
/* Add the structure to the pending signal list */ /* Add the structure to the pending signal list */
flags = enter_critical_section(); flags = enter_critical_section();
sq_addlast((FAR sq_entry_t *)sigpend, &group->sigpendingq); sq_addlast((FAR sq_entry_t *)sigpend, &group->tg_sigpendingq);
leave_critical_section(flags); leave_critical_section(flags);
} }
} }

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* sched/signal/sig_findaction.c * sched/signal/sig_findaction.c
* *
* Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. * Copyright (C) 2007, 2009, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -52,13 +52,13 @@
* *
****************************************************************************/ ****************************************************************************/
FAR sigactq_t *sig_findaction(FAR struct tcb_s *stcb, int signo) FAR sigactq_t *sig_findaction(FAR struct task_group_s *group, int signo)
{ {
FAR sigactq_t *sigact = NULL; FAR sigactq_t *sigact = NULL;
/* Verify the caller's sanity */ /* Verify the caller's sanity */
if (stcb) if (group)
{ {
/* Sigactions can only be assigned to the currently executing /* Sigactions can only be assigned to the currently executing
* thread. So, a simple lock ought to give us sufficient * thread. So, a simple lock ought to give us sufficient
@ -69,7 +69,7 @@ FAR sigactq_t *sig_findaction(FAR struct tcb_s *stcb, int signo)
/* Seach the list for a sigaction on this signal */ /* Seach the list for a sigaction on this signal */
for (sigact = (FAR sigactq_t *)stcb->sigactionq.head; for (sigact = (FAR sigactq_t *)group->tg_sigactionq.head;
((sigact) && (sigact->signo != signo)); ((sigact) && (sigact->signo != signo));
sigact = sigact->flink); sigact = sigact->flink);

View File

@ -103,7 +103,7 @@ sigset_t sig_pendingset(FAR struct tcb_s *stcb)
sigpendset = NULL_SIGNAL_SET; sigpendset = NULL_SIGNAL_SET;
flags = enter_critical_section(); flags = enter_critical_section();
for (sigpend = (FAR sigpendq_t *)group->sigpendingq.head; for (sigpend = (FAR sigpendq_t *)group->tg_sigpendingq.head;
(sigpend); sigpend = sigpend->flink) (sigpend); sigpend = sigpend->flink)
{ {
sigaddset(&sigpendset, sigpend->info.si_signo); sigaddset(&sigpendset, sigpend->info.si_signo);

View File

@ -76,7 +76,7 @@ FAR sigpendq_t *sig_removependingsignal(FAR struct tcb_s *stcb, int signo)
flags = enter_critical_section(); flags = enter_critical_section();
for (prevsig = NULL, currsig = (FAR sigpendq_t *)group->sigpendingq.head; for (prevsig = NULL, currsig = (FAR sigpendq_t *)group->tg_sigpendingq.head;
(currsig && currsig->info.si_signo != signo); (currsig && currsig->info.si_signo != signo);
prevsig = currsig, currsig = currsig->flink); prevsig = currsig, currsig = currsig->flink);
@ -84,11 +84,11 @@ FAR sigpendq_t *sig_removependingsignal(FAR struct tcb_s *stcb, int signo)
{ {
if (prevsig) if (prevsig)
{ {
sq_remafter((FAR sq_entry_t *)prevsig, &group->sigpendingq); sq_remafter((FAR sq_entry_t *)prevsig, &group->tg_sigpendingq);
} }
else else
{ {
sq_remfirst(&group->sigpendingq); sq_remfirst(&group->tg_sigpendingq);
} }
} }

View File

@ -186,7 +186,7 @@ void sig_release(FAR struct task_group_s *group);
FAR sigq_t *sig_allocatependingsigaction(void); FAR sigq_t *sig_allocatependingsigaction(void);
void sig_deliver(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); FAR sigactq_t *sig_findaction(FAR struct task_group_s *group, int signo);
int sig_lowest(FAR sigset_t *set); int sig_lowest(FAR sigset_t *set);
#ifdef CONFIG_CAN_PASS_STRUCTS #ifdef CONFIG_CAN_PASS_STRUCTS
int sig_mqnotempty(int tid, int signo, union sigval value); int sig_mqnotempty(int tid, int signo, union sigval value);