Skip to content

Commit

Permalink
stop creation of multiple timers when not useing repeating timers
Browse files Browse the repository at this point in the history
  • Loading branch information
kilograham committed Jul 20, 2022
1 parent 647d6fc commit 6124bc9
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 9 deletions.
4 changes: 1 addition & 3 deletions src/common/pico_sync/critical_section.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,5 @@ void critical_section_init_with_lock_num(critical_section_t *crit_sec, uint lock

void critical_section_deinit(critical_section_t *crit_sec) {
spin_lock_unclaim(spin_lock_get_num(crit_sec->spin_lock));
#ifndef NDEBUG
crit_sec->spin_lock = (spin_lock_t *)-1;
#endif
crit_sec->spin_lock = NULL;
}
10 changes: 10 additions & 0 deletions src/common/pico_sync/include/pico/critical_section.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ static inline void critical_section_exit(critical_section_t *crit_sec) {
*/
void critical_section_deinit(critical_section_t *crit_sec);

/*! \brief Test whether a critical_section has been initialized
* \ingroup mutex
*
* \param crit_sec Pointer to critical_section structure
* \return true if the critical section is initialized, false otherwise
*/
static inline bool critical_section_is_initialized(critical_section_t *crit_sec) {
return crit_sec->spin_lock != 0;
}

#ifdef __cplusplus
}
#endif
Expand Down
34 changes: 28 additions & 6 deletions src/rp2_common/pico_stdio_usb/stdio_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#include "hardware/irq.h"

static mutex_t stdio_usb_mutex;
// if this crit_sec is initialized, we are not in periodic timer mode, and must make sure
// we don't either create multiple one shot timers, or miss creating one. this crit_sec
// is used to protect the one_shot_timer_pending flag
static critical_section_t one_shot_timer_crit_sec;
static volatile bool one_shot_timer_pending;
#ifndef NDEBUG
static uint8_t stdio_usb_core_num;
#endif
Expand All @@ -31,25 +36,41 @@ static_assert(PICO_STDIO_USB_LOW_PRIORITY_IRQ >= NUM_IRQS - NUM_USER_IRQS, "");
#else
static uint8_t low_priority_irq_num;
#endif
static bool using_periodic_timer;

static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
assert(stdio_usb_core_num == get_core_num()); // if this fails, you have initialized stdio_usb on the wrong core
int64_t repeat_time;
if (critical_section_is_initialized(&one_shot_timer_crit_sec)) {
critical_section_enter_blocking(&one_shot_timer_crit_sec);
one_shot_timer_pending = false;
critical_section_exit(&one_shot_timer_crit_sec);
repeat_time = 0; // don't repeat
} else {
repeat_time = PICO_STDIO_USB_TASK_INTERVAL_US;
}
irq_set_pending(low_priority_irq_num);
return using_periodic_timer ? PICO_STDIO_USB_TASK_INTERVAL_US : 0;
return repeat_time;
}

static void low_priority_worker_irq(void) {
// if the mutex is already owned, then we are in user code
// in this file which will do a tud_task itself, so we'll just do nothing
// until the next tick; we won't starve
static int foo;
if (mutex_try_enter(&stdio_usb_mutex, NULL)) {
tud_task();
mutex_exit(&stdio_usb_mutex);
} else {
// if we don't have a periodic timer, then we need to make sure the tud_task is tried again later
if (!using_periodic_timer) {
add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
if (critical_section_is_initialized(&one_shot_timer_crit_sec)) {
bool need_timer;
critical_section_enter_blocking(&one_shot_timer_crit_sec);
need_timer = !one_shot_timer_pending;
one_shot_timer_pending = true;
critical_section_exit(&one_shot_timer_crit_sec);
if (need_timer) {
add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
}
}
}
}
Expand Down Expand Up @@ -149,10 +170,11 @@ bool stdio_usb_init(void) {
if (irq_has_shared_handler(USBCTRL_IRQ)) {
// we can use a shared handler to notice when there may be work to do
irq_add_shared_handler(USBCTRL_IRQ, usb_irq, PICO_SHARED_IRQ_HANDLER_LOWEST_ORDER_PRIORITY);
using_periodic_timer = false;
critical_section_init_with_lock_num(&one_shot_timer_crit_sec, next_striped_spin_lock_num());
} else {
rc = add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true) >= 0;
using_periodic_timer = rc;
// we use initialization state of the one_shot_timer_critsec as a flag
memset(&one_shot_timer_crit_sec, 0, sizeof(one_shot_timer_crit_sec));
}
#endif
if (rc) {
Expand Down

0 comments on commit 6124bc9

Please sign in to comment.