soc inf (native): Refactor into a top and bottom
Where the bottom is the only one which interacts with the host operating system. And the top the only one that interacts or is aware of the hosted operating system (Zephyr). The bottom uses the native simulator CPU start/stop emulation. By now we replicate its code as a provisional measure, until the native simulator becomes standard. Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
This commit is contained in:
parent
bd66c1d953
commit
7ee41b8776
8 changed files with 447 additions and 148 deletions
|
@ -6,7 +6,13 @@ zephyr_library_sources(
|
|||
cpuhalt.c
|
||||
fatal.c
|
||||
irq.c
|
||||
nsi_compat/nsi_compat.c
|
||||
nsi_compat/nce.c
|
||||
posix_core.c
|
||||
swap.c
|
||||
thread.c
|
||||
)
|
||||
|
||||
zephyr_include_directories(
|
||||
nsi_compat/
|
||||
)
|
||||
|
|
292
arch/posix/core/nsi_compat/nce.c
Normal file
292
arch/posix/core/nsi_compat/nce.c
Normal file
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Native simulator CPU emulator,
|
||||
* an *optional* module provided by the native simulator
|
||||
* the hosted embedded OS / SW can use to emulate the CPU
|
||||
* being started and stopped.
|
||||
*
|
||||
* Its mode of operation is that it step-locks the HW
|
||||
* and SW operation, so that only one of them executes at
|
||||
* a time. Check the docs for more info.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include "nce_if.h"
|
||||
#include "nsi_safe_call.h"
|
||||
|
||||
struct nce_status_t {
|
||||
/* Conditional variable to know if the CPU is running or halted/idling */
|
||||
pthread_cond_t cond_cpu;
|
||||
/* Mutex for the conditional variable cond_cpu */
|
||||
pthread_mutex_t mtx_cpu;
|
||||
/* Variable which tells if the CPU is halted (1) or not (0) */
|
||||
bool cpu_halted;
|
||||
bool terminate; /* Are we terminating the program == cleaning up */
|
||||
void (*start_routine)(void);
|
||||
};
|
||||
|
||||
#define NCE_DEBUG_PRINTS 0
|
||||
|
||||
#define PREFIX "NCE: "
|
||||
#define ERPREFIX PREFIX"error on "
|
||||
#define NO_MEM_ERR PREFIX"Can't allocate memory\n"
|
||||
|
||||
#if NCE_DEBUG_PRINTS
|
||||
#define NCE_DEBUG(fmt, ...) nsi_print_trace(PREFIX fmt, __VA_ARGS__)
|
||||
#else
|
||||
#define NCE_DEBUG(...)
|
||||
#endif
|
||||
|
||||
extern void nsi_exit(int exit_code);
|
||||
|
||||
/*
|
||||
* Initialize an instance of the native simulator CPU emulator
|
||||
* and return a pointer to it.
|
||||
* That pointer should be passed to all subsequent calls to this module.
|
||||
*/
|
||||
void *nce_init(void)
|
||||
{
|
||||
struct nce_status_t *this;
|
||||
|
||||
this = calloc(1, sizeof(struct nce_status_t));
|
||||
|
||||
if (this == NULL) { /* LCOV_EXCL_BR_LINE */
|
||||
nsi_print_error_and_exit(NO_MEM_ERR); /* LCOV_EXCL_LINE */
|
||||
}
|
||||
this->cpu_halted = true;
|
||||
this->terminate = false;
|
||||
|
||||
NSI_SAFE_CALL(pthread_cond_init(&this->cond_cpu, NULL));
|
||||
NSI_SAFE_CALL(pthread_mutex_init(&this->mtx_cpu, NULL));
|
||||
|
||||
return (void *)this;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will:
|
||||
*
|
||||
* If called from a SW thread, release the HW thread which is blocked in
|
||||
* a nce_wake_cpu() and never return.
|
||||
*
|
||||
* If called from a HW thread, do the necessary clean up of this nce instance
|
||||
* and return right away.
|
||||
*/
|
||||
void nce_terminate(void *this_arg)
|
||||
{
|
||||
struct nce_status_t *this = (struct nce_status_t *)this_arg;
|
||||
|
||||
/* LCOV_EXCL_START */ /* See Note1 */
|
||||
/*
|
||||
* If we are being called from a HW thread we can cleanup
|
||||
*
|
||||
* Otherwise (!cpu_halted) we give back control to the HW thread and
|
||||
* tell it to terminate ASAP
|
||||
*/
|
||||
if (this == NULL || this->cpu_halted) {
|
||||
/*
|
||||
* Note: The nce_status structure cannot be safely free'd up
|
||||
* as the user is allowed to call nce_clean_up()
|
||||
* repeatedly on the same structure.
|
||||
* Instead we rely of on the host OS process cleanup.
|
||||
* If you got here due to valgrind's leak report, please use the
|
||||
* provided valgrind suppression file valgrind.supp
|
||||
*/
|
||||
return;
|
||||
} else if (this->terminate == false) {
|
||||
|
||||
this->terminate = true;
|
||||
|
||||
NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu));
|
||||
|
||||
this->cpu_halted = true;
|
||||
|
||||
NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_cpu));
|
||||
NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu));
|
||||
|
||||
while (1) {
|
||||
sleep(1);
|
||||
/* This SW thread will wait until being cancelled from
|
||||
* the HW thread. sleep() is a cancellation point, so it
|
||||
* won't really wait 1 second
|
||||
*/
|
||||
}
|
||||
}
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function which changes the status of the CPU (halted or running)
|
||||
* and waits until somebody else changes it to the opposite
|
||||
*
|
||||
* Both HW and SW threads will use this function to transfer control to the
|
||||
* other side.
|
||||
*
|
||||
* This is how the idle thread halts the CPU and gets halted until the HW models
|
||||
* raise a new interrupt; and how the HW models awake the CPU, and wait for it
|
||||
* to complete and go to idle.
|
||||
*/
|
||||
static void change_cpu_state_and_wait(struct nce_status_t *this, bool halted)
|
||||
{
|
||||
NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu));
|
||||
|
||||
NCE_DEBUG("Going to halted = %d\n", halted);
|
||||
|
||||
this->cpu_halted = halted;
|
||||
|
||||
/* We let the other side know the CPU has changed state */
|
||||
NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_cpu));
|
||||
|
||||
/* We wait until the CPU state has been changed. Either:
|
||||
* we just awoke it, and therefore wait until the CPU has run until
|
||||
* completion before continuing (before letting the HW models do
|
||||
* anything else)
|
||||
* or
|
||||
* we are just hanging it, and therefore wait until the HW models awake
|
||||
* it again
|
||||
*/
|
||||
while (this->cpu_halted == halted) {
|
||||
/* Here we unlock the mutex while waiting */
|
||||
pthread_cond_wait(&this->cond_cpu, &this->mtx_cpu);
|
||||
}
|
||||
|
||||
NCE_DEBUG("Awaken after halted = %d\n", halted);
|
||||
|
||||
NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu));
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function that wraps the SW start_routine
|
||||
*/
|
||||
static void *sw_wrapper(void *this_arg)
|
||||
{
|
||||
struct nce_status_t *this = (struct nce_status_t *)this_arg;
|
||||
|
||||
/* Ensure nce_boot_cpu has reached the cond loop */
|
||||
NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu));
|
||||
NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu));
|
||||
|
||||
#if (NCE_DEBUG_PRINTS)
|
||||
pthread_t sw_thread = pthread_self();
|
||||
|
||||
NCE_DEBUG("SW init started (%lu)\n",
|
||||
sw_thread);
|
||||
#endif
|
||||
|
||||
this->start_routine();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Boot the emulated CPU, that is:
|
||||
* * Spawn a new pthread which will run the first embedded SW thread <start_routine>
|
||||
* * Hold the caller until that embedded SW thread (or a child it spawns)
|
||||
* calls nce_halt_cpu()
|
||||
*
|
||||
* Note that during this, an embedded SW thread may call nsi_exit(), which would result
|
||||
* in this function never returning.
|
||||
*/
|
||||
void nce_boot_cpu(void *this_arg, void (*start_routine)(void))
|
||||
{
|
||||
struct nce_status_t *this = (struct nce_status_t *)this_arg;
|
||||
|
||||
NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu));
|
||||
|
||||
this->cpu_halted = false;
|
||||
this->start_routine = start_routine;
|
||||
|
||||
/* Create a thread for the embedded SW init: */
|
||||
pthread_t sw_thread;
|
||||
|
||||
NSI_SAFE_CALL(pthread_create(&sw_thread, NULL, sw_wrapper, this_arg));
|
||||
|
||||
/* And we wait until the embedded OS has send the CPU to sleep for the first time */
|
||||
while (this->cpu_halted == false) {
|
||||
pthread_cond_wait(&this->cond_cpu, &this->mtx_cpu);
|
||||
}
|
||||
NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu));
|
||||
|
||||
if (this->terminate) {
|
||||
nsi_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Halt the CPU, that is:
|
||||
* * Hold this embedded SW thread until the CPU is awaken again,
|
||||
* and release the HW thread which had been held on
|
||||
* nce_boot_cpu() or nce_wake_cpu().
|
||||
*
|
||||
* Note: Can only be called from embedded SW threads
|
||||
* Calling it from a HW thread is a programming error.
|
||||
*/
|
||||
void nce_halt_cpu(void *this_arg)
|
||||
{
|
||||
struct nce_status_t *this = (struct nce_status_t *)this_arg;
|
||||
|
||||
if (this->cpu_halted == true) {
|
||||
nsi_print_error_and_exit("Programming error on: %s ",
|
||||
"This CPU was already halted\n");
|
||||
}
|
||||
change_cpu_state_and_wait(this, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Awake the CPU, that is:
|
||||
* * Hold this HW thread until the CPU is set to idle again
|
||||
* * Release the SW thread which had been held on nce_halt_cpu()
|
||||
*
|
||||
* Note: Can only be called from HW threads
|
||||
* Calling it from a SW thread is a programming error.
|
||||
*/
|
||||
void nce_wake_cpu(void *this_arg)
|
||||
{
|
||||
struct nce_status_t *this = (struct nce_status_t *)this_arg;
|
||||
|
||||
if (this->cpu_halted == false) {
|
||||
nsi_print_error_and_exit("Programming error on: %s ",
|
||||
"This CPU was already awake\n");
|
||||
}
|
||||
change_cpu_state_and_wait(this, false);
|
||||
|
||||
/*
|
||||
* If while the SW was running it was decided to terminate the execution
|
||||
* we stop immediately.
|
||||
*/
|
||||
if (this->terminate) {
|
||||
nsi_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 0 if the CPU is sleeping (or terminated)
|
||||
* and !=0 if the CPU is running
|
||||
*/
|
||||
int nce_is_cpu_running(void *this_arg)
|
||||
{
|
||||
struct nce_status_t *this = (struct nce_status_t *)this_arg;
|
||||
|
||||
if (this != NULL) {
|
||||
return !this->cpu_halted;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Notes about coverage:
|
||||
*
|
||||
* Note1: When the application is closed due to a SIGTERM, the path in this
|
||||
* function will depend on when that signal was received. Typically during a
|
||||
* regression run, both paths will be covered. But in some cases they won't.
|
||||
* Therefore and to avoid confusing developers with spurious coverage changes
|
||||
* we exclude this function from the coverage check
|
||||
*/
|
26
arch/posix/core/nsi_compat/nce_if.h
Normal file
26
arch/posix/core/nsi_compat/nce_if.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef NSI_COMMON_SRC_INCL_NCE_IF_H
|
||||
#define NSI_COMMON_SRC_INCL_NCE_IF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Native simulator CPU start/stop emulation module interface */
|
||||
|
||||
void *nce_init(void);
|
||||
void nce_terminate(void *this);
|
||||
void nce_boot_cpu(void *this, void (*start_routine)(void));
|
||||
void nce_halt_cpu(void *this);
|
||||
void nce_wake_cpu(void *this);
|
||||
int nce_is_cpu_running(void *this);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NSI_COMMON_SRC_INCL_NCE_IF_H */
|
49
arch/posix/core/nsi_compat/nsi_compat.c
Normal file
49
arch/posix/core/nsi_compat/nsi_compat.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* This module exist to provide a basic compatibility shim
|
||||
* from Native simulator components into the POSIX architecture.
|
||||
*
|
||||
* It is a transitional component, intended to facilitate
|
||||
* the migration towards the Native simulator.
|
||||
*/
|
||||
|
||||
#include "zephyr/arch/posix/posix_trace.h"
|
||||
|
||||
void nsi_print_error_and_exit(const char *format, ...)
|
||||
{
|
||||
va_list variable_args;
|
||||
|
||||
va_start(variable_args, format);
|
||||
posix_vprint_error_and_exit(format, variable_args);
|
||||
va_end(variable_args);
|
||||
}
|
||||
|
||||
void nsi_print_warning(const char *format, ...)
|
||||
{
|
||||
va_list variable_args;
|
||||
|
||||
va_start(variable_args, format);
|
||||
posix_vprint_warning(format, variable_args);
|
||||
va_end(variable_args);
|
||||
}
|
||||
|
||||
void nsi_print_trace(const char *format, ...)
|
||||
{
|
||||
va_list variable_args;
|
||||
|
||||
va_start(variable_args, format);
|
||||
posix_vprint_trace(format, variable_args);
|
||||
va_end(variable_args);
|
||||
}
|
||||
|
||||
void nsi_exit(int exit_code)
|
||||
{
|
||||
extern void posix_exit(int exit_code);
|
||||
|
||||
posix_exit(exit_code);
|
||||
}
|
22
arch/posix/core/nsi_compat/nsi_compat.h
Normal file
22
arch/posix/core/nsi_compat/nsi_compat.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ARCH_POSIX_CORE_NSI_COMPAT_H
|
||||
#define ARCH_POSIX_CORE_NSI_COMPAT_H
|
||||
|
||||
#include "nsi_tracing.h"
|
||||
#include "nsi_safe_call.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void nsi_exit(int exit_code);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ARCH_POSIX_CORE_NSI_COMPAT_H */
|
15
arch/posix/core/nsi_compat/nsi_safe_call.h
Normal file
15
arch/posix/core/nsi_compat/nsi_safe_call.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ARCH_POSIX_CORE_NSI_SAFE_CALLL_H
|
||||
#define ARCH_POSIX_CORE_NSI_SAFE_CALLL_H
|
||||
|
||||
#include "nsi_tracing.h"
|
||||
#include "posix_arch_internal.h"
|
||||
|
||||
#define NSI_SAFE_CALL PC_SAFE_CALL
|
||||
|
||||
#endif /* ARCH_POSIX_CORE_NSI_SAFE_CALLL_H */
|
22
arch/posix/core/nsi_compat/nsi_tracing.h
Normal file
22
arch/posix/core/nsi_compat/nsi_tracing.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ARCH_POSIX_CORE_NSI_TRACING_H
|
||||
#define ARCH_POSIX_CORE_NSI_TRACING_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void nsi_print_error_and_exit(const char *format, ...);
|
||||
void nsi_print_warning(const char *format, ...);
|
||||
void nsi_print_trace(const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ARCH_POSIX_CORE_NSI_TRACING_H */
|
|
@ -24,9 +24,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <zephyr/arch/posix/posix_soc_if.h>
|
||||
#include "posix_soc.h"
|
||||
#include "posix_board_if.h"
|
||||
|
@ -34,34 +31,15 @@
|
|||
#include "posix_arch_internal.h"
|
||||
#include "kernel_internal.h"
|
||||
#include "soc.h"
|
||||
#include "nce_if.h"
|
||||
|
||||
#define POSIX_ARCH_SOC_DEBUG_PRINTS 0
|
||||
|
||||
#define PREFIX "POSIX SOC: "
|
||||
#define ERPREFIX PREFIX"error on "
|
||||
|
||||
#if POSIX_ARCH_SOC_DEBUG_PRINTS
|
||||
#define PS_DEBUG(fmt, ...) posix_print_trace(PREFIX fmt, __VA_ARGS__)
|
||||
#else
|
||||
#define PS_DEBUG(...)
|
||||
#endif
|
||||
|
||||
/* Conditional variable to know if the CPU is running or halted/idling */
|
||||
static pthread_cond_t cond_cpu = PTHREAD_COND_INITIALIZER;
|
||||
/* Mutex for the conditional variable posix_soc_cond_cpu */
|
||||
static pthread_mutex_t mtx_cpu = PTHREAD_MUTEX_INITIALIZER;
|
||||
/* Variable which tells if the CPU is halted (1) or not (0) */
|
||||
static bool cpu_halted = true;
|
||||
|
||||
static bool soc_terminate; /* Is the program being closed */
|
||||
|
||||
static void *nce_st;
|
||||
|
||||
int posix_is_cpu_running(void)
|
||||
{
|
||||
return !cpu_halted;
|
||||
return nce_is_cpu_running(nce_st);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function which changes the status of the CPU (halted or running)
|
||||
* and waits until somebody else changes it to the opposite
|
||||
|
@ -75,31 +53,11 @@ int posix_is_cpu_running(void)
|
|||
*/
|
||||
void posix_change_cpu_state_and_wait(bool halted)
|
||||
{
|
||||
PC_SAFE_CALL(pthread_mutex_lock(&mtx_cpu));
|
||||
|
||||
PS_DEBUG("Going to halted = %d\n", halted);
|
||||
|
||||
cpu_halted = halted;
|
||||
|
||||
/* We let the other side know the CPU has changed state */
|
||||
PC_SAFE_CALL(pthread_cond_broadcast(&cond_cpu));
|
||||
|
||||
/* We wait until the CPU state has been changed. Either:
|
||||
* we just awoke it, and therefore wait until the CPU has run until
|
||||
* completion before continuing (before letting the HW models do
|
||||
* anything else)
|
||||
* or
|
||||
* we are just hanging it, and therefore wait until the HW models awake
|
||||
* it again
|
||||
*/
|
||||
while (cpu_halted == halted) {
|
||||
/* Here we unlock the mutex while waiting */
|
||||
pthread_cond_wait(&cond_cpu, &mtx_cpu);
|
||||
if (halted) {
|
||||
nce_halt_cpu(nce_st);
|
||||
} else {
|
||||
nce_wake_cpu(nce_st);
|
||||
}
|
||||
|
||||
PS_DEBUG("Awaken after halted = %d\n", halted);
|
||||
|
||||
PC_SAFE_CALL(pthread_mutex_unlock(&mtx_cpu));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,15 +69,7 @@ void posix_interrupt_raised(void)
|
|||
/* We change the CPU to running state (we awake it), and block this
|
||||
* thread until the CPU is halted again
|
||||
*/
|
||||
posix_change_cpu_state_and_wait(false);
|
||||
|
||||
/*
|
||||
* If while the SW was running it was decided to terminate the execution
|
||||
* we stop immediately.
|
||||
*/
|
||||
if (soc_terminate) {
|
||||
posix_exit(0);
|
||||
}
|
||||
nce_wake_cpu(nce_st);
|
||||
}
|
||||
|
||||
|
||||
|
@ -136,7 +86,7 @@ void posix_halt_cpu(void)
|
|||
* We set the CPU in the halted state (this blocks this pthread
|
||||
* until the CPU is awoken again by the HW models)
|
||||
*/
|
||||
posix_change_cpu_state_and_wait(true);
|
||||
nce_halt_cpu(nce_st);
|
||||
|
||||
/* We are awoken, normally that means some interrupt has just come
|
||||
* => let the "irq handler" check if/what interrupt was raised
|
||||
|
@ -164,34 +114,6 @@ void posix_atomic_halt_cpu(unsigned int imask)
|
|||
posix_irq_unlock(imask);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Just a wrapper function to call Zephyr's z_cstart()
|
||||
* called from posix_boot_cpu()
|
||||
*/
|
||||
static void *zephyr_wrapper(void *a)
|
||||
{
|
||||
/* Ensure posix_boot_cpu has reached the cond loop */
|
||||
PC_SAFE_CALL(pthread_mutex_lock(&mtx_cpu));
|
||||
PC_SAFE_CALL(pthread_mutex_unlock(&mtx_cpu));
|
||||
|
||||
#if (POSIX_ARCH_SOC_DEBUG_PRINTS)
|
||||
pthread_t zephyr_thread = pthread_self();
|
||||
|
||||
PS_DEBUG("Zephyr init started (%lu)\n",
|
||||
zephyr_thread);
|
||||
#endif
|
||||
|
||||
posix_arch_init();
|
||||
|
||||
/* Start Zephyr: */
|
||||
z_cstart();
|
||||
CODE_UNREACHABLE;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The HW models will call this function to "boot" the CPU
|
||||
* == spawn the Zephyr init thread, which will then spawn
|
||||
|
@ -199,24 +121,9 @@ static void *zephyr_wrapper(void *a)
|
|||
*/
|
||||
void posix_boot_cpu(void)
|
||||
{
|
||||
PC_SAFE_CALL(pthread_mutex_lock(&mtx_cpu));
|
||||
|
||||
cpu_halted = false;
|
||||
|
||||
pthread_t zephyr_thread;
|
||||
|
||||
/* Create a thread for Zephyr init: */
|
||||
PC_SAFE_CALL(pthread_create(&zephyr_thread, NULL, zephyr_wrapper, NULL));
|
||||
|
||||
/* And we wait until Zephyr has run til completion (has gone to idle) */
|
||||
while (cpu_halted == false) {
|
||||
pthread_cond_wait(&cond_cpu, &mtx_cpu);
|
||||
}
|
||||
PC_SAFE_CALL(pthread_mutex_unlock(&mtx_cpu));
|
||||
|
||||
if (soc_terminate) {
|
||||
posix_exit(0);
|
||||
}
|
||||
nce_st = nce_init();
|
||||
posix_arch_init();
|
||||
nce_boot_cpu(nce_st, z_cstart);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,47 +133,7 @@ void posix_boot_cpu(void)
|
|||
*/
|
||||
void posix_soc_clean_up(void)
|
||||
{
|
||||
/* LCOV_EXCL_START */ /* See Note1 */
|
||||
/*
|
||||
* If we are being called from a HW thread we can cleanup
|
||||
*
|
||||
* Otherwise (!cpu_halted) we give back control to the HW thread and
|
||||
* tell it to terminate ASAP
|
||||
*/
|
||||
if (cpu_halted) {
|
||||
|
||||
posix_arch_clean_up();
|
||||
run_native_tasks(_NATIVE_ON_EXIT_LEVEL);
|
||||
|
||||
} else if (soc_terminate == false) {
|
||||
|
||||
soc_terminate = true;
|
||||
|
||||
PC_SAFE_CALL(pthread_mutex_lock(&mtx_cpu));
|
||||
|
||||
cpu_halted = true;
|
||||
|
||||
PC_SAFE_CALL(pthread_cond_broadcast(&cond_cpu));
|
||||
PC_SAFE_CALL(pthread_mutex_unlock(&mtx_cpu));
|
||||
|
||||
while (1) {
|
||||
sleep(1);
|
||||
/* This SW thread will wait until being cancelled from
|
||||
* the HW thread. sleep() is a cancellation point, so it
|
||||
* won't really wait 1 second
|
||||
*/
|
||||
}
|
||||
}
|
||||
/* LCOV_EXCL_STOP */
|
||||
nce_terminate(nce_st);
|
||||
posix_arch_clean_up();
|
||||
run_native_tasks(_NATIVE_ON_EXIT_LEVEL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Notes about coverage:
|
||||
*
|
||||
* Note1: When the application is closed due to a SIGTERM, the path in this
|
||||
* function will depend on when that signal was received. Typically during a
|
||||
* regression run, both paths will be covered. But in some cases they won't.
|
||||
* Therefore and to avoid confusing developers with spurious coverage changes
|
||||
* we exclude this function from the coverage check
|
||||
*
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue