Fix: interrupt preemption

This commit is contained in:
2025-04-15 17:22:45 +08:00
parent 89ff8a018d
commit c4a44542ef
8 changed files with 93 additions and 51 deletions

View File

@@ -11,6 +11,8 @@ typedef struct interrupt {
uint64_t priority;
interrupt_callback_func_t func;
uint64_t param;
int is_start;
} interrupt_t;
void add_interrupt_task(uint64_t priority,

View File

@@ -73,16 +73,27 @@ void add_interrupt_task(uint64_t priority,
.priority = priority,
.func = func,
.param = param
.param = param,
.is_start = false,
};
global_interrupt_pool = _merge(global_interrupt_pool, newint);
while (global_interrupt_pool) {
// LOG("check interrupt"); DEBUG_EXCEP(global_interrupt_pool->priority);
if (global_interrupt_pool->is_start)
return;
global_interrupt_pool->is_start = true;
global_interrupt_pool->func(global_interrupt_pool->param);
global_interrupt_pool = _pop(global_interrupt_pool);
}
}
void init_interrupt(void)
{
W_SYSREG(cntp_ctl_el0, 1);
_enable_interrupt();
_enable_timer_irq(true);
}
void irq_handler(void)
@@ -99,6 +110,8 @@ void irq_handler(void)
void wfe(void)
{
return; // do nothing for now
if (!global_interrupt_pool) {
// asm volatile("wfe");
asm volatile("nop");

View File

@@ -1,4 +1,3 @@
#include <uart.h>
#include <logger.h>
#include <errcode.h>
#include <utils.h>

View File

@@ -118,16 +118,12 @@ uint64_t _allocate_page(size_t req, int idx, uint64_t l, uint64_t r)
switch (CUR->state) {
case PAGE_FREE:
if (req == sz) {
LOG("page allocated");
LOG(l);
DEBUG_MEM(r);
LOG("page allocated"); LOG(l); DEBUG_MEM(r);
CUR->state = PAGE_ALLOCATED;
CUR->size = 0;
return l;
}
LOG("page divided");
LOG(l);
DEBUG(r);
LOG("page divided"); LOG(l); DEBUG_MEM(r);
LCH->state = RCH->state = PAGE_FREE;
LCH->size = m - l;
RCH->size = r - m;

View File

@@ -125,6 +125,7 @@ static inline
void _settimeout_cb_func(uint64_t args)
{
vector_t *v = (void *)args;
uart_puts("timeout: ");
for (int i = 2; i < (int)v->size; ++i) {
uart_puts(VEC_AT(char, v, i));
uart_puts(" ");

View File

@@ -47,7 +47,7 @@ timer_t *_pop(timer_t *t)
}
static inline
void _set_timer_interrupt()
void _check_enable_timer()
{
if (global_timer) {
uint64_t cntpct_el0;
@@ -59,8 +59,9 @@ void _set_timer_interrupt()
else
W_SYSREG(cntp_cval_el0, global_timer->data.firing_tick);
_enable_timer_irq(true);
}
W_SYSREG(cntp_ctl_el0, 1);
} else
W_SYSREG(cntp_ctl_el0, 0);
}
static inline
@@ -87,8 +88,23 @@ void add_timer_task(task_t task)
global_timer = _merge(global_timer, newtimer);
_traverse(global_timer);
_set_timer_interrupt();
// _traverse(global_timer);
_check_enable_timer();
}
typedef struct {
interrupt_callback_func_t func;
uint64_t param;
} _timer_task_wrapper_param_t;
static inline
void _timer_task_wrapper(uint64_t param)
{
_timer_task_wrapper_param_t *data = (void *)param;
data->func(data->param);
kfree(data);
_enable_timer_irq(true);
}
void timer_irq_handler(void)
@@ -100,9 +116,15 @@ void timer_irq_handler(void)
LOG("timer irq"); DEBUG_EXCEP(cntpct_el0);
if (global_timer) {
add_interrupt_task(20, global_timer->data.func, global_timer->data.param);
global_timer = _pop(global_timer);
}
_timer_task_wrapper_param_t *param =
kmalloc(sizeof(_timer_task_wrapper_param_t));
*param = (_timer_task_wrapper_param_t){
.func = global_timer->data.func,
.param = global_timer->data.param,
};
add_interrupt_task(20, _timer_task_wrapper, (uint64_t)param);
_set_timer_interrupt();
global_timer = _pop(global_timer);
_check_enable_timer();
}
}

