From 2332051c615e04a5e6e785544c61694e9976f2b7 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Tue, 15 Feb 2022 18:20:08 +0100 Subject: [PATCH] babblesim: Use pthreads instead of setlongjmp for tasks This changes tasks handling to native threads instead of setlongjmp() which resolves issue with calling the setlongjmp() from nested signal handlers but also simplifies code, makes debugging much easier and can work nicely with e.g. Valgrind. Each task is wrapped in a thread and all threads are synchronized on a global mutex to make sure only one task executes at any time. If context switch is requested (this is always done via os_sched() in critical section), a flag is set to indicate pending context switch which will be handled after exiting from critical setion and handling all other pending interrupts. This mimics the way it's done on a real hardware. --- babblesim/core/src/irq_handler.c | 6 - babblesim/core/src/main_config.c | 5 + .../nrf52_bsim/src/arch/bsim_arch/os_arch.c | 133 +++++--- .../src/arch/bsim_arch/os_arch_stack_frame.s | 104 ------- .../nrf52_bsim/src/arch/bsim_arch/sim_priv.h | 44 --- .../src/arch/bsim_arch/sim_sched_gen.c | 240 --------------- .../src/arch/bsim_arch/sim_sched_nosig.c | 238 --------------- .../src/arch/bsim_arch/sim_sched_sig.c | 288 ------------------ babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml | 3 + 9 files changed, 104 insertions(+), 957 deletions(-) delete mode 100644 babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch_stack_frame.s delete mode 100644 babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_priv.h delete mode 100644 babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_gen.c delete mode 100644 babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_nosig.c delete mode 100644 babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_sig.c diff --git a/babblesim/core/src/irq_handler.c b/babblesim/core/src/irq_handler.c index 805d7ecdc..f72aaf241 100644 --- a/babblesim/core/src/irq_handler.c +++ b/babblesim/core/src/irq_handler.c @@ -57,9 +57,6 @@ void posix_interrupt_raised(void) */ void posix_irq_handler_im_from_sw(void) { - int sr = 0; - - sr = sig_block_irq_on(); /* * if a higher priority interrupt than the possibly currently running is * pending we go immediately into irq_handler() to vector into its @@ -68,7 +65,4 @@ void posix_irq_handler_im_from_sw(void) if (hw_irq_ctrl_get_highest_prio_irq() != -1) { posix_interrupt_raised(); } - if (sr) { - sig_unblock_irq_off(); - } } diff --git a/babblesim/core/src/main_config.c b/babblesim/core/src/main_config.c index 4116e0797..ef8cb04d2 100644 --- a/babblesim/core/src/main_config.c +++ b/babblesim/core/src/main_config.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include "NRF_HW_model_top.h" #include "NRF_HWLowL.h" #include "bs_tracing.h" @@ -65,6 +66,10 @@ bsim_init(int argc, char** argv, int (*main_fn)(int argc, char **arg)) nrf_hw_initialize(&args->nrf_hw); os_init(main_fn); os_start(); + + while (1) { + sleep(1); + } } void diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c index 6700e90a6..8277ae7ca 100644 --- a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c +++ b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c @@ -17,72 +17,129 @@ * under the License. */ -#include "os/mynewt.h" -#include "os/sim.h" -#include "sim_priv.h" +#define _GNU_SOURCE +#include +#include +#include +#include #include -/* - * From HAL_CM4.s - */ -extern void SVC_Handler(void); -extern void PendSV_Handler(void); -extern void SysTick_Handler(void); +static pthread_mutex_t bsim_ctx_sw_mutex = PTHREAD_MUTEX_INITIALIZER; +static int bsim_pend_sv; -/* - * Assert that 'sf_mainsp' and 'sf_jb' are at the specific offsets where - * os_arch_frame_init() expects them to be. - */ -CTASSERT(offsetof(struct stack_frame, sf_mainsp) == 0); -CTASSERT(offsetof(struct stack_frame, sf_jb) == 4); +struct task_info { + pthread_t tid; + pthread_cond_t cond; + void *arg; +}; -void -os_arch_task_start(struct stack_frame *sf, int rc) +static void * +task_wrapper(void *arg) { - sim_task_start(sf, rc); + struct os_task *me = arg; + struct task_info *ti = me->t_arg; + + pthread_mutex_lock(&bsim_ctx_sw_mutex); + if (g_current_task != me) { + pthread_cond_wait(&ti->cond, &bsim_ctx_sw_mutex); + assert(g_current_task == me); + } + + me->t_func(ti->arg); + + assert(0); } os_stack_t * os_arch_task_stack_init(struct os_task *t, os_stack_t *stack_top, int size) { - return sim_task_stack_init(t, stack_top, size); + struct task_info *ti; + int err; + + ti = calloc(1, sizeof(*ti)); + + pthread_cond_init(&ti->cond, NULL); + ti->arg = t->t_arg; + t->t_arg = ti; + + err = pthread_create(&ti->tid, NULL, task_wrapper, t); + assert(err == 0); + + pthread_setname_np(ti->tid, t->t_name); + + return stack_top; } os_error_t os_arch_os_start(void) { - return sim_os_start(); -} + struct os_task *next_t; + struct task_info *ti; -void -os_arch_os_stop(void) -{ - sim_os_stop(); -} + os_tick_init(OS_TICKS_PER_SEC, 7); -void -PendSV_Handler(void) -{ - sim_switch_tasks(); + next_t = os_sched_next_task(); + assert(next_t); + os_sched_set_current_task(next_t); + + g_os_started = 1; + + ti = next_t->t_arg; + pthread_cond_signal(&ti->cond); + + return 0; } os_error_t os_arch_os_init(void) { - NVIC_SetVector(PendSV_IRQn, (uint32_t)PendSV_Handler); - return sim_os_init(); + STAILQ_INIT(&g_os_task_list); + TAILQ_INIT(&g_os_run_list); + TAILQ_INIT(&g_os_sleep_list); + + os_init_idle_task(); + + return OS_OK; } void os_arch_ctx_sw(struct os_task *next_t) { - sim_ctx_sw(next_t); + os_sched_ctx_sw_hook(next_t); + bsim_pend_sv = 1; +} + +static void +do_ctx_sw(void) +{ + struct os_task *next_t; + struct os_task *me; + struct task_info *ti, *next_ti; + + next_t = os_sched_next_task(); + assert(next_t); + + bsim_pend_sv = 0; + + assert(g_current_task); + me = g_current_task; + ti = me->t_arg; + + if (me == next_t) { + return; + } + + g_current_task = next_t; + next_ti = g_current_task->t_arg; + + pthread_cond_signal(&next_ti->cond); + pthread_cond_wait(&ti->cond, &bsim_ctx_sw_mutex); + assert(g_current_task == me); } os_sr_t os_arch_save_sr(void) { - sim_save_sr(); return hw_irq_ctrl_change_lock(1); } @@ -90,14 +147,16 @@ void os_arch_restore_sr(os_sr_t osr) { hw_irq_ctrl_change_lock(osr); - sim_restore_sr(osr); -} + if (!osr && bsim_pend_sv) { + do_ctx_sw(); + } +} int os_arch_in_critical(void) { - return sim_in_critical(); + return hw_irq_ctrl_get_current_lock(); } void diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch_stack_frame.s b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch_stack_frame.s deleted file mode 100644 index 81e5c066e..000000000 --- a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch_stack_frame.s +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#if defined MN_LINUX -#define sigsetjmp __sigsetjmp -#define CNAME(x) x -#elif defined MN_OSX -#define sigsetjmp sigsetjmp -#define CNAME(x) _ ## x -#elif defined MN_FreeBSD -#define sigsetjmp sigsetjmp -#define CNAME(x) x -#else -#error "unsupported platform" -#endif - - .text - .code32 - .p2align 4, 0x90 /* align on 16-byte boundary and fill with NOPs */ - - .globl CNAME(os_arch_frame_init) - .globl _os_arch_frame_init - /* - * void os_arch_frame_init(struct stack_frame *sf) - */ -CNAME(os_arch_frame_init): - push %ebp /* function prologue for backtrace */ - mov %esp,%ebp - push %esi /* save %esi before using it as a tmpreg */ - - /* - * At this point we are executing on the main() stack: - * ---------------- - * stack_frame ptr 0xc(%esp) - * ---------------- - * return address 0x8(%esp) - * ---------------- - * saved ebp 0x4(%esp) - * ---------------- - * saved esi 0x0(%esp) - * ---------------- - */ - movl 0xc(%esp),%esi /* %esi = 'sf' */ - movl %esp,0x0(%esi) /* sf->mainsp = %esp */ - - /* - * Switch the stack so the stack pointer stored in 'sf->sf_jb' points - * to the task stack. This is slightly complicated because OS X wants - * the incoming stack pointer to be 16-byte aligned. - * - * ---------------- - * sf (other fields) - * ---------------- - * sf (sf_jb) 0x4(%esi) - * ---------------- - * sf (sf_mainsp) 0x0(%esi) - * ---------------- - * alignment padding variable (0 to 12 bytes) - * ---------------- - * savemask (0) 0x4(%esp) - * ---------------- - * pointer to sf_jb 0x0(%esp) - * ---------------- - */ - movl %esi,%esp - subl $0x8,%esp /* make room for sigsetjmp() arguments */ - andl $0xfffffff0,%esp /* align %esp on 16-byte boundary */ - leal 0x4(%esi),%eax /* %eax = &sf->sf_jb */ - movl %eax,0x0(%esp) - movl $0, 0x4(%esp) - call CNAME(sigsetjmp) /* sigsetjmp(sf->sf_jb, 0) */ - test %eax,%eax - jne 1f - movl 0x0(%esi),%esp /* switch back to the main() stack */ - pop %esi - pop %ebp - ret /* return to os_arch_task_stack_init() */ -1: - lea 2f,%ecx - push %ecx /* retaddr */ - push $0 /* frame pointer */ - movl %esp,%ebp /* handcrafted prologue for backtrace */ - push %eax /* rc */ - push %esi /* sf */ - call CNAME(os_arch_task_start) /* os_arch_task_start(sf, rc) */ - /* never returns */ -2: - nop diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_priv.h b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_priv.h deleted file mode 100644 index 39984dfc2..000000000 --- a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_priv.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_SIM_PRIV_ -#define H_SIM_PRIV_ - -#include -#include "os/mynewt.h" -#include "mcu/mcu_sim.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define OS_USEC_PER_TICK (1000000 / OS_TICKS_PER_SEC) - -void sim_switch_tasks(void); -void sim_tick(void); -void sim_signals_init(void); -void sim_signals_cleanup(void); - -extern pid_t sim_pid; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_gen.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_gen.c deleted file mode 100644 index b3c192fcd..000000000 --- a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_gen.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This file contains code that is shared by both sim implementations (signals - * and no-signals). - */ - -#include "os/mynewt.h" - -#include - -#ifdef __APPLE__ -#define _XOPEN_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include "os/sim.h" -#include "sim_priv.h" - -#define sim_setjmp(__jb) sigsetjmp(__jb, 0) -#define sim_longjmp(__jb, __ret) siglongjmp(__jb, __ret) - -pid_t sim_pid; - -void -sim_switch_tasks(void) -{ - struct os_task *t, *next_t; - struct stack_frame *sf; - int rc; - - OS_ASSERT_CRITICAL(); - - t = os_sched_get_current_task(); - next_t = os_sched_next_task(); - if (t == next_t) { - /* - * Context switch not needed - just return. - */ - return; - } - - if (t) { - sf = (struct stack_frame *) t->t_stackptr; - - rc = sim_setjmp(sf->sf_jb); - if (rc != 0) { - OS_ASSERT_CRITICAL(); - return; - } - } - - os_sched_ctx_sw_hook(next_t); - - os_sched_set_current_task(next_t); - - sf = (struct stack_frame *) next_t->t_stackptr; - sim_longjmp(sf->sf_jb, 1); -} - -void -sim_tick(void) -{ - struct timeval time_now, time_diff; - int ticks; - - static struct timeval time_last; - static int time_inited; - - OS_ASSERT_CRITICAL(); - - if (!time_inited) { - gettimeofday(&time_last, NULL); - time_inited = 1; - } - - gettimeofday(&time_now, NULL); - if (timercmp(&time_now, &time_last, <)) { - /* - * System time going backwards. - */ - time_last = time_now; - } else { - timersub(&time_now, &time_last, &time_diff); - - ticks = time_diff.tv_sec * OS_TICKS_PER_SEC; - ticks += time_diff.tv_usec / OS_USEC_PER_TICK; - - /* - * Update 'time_last' but account for the remainder usecs that did not - * contribute towards whole 'ticks'. - */ - time_diff.tv_sec = 0; - time_diff.tv_usec %= OS_USEC_PER_TICK; - timersub(&time_now, &time_diff, &time_last); - - os_time_advance(ticks); - } -} - -#define OS_TICK_PRIO 7 - -static void -sim_start_timer(void) -{ - /* Intitialize and start system clock timer */ - os_tick_init(OS_TICKS_PER_SEC, OS_TICK_PRIO); -} - -static void -sim_stop_timer(void) -{ - struct itimerval it; - int rc; - - memset(&it, 0, sizeof(it)); - - rc = setitimer(ITIMER_REAL, &it, NULL); - assert(rc == 0); -} - -/* - * Called from 'os_arch_frame_init()' when setjmp returns indirectly via - * longjmp. The return value of setjmp is passed to this function as 'rc'. - */ -void -sim_task_start(struct stack_frame *sf, int rc) -{ - struct os_task *task; - - /* - * Interrupts are disabled when a task starts executing. This happens in - * two different ways: - * - via sim_os_start() for the first task. - * - via os_sched() for all other tasks. - * - * Enable interrupts before starting the task. - */ - OS_EXIT_CRITICAL(0); - - task = sf->sf_task; - task->t_func(task->t_arg); - - /* A task handler should never return. */ - assert(0); -} - -os_stack_t * -sim_task_stack_init(struct os_task *t, os_stack_t *stack_top, int size) -{ - struct stack_frame *sf; - - sf = (struct stack_frame *) ((uint8_t *) stack_top - sizeof(*sf)); - sf->sf_task = t; - - os_arch_frame_init(sf); - - return ((os_stack_t *)sf); -} - -os_error_t -sim_os_start(void) -{ - struct stack_frame *sf; - struct os_task *t; - os_sr_t sr; - - /* - * Disable interrupts before enabling any interrupt sources. Pending - * interrupts will be recognized when the first task starts executing. - */ - OS_ENTER_CRITICAL(sr); - assert(sr == 0); - - /* Enable the interrupt sources */ - sim_start_timer(); - - t = os_sched_next_task(); - os_sched_set_current_task(t); - - g_os_started = 1; - - sf = (struct stack_frame *) t->t_stackptr; - sim_longjmp(sf->sf_jb, 1); - - return 0; -} - -/** - * Stops the tick timer and clears the "started" flag. This function is only - * implemented for sim. - */ -void -sim_os_stop(void) -{ - sim_stop_timer(); - sim_signals_cleanup(); - g_os_started = 0; -} - -os_error_t -sim_os_init(void) -{ - sim_pid = getpid(); - g_current_task = NULL; - - STAILQ_INIT(&g_os_task_list); - TAILQ_INIT(&g_os_run_list); - TAILQ_INIT(&g_os_sleep_list); - - sim_signals_init(); - - os_init_idle_task(); - - return OS_OK; -} diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_nosig.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_nosig.c deleted file mode 100644 index fadb712ad..000000000 --- a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_nosig.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This file implements the "no-signals" version of sim. This implementation - * does not use signals to perform context switches. This is the less correct - * version of sim: the OS tick timer only runs while the idle task is active. - * Therefore, a sleeping high-priority task will not preempt a low-priority - * task due to a timing event (e.g., delay or callout expired). However, this - * version of sim does not suffer from the stability issues that affect the - * "signals" implementation. - * - * To use this version of sim, disable the MCU_NATIVE_USE_SIGNALS syscfg - * setting. - */ - -#include "os/mynewt.h" - -#if !MYNEWT_VAL(MCU_NATIVE_USE_SIGNALS) - -#include - -#ifdef __APPLE__ -#define _XOPEN_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include "sim_priv.h" - -static sigset_t nosigs; -static sigset_t suspsigs; /* signals delivered in sigsuspend() */ - -static int ctx_sw_pending; -static int interrupts_enabled = 1; - -void -sim_ctx_sw(struct os_task *next_t) -{ - if (interrupts_enabled) { - /* Perform the context switch immediately. */ - sim_switch_tasks(); - } else { - /* Remember that we want to perform a context switch. Perform it when - * interrupts are re-enabled. - */ - ctx_sw_pending = 1; - } -} - -/* - * Enter a critical section. - * - * Returns 1 if interrupts were already disabled; 0 otherwise. - */ -os_sr_t -sim_save_sr(void) -{ - if (!interrupts_enabled) { - return 1; - } - - interrupts_enabled = 0; - return 0; -} - -void -sim_restore_sr(os_sr_t osr) -{ - OS_ASSERT_CRITICAL(); - assert(osr == 0 || osr == 1); - - if (osr == 1) { - /* Exiting a nested critical section */ - return; - } - - if (ctx_sw_pending) { - /* A context switch was requested while interrupts were disabled. - * Perform it now that interrupts are enabled again. - */ - ctx_sw_pending = 0; - sim_switch_tasks(); - } - interrupts_enabled = 1; -} - -int -sim_in_critical(void) -{ - return !interrupts_enabled; -} - -/** - * Unblocks the SIGALRM signal that is delivered by the OS tick timer. - */ -static void -unblock_timer(void) -{ - sigset_t sigs; - int rc; - - sigemptyset(&sigs); - sigaddset(&sigs, SIGALRM); - - rc = sigprocmask(SIG_UNBLOCK, &sigs, NULL); - assert(rc == 0); -} - -/** - * Blocks the SIGALRM signal that is delivered by the OS tick timer. - */ -static void -block_timer(void) -{ - sigset_t sigs; - int rc; - - sigemptyset(&sigs); - sigaddset(&sigs, SIGALRM); - - rc = sigprocmask(SIG_BLOCK, &sigs, NULL); - assert(rc == 0); -} - -static void -sig_handler_alrm(int sig) -{ - /* Wake the idle task. */ - sigaddset(&suspsigs, sig); -} - -void -sim_tick_idle(os_time_t ticks) -{ - int rc; - struct itimerval it; - - OS_ASSERT_CRITICAL(); - - if (ticks > 0) { - /* - * Enter tickless regime and set the timer to fire after 'ticks' - * worth of time has elapsed. - */ - it.it_value.tv_sec = ticks / OS_TICKS_PER_SEC; - it.it_value.tv_usec = (ticks % OS_TICKS_PER_SEC) * OS_USEC_PER_TICK; - it.it_interval.tv_sec = 0; - it.it_interval.tv_usec = OS_USEC_PER_TICK; - rc = setitimer(ITIMER_REAL, &it, NULL); - assert(rc == 0); - } - - unblock_timer(); - - sigemptyset(&suspsigs); - sigsuspend(&nosigs); /* Wait for a signal to wake us up */ - - block_timer(); - - /* - * Call handlers for signals delivered to the process during sigsuspend(). - * The SIGALRM handler is called before any other handlers to ensure that - * OS time is always correct. - */ - if (sigismember(&suspsigs, SIGALRM)) { - sim_tick(); - } - - if (ticks > 0) { - /* - * Enable the periodic timer interrupt. - */ - it.it_value.tv_sec = 0; - it.it_value.tv_usec = OS_USEC_PER_TICK; - it.it_interval.tv_sec = 0; - it.it_interval.tv_usec = OS_USEC_PER_TICK; - rc = setitimer(ITIMER_REAL, &it, NULL); - assert(rc == 0); - } -} - -void -sim_signals_init(void) -{ - sigset_t sigset_alrm; - struct sigaction sa; - int error; - - block_timer(); - - sigemptyset(&nosigs); - - sigemptyset(&sigset_alrm); - sigaddset(&sigset_alrm, SIGALRM); - - memset(&sa, 0, sizeof sa); - sa.sa_handler = sig_handler_alrm; - sa.sa_mask = sigset_alrm; - sa.sa_flags = SA_RESTART; - error = sigaction(SIGALRM, &sa, NULL); - assert(error == 0); -} - -void -sim_signals_cleanup(void) -{ - int error; - struct sigaction sa; - - memset(&sa, 0, sizeof sa); - sa.sa_handler = SIG_DFL; - error = sigaction(SIGALRM, &sa, NULL); - assert(error == 0); -} - -#endif /* !MYNEWT_VAL(MCU_NATIVE_USE_SIGNALS) */ diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_sig.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_sig.c deleted file mode 100644 index c26abcea0..000000000 --- a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_sig.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This file implements the "signals" version of sim. This implementation uses - * signals to perform context switches. This is the more correct version of - * sim: the OS tick timer will cause a high-priority task to preempt a - * low-priority task. Unfortunately, there are stability issues because a task - * can be preempted while it is in the middle of a system call, potentially - * causing deadlock or memory corruption. - * - * To use this version of sim, enable the MCU_NATIVE_USE_SIGNALS syscfg - * setting. - */ - -#include "os/mynewt.h" - -#if MYNEWT_VAL(MCU_NATIVE_USE_SIGNALS) - -#include "sim_priv.h" - -#include - -#ifdef __APPLE__ -#define _XOPEN_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include - -static bool suspended; /* process is blocked in sigsuspend() */ -static sigset_t suspsigs; /* signals delivered in sigsuspend() */ -static sigset_t allsigs; -static sigset_t nosigs; - -static int in_irq; -int counter = 0; - -int -sig_block_irq_on() -{ - int error; - - counter++; - - error = sigprocmask(SIG_BLOCK, &allsigs, NULL); - - in_irq = 1; - assert(error == 0); - return 1; -} - -void -sig_unblock_irq_off() -{ - int error; - - in_irq = 0; - - if (counter > 0) { - counter--; - return; - } - - error = sigprocmask(SIG_UNBLOCK, &allsigs, NULL); - assert(error == 0); - -} - -void -sim_ctx_sw(struct os_task *next_t) -{ - /* - * gdb will stop execution of the program on most signals (e.g. SIGUSR1) - * whereas it passes SIGURG to the process without any special settings. - */ - kill(sim_pid, SIGURG); -} - -static void -ctxsw_handler(int sig) -{ - assert(in_irq==0); - OS_ASSERT_CRITICAL(); - - /* - * Just record that this handler was called when the process was blocked. - * The handler will be called after sigsuspend() returns in the correct - * order. - */ - if (suspended) { - sigaddset(&suspsigs, sig); - } else { - sim_switch_tasks(); - } -} - -/* - * Disable signals and enter a critical section. - * - * Returns 1 if signals were already blocked and 0 otherwise. - */ -os_sr_t -sim_save_sr(void) -{ - int error; - sigset_t omask; - - counter++; - - error = sigprocmask(SIG_BLOCK, &allsigs, &omask); - assert(error == 0); - - /* - * If any one of the signals in 'allsigs' is present in 'omask' then - * we are already inside a critical section. - */ - return (sigismember(&omask, SIGURG)); -} - -void -sim_restore_sr(os_sr_t osr) -{ - int error; - - OS_ASSERT_CRITICAL(); - assert(osr == 0 || osr == 1); - - if (counter > 0) { - counter--; - } - - if (osr == 1 || in_irq == 1 || counter > 0) { - /* Exiting a nested critical section */ - return; - } - - error = sigprocmask(SIG_UNBLOCK, &allsigs, NULL); - assert(error == 0); -} - -int -sim_in_critical(void) -{ - int error; - sigset_t omask; - - error = sigprocmask(SIG_SETMASK, NULL, &omask); - assert(error == 0); - - /* - * If any one of the signals in 'allsigs' is present in 'omask' then - * we are already inside a critical section. - */ - return (sigismember(&omask, SIGURG)); -} - -static struct { - int num; - void (*handler)(int sig); -} signals[] = { -// { SIGALRM, timer_handler }, - { SIGURG, ctxsw_handler }, -}; - -#define NUMSIGS (sizeof(signals)/sizeof(signals[0])) - -void -sim_tick_idle(os_time_t ticks) -{ - int i, rc, sig; - struct itimerval it; - void (*handler)(int sig); - - OS_ASSERT_CRITICAL(); - - if (ticks > 0) { - /* - * Enter tickless regime and set the timer to fire after 'ticks' - * worth of time has elapsed. - */ - it.it_value.tv_sec = ticks / OS_TICKS_PER_SEC; - it.it_value.tv_usec = (ticks % OS_TICKS_PER_SEC) * OS_USEC_PER_TICK; - it.it_interval.tv_sec = 0; - it.it_interval.tv_usec = OS_USEC_PER_TICK; - rc = setitimer(ITIMER_REAL, &it, NULL); - assert(rc == 0); - } - - suspended = true; - sigemptyset(&suspsigs); - sigsuspend(&nosigs); /* Wait for a signal to wake us up */ - suspended = false; - - /* - * Call handlers for signals delivered to the process during sigsuspend(). - * The SIGALRM handler is called before any other handlers to ensure that - * OS time is always correct. - */ - if (sigismember(&suspsigs, SIGALRM)) { - sim_tick(); - } - for (i = 0; i < NUMSIGS; i++) { - sig = signals[i].num; - handler = signals[i].handler; - if (sig != SIGALRM && sigismember(&suspsigs, sig)) { - handler(sig); - } - } - - if (ticks > 0) { - /* - * Enable the periodic timer interrupt. - */ - it.it_value.tv_sec = 0; - it.it_value.tv_usec = OS_USEC_PER_TICK; - it.it_interval.tv_sec = 0; - it.it_interval.tv_usec = OS_USEC_PER_TICK; - rc = setitimer(ITIMER_REAL, &it, NULL); - assert(rc == 0); - } -} - -void -sim_signals_init(void) -{ - int i, error; - struct sigaction sa; - - sigemptyset(&nosigs); - sigemptyset(&allsigs); - for (i = 0; i < NUMSIGS; i++) { - sigaddset(&allsigs, signals[i].num); - } - - for (i = 0; i < NUMSIGS; i++) { - memset(&sa, 0, sizeof sa); - sa.sa_handler = signals[i].handler; - sa.sa_mask = allsigs; - sa.sa_flags = SA_RESTART; - error = sigaction(signals[i].num, &sa, NULL); - assert(error == 0); - } - - /* - * We use SIGALRM as a proxy for 'allsigs' to check if we are inside - * a critical section (for e.g. see sim_in_critical()). Make sure - * that SIGALRM is indeed present in 'allsigs'. - */ -// assert(sigismember(&allsigs, SIGALRM)); -} - -void -sim_signals_cleanup(void) -{ - int i, error; - struct sigaction sa; - - for (i = 0; i < NUMSIGS; i++) { - memset(&sa, 0, sizeof sa); - sa.sa_handler = SIG_DFL; - error = sigaction(signals[i].num, &sa, NULL); - assert(error == 0); - } -} - -#endif /* MYNEWT_VAL(MCU_NATIVE_USE_SIGNALS) */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml b/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml index 4f332acba..10069a2e6 100644 --- a/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml @@ -22,6 +22,9 @@ pkg.description: nRF52 on BabbleSim pkg.author: "Apache Mynewt " pkg.homepage: "http://mynewt.apache.org/" +pkg.lflags: + - -lpthread + pkg.deps: - "babblesim/nrfx"