Skip to content

Use a linked list of background tasks to perform #2879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

#include "background.h"
#include "mpconfigboard.h"
#include "supervisor/background_callback.h"
#include "supervisor/cpu.h"
#include "supervisor/memory.h"
#include "supervisor/port.h"
Expand Down Expand Up @@ -100,8 +101,6 @@ void start_mp(supervisor_allocation* heap) {
reset_status_led();
autoreload_stop();

background_tasks_reset();

// Stack limit should be less than real stack size, so we have a chance
// to recover from limit hit. (Limit is measured in bytes.)
mp_stack_ctrl_init();
Expand Down Expand Up @@ -161,6 +160,8 @@ void stop_mp(void) {
MP_STATE_VM(vfs_cur) = vfs;
#endif

background_callback_reset();

gc_deinit();
}

Expand Down Expand Up @@ -492,6 +493,8 @@ void gc_collect(void) {
// have lost their references in the VM even though they are mounted.
gc_collect_root((void**)&MP_STATE_VM(vfs_mount_table), sizeof(mp_vfs_mount_t) / sizeof(mp_uint_t));

background_callback_gc_collect();

#if CIRCUITPY_DISPLAYIO
displayio_gc_collect();
#endif
Expand Down
54 changes: 35 additions & 19 deletions ports/atmel-samd/audio_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

#include "shared-bindings/audiocore/RawSample.h"
#include "shared-bindings/audiocore/WaveFile.h"
#include "supervisor/shared/tick.h"
#include "supervisor/background_callback.h"

#include "py/mpstate.h"
#include "py/runtime.h"
Expand Down Expand Up @@ -61,7 +61,6 @@ void audio_dma_free_channel(uint8_t channel) {
assert(audio_dma_allocated[channel]);
audio_dma_disable_channel(channel);
audio_dma_allocated[channel] = false;
supervisor_disable_tick();
}

void audio_dma_disable_channel(uint8_t channel) {
Expand All @@ -73,7 +72,6 @@ void audio_dma_disable_channel(uint8_t channel) {
void audio_dma_enable_channel(uint8_t channel) {
if (channel >= AUDIO_DMA_CHANNEL_COUNT)
return;
supervisor_enable_tick();
dma_enable_channel(channel);
}

Expand Down Expand Up @@ -259,6 +257,15 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
dma->beat_size *= 2;
}

#ifdef SAM_D5X_E5X
int irq = dma->event_channel < 4 ? EVSYS_0_IRQn + dma->event_channel : EVSYS_4_IRQn;
#else
int irq = EVSYS_IRQn;
#endif

NVIC_DisableIRQ(irq);
NVIC_ClearPendingIRQ(irq);

DmacDescriptor* first_descriptor = dma_descriptor(dma_channel);
setup_audio_descriptor(first_descriptor, dma->beat_size, output_spacing, output_register_address);
if (single_buffer) {
Expand All @@ -281,6 +288,8 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
dma_configure(dma_channel, dma_trigger_source, true);
audio_dma_enable_channel(dma_channel);

NVIC_EnableIRQ(irq);

return AUDIO_DMA_OK;
}

Expand Down Expand Up @@ -321,9 +330,6 @@ void audio_dma_reset(void) {
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
audio_dma_state[i] = NULL;
audio_dma_pending[i] = false;
if (audio_dma_allocated[i]) {
supervisor_disable_tick();
}
audio_dma_allocated[i] = false;
audio_dma_disable_channel(i);
dma_descriptor(i)->BTCTRL.bit.VALID = false;
Expand All @@ -343,29 +349,39 @@ bool audio_dma_get_playing(audio_dma_t* dma) {
return (status & DMAC_CHINTFLAG_TERR) == 0;
}

// WARN(tannewt): DO NOT print from here. Printing calls background tasks such as this and causes a
// stack overflow.
// WARN(tannewt): DO NOT print from here, or anything it calls. Printing calls
// background tasks such as this and causes a stack overflow.
STATIC void dma_callback_fun(void *arg) {
audio_dma_t* dma = arg;
if (dma == NULL) {
return;
}

audio_dma_load_next_block(dma);
}

void audio_dma_background(void) {
void evsyshandler_common(void) {
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
if (audio_dma_pending[i]) {
continue;
}
audio_dma_t* dma = audio_dma_state[i];
if (dma == NULL) {
continue;
}

bool block_done = event_interrupt_active(dma->event_channel);
if (!block_done) {
continue;
}

// audio_dma_load_next_block() can call Python code, which can call audio_dma_background()
// recursively at the next background processing time. So disallow recursive calls to here.
audio_dma_pending[i] = true;
audio_dma_load_next_block(dma);
audio_dma_pending[i] = false;
background_callback_add(&dma->callback, dma_callback_fun, (void*)dma);
}
}

#ifdef SAM_D5X_E5X
void EVSYS_0_Handler(void) { evsyshandler_common(); }
void EVSYS_1_Handler(void) { evsyshandler_common(); }
void EVSYS_2_Handler(void) { evsyshandler_common(); }
void EVSYS_3_Handler(void) { evsyshandler_common(); }
void EVSYS_4_Handler(void) { evsyshandler_common(); }
#else
void EVSYS_Handler(void) { evsyshandler_common(); }
#endif

#endif
2 changes: 2 additions & 0 deletions ports/atmel-samd/audio_dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "py/obj.h"
#include "shared-module/audiocore/RawSample.h"
#include "shared-module/audiocore/WaveFile.h"
#include "supervisor/background_callback.h"

typedef struct {
mp_obj_t sample;
Expand All @@ -49,6 +50,7 @@ typedef struct {
uint8_t* second_buffer;
bool first_descriptor_free;
DmacDescriptor* second_descriptor;
background_callback_t callback;
} audio_dma_t;

typedef enum {
Expand Down
52 changes: 5 additions & 47 deletions ports/atmel-samd/background.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,63 +39,21 @@
#include "shared-module/displayio/__init__.h"
#endif

volatile uint64_t last_finished_tick = 0;

bool stack_ok_so_far = true;

static bool running_background_tasks = false;

#ifdef MONITOR_BACKGROUND_TASKS
// PB03 is physical pin "SCL" on the Metro M4 express
// so you can't use this code AND an i2c peripheral
// at the same time unless you change this
STATIC void start_background_task(void) {
void port_start_background_task(void) {
REG_PORT_DIRSET1 = (1<<3);
REG_PORT_OUTSET1 = (1<<3);
}

STATIC void finish_background_task(void) {
void port_finish_background_task(void) {
REG_PORT_OUTCLR1 = (1<<3);
}
#else
STATIC void start_background_task(void) {}
STATIC void finish_background_task(void) {}
void port_start_background_task(void) {}
void port_finish_background_task(void) {}
#endif

void background_tasks_reset(void) {
running_background_tasks = false;
}

void run_background_tasks(void) {
// Don't call ourselves recursively.
if (running_background_tasks) {
return;
}

start_background_task();

assert_heap_ok();
running_background_tasks = true;

#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
audio_dma_background();
#endif
#if CIRCUITPY_DISPLAYIO
displayio_background();
#endif

#if CIRCUITPY_NETWORK
network_module_background();
#endif
filesystem_background();
usb_background();
running_background_tasks = false;
assert_heap_ok();

last_finished_tick = port_get_raw_ticks(NULL);
finish_background_task();
}

bool background_tasks_ok(void) {
return port_get_raw_ticks(NULL) - last_finished_tick < 1024;
}
void port_background_task(void) {}
5 changes: 0 additions & 5 deletions ports/atmel-samd/background.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,4 @@

#include <stdbool.h>

void background_tasks_reset(void);
void run_background_tasks(void);
void run_background_vm_tasks(void);
bool background_tasks_ok(void);

#endif // MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H
7 changes: 7 additions & 0 deletions ports/atmel-samd/boards/uchip/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@ CHIP_FAMILY = samd21
INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = NONE
CIRCUITPY_FULL_BUILD = 0

# Tweak inlining depending on language.
ifeq ($(TRANSLATION), zh_Latn_pinyin)
CFLAGS_INLINE_LIMIT = 45
else
CFLAGS_INLINE_LIMIT = 70
endif
3 changes: 2 additions & 1 deletion ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "hpl_gclk_config.h"

#include "shared-bindings/time/__init__.h"
#include "supervisor/shared/tick.h"
#include "supervisor/shared/translate.h"

#ifdef SAMD21
Expand Down Expand Up @@ -132,7 +133,7 @@ void frequencyin_interrupt_handler(uint8_t index) {
}

// Check if we've reached the upper limit of detection
if (!background_tasks_ok() || self->errored_too_fast) {
if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
self->errored_too_fast = true;
frequencyin_emergency_cancel_capture(i);
}
Expand Down
3 changes: 2 additions & 1 deletion ports/atmel-samd/common-hal/pulseio/PulseIn.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "samd/timers.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/pulseio/PulseIn.h"
#include "supervisor/shared/tick.h"
#include "supervisor/shared/translate.h"

// This timer is shared amongst all PulseIn objects as a higher resolution clock.
Expand Down Expand Up @@ -87,7 +88,7 @@ void pulsein_interrupt_handler(uint8_t channel) {
uint32_t current_count = tc->COUNT16.COUNT.reg;

pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
if (!background_tasks_ok() || self->errored_too_fast) {
if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
self->errored_too_fast = true;
common_hal_pulseio_pulsein_pause(self);
return;
Expand Down
12 changes: 7 additions & 5 deletions ports/atmel-samd/supervisor/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include "hpl/gclk/hpl_gclk_base.h"
#include "hal_gpio.h"
#include "lib/tinyusb/src/device/usbd.h"
#include "supervisor/background_callback.h"
#include "supervisor/usb.h"

void init_usb_hardware(void) {
#ifdef SAMD21
Expand Down Expand Up @@ -61,24 +63,24 @@ void init_usb_hardware(void) {

#ifdef SAMD21
void USB_Handler(void) {
tud_int_handler(0);
usb_irq_handler();
}
#endif

#ifdef SAM_D5X_E5X
void USB_0_Handler (void) {
tud_int_handler(0);
usb_irq_handler();
}

void USB_1_Handler (void) {
tud_int_handler(0);
usb_irq_handler();
}

void USB_2_Handler (void) {
tud_int_handler(0);
usb_irq_handler();
}

void USB_3_Handler (void) {
tud_int_handler(0);
usb_irq_handler();
}
#endif
24 changes: 3 additions & 21 deletions ports/cxd56/background.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,6 @@
#include "supervisor/filesystem.h"
#include "supervisor/shared/stack.h"

static bool running_background_tasks = false;

void background_tasks_reset(void) {
running_background_tasks = false;
}

void run_background_tasks(void) {
// Don't call ourselves recursively.
if (running_background_tasks) {
return;
}

assert_heap_ok();
running_background_tasks = true;

usb_background();
filesystem_background();

running_background_tasks = false;
assert_heap_ok();
}
void port_background_task(void) {}
void port_start_background_task(void) {}
void port_finish_background_task(void) {}
3 changes: 0 additions & 3 deletions ports/cxd56/background.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,4 @@
#ifndef MICROPY_INCLUDED_CXD56_BACKGROUND_H
#define MICROPY_INCLUDED_CXD56_BACKGROUND_H

void background_tasks_reset(void);
void run_background_tasks(void);

#endif // MICROPY_INCLUDED_CXD56_BACKGROUND_H
23 changes: 4 additions & 19 deletions ports/esp32s2/background.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,12 @@
#include "shared-module/displayio/__init__.h"
#endif

static bool running_background_tasks = false;

void background_tasks_reset(void) {
running_background_tasks = false;
}

void run_background_tasks(void) {
// Don't call ourselves recursively.
if (running_background_tasks) {
return;
}

void port_background_task(void) {
// Zero delay in case FreeRTOS wants to switch to something else.
vTaskDelay(0);
running_background_tasks = true;
filesystem_background();
}

#if CIRCUITPY_DISPLAYIO
displayio_background();
#endif
running_background_tasks = false;
void port_start_background_task(void) {}

assert_heap_ok();
}
void port_finish_background_task(void) {}
Loading