View File

@@ -29,6 +29,8 @@ size_t (*uart_putb)(const uint8_t *bytes, size_t len) = uart_putb_sync;
size_t (*uart_getb)(uint8_t *bytes, size_t len) = uart_getb_sync;
int is_uart_inited = false;
int is_uart_in_interrupt_queue = false;
ringbuffer_t *uart_readbuf;
ringbuffer_t *uart_writebuf;
@@ -83,37 +85,47 @@ void uart_init(void)
is_uart_inited = true;
}
void uart_transmit_interrupt_handler()
static inline
void _enable_uart_interrupt()
{
_uart_enable_receive_interrupt(true);
if (uart_writebuf->size > 0)
_uart_write_data(ringbuffer_bump(uart_writebuf));
_uart_enable_transmit_interrupt(true);
}
typedef struct {
ringbuffer_t *buf;
uint8_t val;
} uart_interrupt_callback_payload_t;
static inline
void uart_receive_interrupt_callback(uint64_t param)
void _uart_transmit_interrupt_callback(uint64_t)
{
uart_interrupt_callback_payload_t *payload = (void *)param;
ringbuffer_push(payload->buf, payload->val);
kfree(payload);
_uart_write_data(ringbuffer_bump(uart_writebuf));
is_uart_in_interrupt_queue = false;
_enable_uart_interrupt();
}
void uart_receive_interrupt_handler()
static inline
void _uart_transmit_interrupt_handler()
{
if (uart_writebuf->size > 0) {
is_uart_in_interrupt_queue = true;
add_interrupt_task(11, _uart_transmit_interrupt_callback, 0x0);
}
}
static inline
void _uart_receive_interrupt_callback(uint64_t)
{
ringbuffer_push(uart_readbuf, _uart_read_data());
is_uart_in_interrupt_queue = false;
_enable_uart_interrupt();
}
static inline
void _uart_receive_interrupt_handler()
{
if (uart_readbuf->size < uart_readbuf->cap) {
uint8_t b = _uart_read_data();
uart_interrupt_callback_payload_t *param = kmalloc(
sizeof(uart_interrupt_callback_payload_t));
*param = (uart_interrupt_callback_payload_t){
.buf = uart_readbuf,
.val = b,
};
add_interrupt_task(10, uart_receive_interrupt_callback, (uint64_t)param);
is_uart_in_interrupt_queue = true;
add_interrupt_task(12, _uart_receive_interrupt_callback, 0x0);
}
}
@@ -121,14 +133,11 @@ void uart_irq_handler(void)
{
_uart_enable_receive_interrupt(false);
_uart_enable_transmit_interrupt(false);
if (_uart_receive_interrupt())
uart_receive_interrupt_handler();
_uart_receive_interrupt_handler();
if (_uart_transmit_interrupt())
uart_transmit_interrupt_handler();
_uart_enable_receive_interrupt(true);
if (uart_writebuf->size > 0)
_uart_enable_transmit_interrupt(true);
_uart_transmit_interrupt_handler();
}
size_t uart_putb_async(const uint8_t *bytes, size_t len)
@@ -137,8 +146,8 @@ size_t uart_putb_async(const uint8_t *bytes, size_t len)
for (; sentlen < len; ++bytes, ++sentlen)
ringbuffer_push(uart_writebuf, *bytes);
if (uart_writebuf->size > 0)
_uart_enable_transmit_interrupt(true);
if (!is_uart_in_interrupt_queue && uart_writebuf)
_enable_uart_interrupt();
return sentlen;
}