SMP: Initial implementation of up_cpu_pause and up_cpu_resume. Does not yet work.
This commit is contained in:
parent
e3ea40e4f9
commit
3deac3d43d
@ -70,6 +70,7 @@ ifeq ($(CONFIG_SPINLOCK),y)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SMP),y)
|
||||
CSRCS += up_smpsignal.c
|
||||
HOSTSRCS += up_simsmp.c
|
||||
endif
|
||||
|
||||
@ -124,7 +125,7 @@ endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SMP),y)
|
||||
HOSTCFLAGS += -DCONFIG_SMP=1
|
||||
HOSTCFLAGS += -DCONFIG_SMP=1 -DCONFIG_SMP_NCPUS=$(CONFIG_SMP_NCPUS)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_FS_HOSTFS),y)
|
||||
@ -179,6 +180,10 @@ ifeq ($(CONFIG_SIM_TOUCHSCREEN),y)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SMP),y)
|
||||
REQUIREDOBJS += up_smpsignal$(OBJEXT)
|
||||
endif
|
||||
|
||||
# Determine which NuttX libraries will need to be linked in
|
||||
# Most are provided by LINKLIBS on the MAKE command line
|
||||
|
||||
|
@ -29,14 +29,16 @@ nanosleep NXnanosleep
|
||||
poll NXpoll
|
||||
printf NXprintf
|
||||
pthread_create NXpthread_create
|
||||
pthread_yield NXpthread_yield
|
||||
pthread_getspecific NXpthread_getspecific
|
||||
pthread_key_create NXpthread_key_create
|
||||
pthread_kill NXpthread_kill
|
||||
pthread_mutex_destroy NXpthread_mutex_destroy
|
||||
pthread_mutex_init NXpthread_mutex_init
|
||||
pthread_mutex_lock NXpthread_mutex_lock
|
||||
pthread_mutex_unlock NXpthread_mutex_unlock
|
||||
pthread_mutex_destroy NXpthread_mutex_destroy
|
||||
pthread_key_create NXpthread_key_create
|
||||
pthread_setspecific NXpthread_setspecific
|
||||
pthread_getspecific NXpthread_getspecific
|
||||
pthread_sigmask NXpthread_sigmask
|
||||
pthread_yield NXpthread_yield
|
||||
puts NXputs
|
||||
read NXread
|
||||
readdir NXreaddir
|
||||
@ -53,6 +55,7 @@ sem_wait NXsem_wait
|
||||
send NXsend
|
||||
sendto NXsendto
|
||||
setsockopt NXsetsockopt
|
||||
sigaction NXsigaction
|
||||
sighold NXsighold
|
||||
sigprocmask NXsigprocmask
|
||||
sigrelse NXsigrelse
|
||||
|
@ -51,6 +51,7 @@
|
||||
# include <arch/irq.h>
|
||||
# ifdef CONFIG_SMP
|
||||
# include <nuttx/sched.h>
|
||||
# include <arch/spinlock.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@ -220,6 +221,13 @@ int sim_cpu0_initialize(void);
|
||||
int sim_cpustart(int cpu, main_t idletask);
|
||||
#endif
|
||||
|
||||
/* up_smpsignal.c *********************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void sim_cpupause(int cpu, FAR volatile spinlock_t *wait,
|
||||
FAR volatile unsigned char *paused);
|
||||
#endif
|
||||
|
||||
/* up_tickless.c **********************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
|
@ -40,10 +40,27 @@
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
/* Must match definitions in arch/sim/include/spinlock.h */
|
||||
|
||||
#define SP_UNLOCKED 0 /* The Un-locked state */
|
||||
#define SP_LOCKED 1 /* The Locked state */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
/* Must match definitions in arch/sim/include/spinlock.h. Assuming that
|
||||
* bool and unsigned char are equivalent.
|
||||
*/
|
||||
|
||||
typedef unsigned char spinlock_t;
|
||||
|
||||
/* Task entry point type */
|
||||
|
||||
typedef int (*main_t)(int argc, char **argv);
|
||||
|
||||
@ -58,7 +75,17 @@ struct sim_cpuinfo_s
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static pthread_key_t g_cpukey;
|
||||
static pthread_key_t g_cpukey;
|
||||
static pthread_t g_sim_cputhread[CONFIG_SMP_NCPUS];
|
||||
static volatile unsigned char g_sim_cpupaused[CONFIG_SMP_NCPUS];
|
||||
static volatile spinlock_t g_sim_cpuwait[CONFIG_SMP_NCPUS];
|
||||
|
||||
/****************************************************************************
|
||||
* NuttX domain function prototypes
|
||||
****************************************************************************/
|
||||
|
||||
void sim_cpupause(int cpu, volatile spinlock_t *wait,
|
||||
volatile unsigned char *paused);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -77,7 +104,7 @@ static pthread_key_t g_cpukey;
|
||||
* point.
|
||||
*
|
||||
* Input Parameters:
|
||||
* arg - Stanard pthread argument
|
||||
* arg - Standard pthread argument
|
||||
*
|
||||
* Returned Value:
|
||||
* This function does not return
|
||||
@ -87,6 +114,7 @@ static pthread_key_t g_cpukey;
|
||||
static void *sim_idle_trampoline(void *arg)
|
||||
{
|
||||
struct sim_cpuinfo_s *cpuinfo = (struct sim_cpuinfo_s *)arg;
|
||||
sigset_t set;
|
||||
int ret;
|
||||
|
||||
/* Set the CPU number zero for the CPU thread */
|
||||
@ -97,6 +125,17 @@ static void *sim_idle_trampoline(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make sure the SIGUSR1 is not masked */
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGUSR1);
|
||||
|
||||
ret = pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Let up_cpu_start() continue */
|
||||
|
||||
(void)pthread_mutex_unlock(&cpuinfo->mutex);
|
||||
@ -110,6 +149,30 @@ static void *sim_idle_trampoline(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_handle_signal
|
||||
*
|
||||
* Description:
|
||||
* This is the SIGUSR signal handler. It implements the core logic of
|
||||
* up_cpu_pause() on the thread of execution the simulated CPU.
|
||||
*
|
||||
* Input Parameters:
|
||||
* arg - Standard sigaction arguments
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sim_handle_signal(int signo, siginfo_t *info, void *context)
|
||||
{
|
||||
int cpu = (int)((uintptr_t)pthread_getspecific(g_cpukey));
|
||||
|
||||
/* We need to perform the actual tasking operations in the NuttX domain */
|
||||
|
||||
sim_cpupause(cpu, &g_sim_cpuwait[cpu], &g_sim_cpupaused[cpu]);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -132,6 +195,8 @@ static void *sim_idle_trampoline(void *arg)
|
||||
|
||||
int sim_cpu0_initialize(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
sigset_t set;
|
||||
int ret;
|
||||
|
||||
/* Create the pthread key */
|
||||
@ -150,6 +215,29 @@ int sim_cpu0_initialize(void)
|
||||
return -ret;
|
||||
}
|
||||
|
||||
/* Register the common signal handler for all threads */
|
||||
|
||||
act.sa_sigaction = sim_handle_signal;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&act.sa_mask);
|
||||
|
||||
ret = sigaction(SIGUSR1, &act, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Make sure the SIGUSR1 is not masked */
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGUSR1);
|
||||
|
||||
ret = sigprocmask(SIG_UNBLOCK, &set, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -206,7 +294,6 @@ int up_cpu_index(void)
|
||||
int up_cpu_start(int cpu, main_t idletask)
|
||||
{
|
||||
struct sim_cpuinfo_s cpuinfo;
|
||||
pthread_t thread;
|
||||
int ret;
|
||||
|
||||
/* Initialize the CPU info */
|
||||
@ -232,7 +319,7 @@ int up_cpu_start(int cpu, main_t idletask)
|
||||
* in a multi-CPU hardware model.
|
||||
*/
|
||||
|
||||
ret = pthread_create(&thread, NULL, sim_idle_trampoline, &cpuinfo);
|
||||
ret = pthread_create(&g_sim_cputhread[cpu], NULL, sim_idle_trampoline, &cpuinfo);
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = -ret; /* REVISIT: That is a host errno value. */
|
||||
@ -279,7 +366,21 @@ errout_with_mutex:
|
||||
|
||||
int up_cpu_pause(int cpu)
|
||||
{
|
||||
#warning Missing SMP logic
|
||||
/* Take the spinlock that will prevent the CPU thread from running */
|
||||
|
||||
g_sim_cpuwait[cpu] = SP_LOCKED;
|
||||
|
||||
/* Signal the CPU thread */
|
||||
|
||||
pthread_kill(g_sim_cputhread[cpu], SIGUSR1);
|
||||
|
||||
/* Spin, waiting for the thread to pause */
|
||||
|
||||
while (!g_sim_cpupaused[cpu])
|
||||
{
|
||||
pthread_yield();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -304,6 +405,8 @@ int up_cpu_pause(int cpu)
|
||||
|
||||
int up_cpu_resume(int cpu)
|
||||
{
|
||||
#warning Missing SMP logic
|
||||
/* Release the spinlock that will alloc the CPU thread to continue */
|
||||
|
||||
g_sim_cpuwait[cpu] = SP_UNLOCKED;
|
||||
return 0;
|
||||
}
|
||||
|
134
arch/sim/src/up_smpsignal.c
Normal file
134
arch/sim/src/up_smpsignal.c
Normal file
@ -0,0 +1,134 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/up_simsmp.c
|
||||
*
|
||||
* Copyright (C) 2016 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 <nuttx/sched.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "up_internal.h"
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_cpupause
|
||||
*
|
||||
* Description:
|
||||
* This is the SIGUSR1 signal handling logic. It implements the core
|
||||
* logic of up_cpu_pause() on the thread of execution the simulated CPU.
|
||||
* This is the part of the implementation that must be performed in the
|
||||
* NuttX vs. the host domain.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The CPU being paused.
|
||||
* wait - Spinlock to wait on to be un-paused
|
||||
* paused - A boolean to set when we are in the paused state.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void sim_cpupause(int cpu, volatile spinlock_t *wait,
|
||||
volatile unsigned char *paused)
|
||||
{
|
||||
struct tcb_s *rtcb = current_task(cpu);
|
||||
|
||||
sdbg("CPU%d: Blocking TCB=%p\n", cpu, rtcb);
|
||||
|
||||
/* Update scheduler parameters */
|
||||
|
||||
sched_suspend_scheduler(rtcb);
|
||||
|
||||
/* Copy the exception context into the TCB at the (old) head of the
|
||||
* CPUs assigned task list. if up_setjmp returns a non-zero value, then
|
||||
* this is really the previously running task restarting!
|
||||
*/
|
||||
|
||||
if (up_setjmp(rtcb->xcp.regs) == 0)
|
||||
{
|
||||
/* Indicate that we are in the paused state */
|
||||
|
||||
*paused = 1;
|
||||
|
||||
/* Spin until we are asked to resume. When we resume, we need to
|
||||
* inicate that we are not longer paused.
|
||||
*/
|
||||
|
||||
spin_lock(wait);
|
||||
*paused = 0;
|
||||
|
||||
/* While we were paused, logic on a different CPU probably changed
|
||||
* the task as that head of the assigned task list. So now we need
|
||||
* restore the exception context of the rtcb at the (new) head
|
||||
* of the assigned list in order to instantiate the new task.
|
||||
*/
|
||||
|
||||
rtcb = current_task(cpu);
|
||||
sdbg("CPU%d: New Active Task TCB=%p\n", cpu, rtcb);
|
||||
|
||||
/* The way that we handle signals in the simulation is kind of a
|
||||
* kludge. This would be unsafe in a truly multi-threaded,
|
||||
* interrupt driven environment.
|
||||
*/
|
||||
|
||||
if (rtcb->xcp.sigdeliver)
|
||||
{
|
||||
sdbg("CPU%d: Delivering signals TCB=%p\n", cpu, rtcb);
|
||||
((sig_deliver_t)rtcb->xcp.sigdeliver)(rtcb);
|
||||
rtcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* Reset scheduler parameters */
|
||||
|
||||
sched_resume_scheduler(rtcb);
|
||||
|
||||
/* Then switch contexts */
|
||||
|
||||
up_longjmp(rtcb->xcp.regs, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
Loading…
Reference in New Issue
Block a user