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"