-
Notifications
You must be signed in to change notification settings - Fork 0
fix (tested on PCU, LV-BMS, HV-BMS and LCU) #594
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
base: development
Are you sure you want to change the base?
Changes from all commits
e9cbbdb
773c446
5418b89
7231bfd
f60c159
643d2c8
8629f5e
175dc80
9862b38
cb381bf
1c489af
f1171b4
3c16640
e49afea
fb9fa43
3eb88ab
6f2eaf8
d07b4bb
c199f42
d40395e
df98f27
b0a91cd
6dd5494
1d96793
6e500e4
7a58320
8cad77f
379319e
8212c6c
d14ece9
581bb19
29467e2
b24b1fe
b6ead59
97473f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| release: patch | ||
| summary: fix remaining scheduler race conditions | ||
|
|
||
| Currently only tested on LCU despite title saying otherwise (too many changes to say it was tested) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| /* | ||
| * Scheduler.hpp | ||
| * Scheduler.cpp | ||
| * | ||
| * Created on: 17 nov. 2025 | ||
| * Author: Victor (coauthor Stephan) | ||
|
|
@@ -31,23 +31,6 @@ uint64_t Scheduler::global_tick_us_{0}; | |
| uint32_t Scheduler::current_interval_us_{0}; | ||
| uint16_t Scheduler::timeout_idx_{1}; | ||
|
|
||
| inline uint8_t Scheduler::get_at(uint8_t idx) { | ||
| int word_idx = idx > 7; | ||
| uint32_t shift = (idx & 7) << 2; | ||
| return (((uint32_t*)&sorted_task_ids_)[word_idx] & (0x0F << shift)) >> shift; | ||
| } | ||
| inline void Scheduler::set_at(uint8_t idx, uint8_t id) { | ||
| uint32_t shift = idx * 4; | ||
| uint64_t clearmask = ~(0xFF << shift); | ||
| Scheduler::sorted_task_ids_ = (sorted_task_ids_ & clearmask) | (id << shift); | ||
| } | ||
| inline uint8_t Scheduler::front_id() { return *((uint8_t*)&sorted_task_ids_) & 0xF; } | ||
| inline void Scheduler::pop_front() { | ||
| // O(1) remove of logical index 0 | ||
| Scheduler::active_task_count_--; | ||
| Scheduler::sorted_task_ids_ >>= 4; | ||
| } | ||
|
|
||
| // ---------------------------- | ||
|
|
||
| inline void Scheduler::global_timer_disable() { | ||
|
|
@@ -159,21 +142,29 @@ void Scheduler::update() { | |
| while (ready_bitmap_ != 0u) { | ||
| uint32_t bit_index = static_cast<uint32_t>(__builtin_ctz(ready_bitmap_)); | ||
|
|
||
| CLEAR_BIT(ready_bitmap_, 1u << bit_index); | ||
|
|
||
| Task& task = tasks_[bit_index]; | ||
|
|
||
| task.callback(); | ||
|
|
||
| SchedLock(); | ||
| CLEAR_BIT(ready_bitmap_, 1u << bit_index); | ||
| if (!task.repeating) [[unlikely]] { | ||
| SchedLock(); | ||
| release_slot(static_cast<uint8_t>(bit_index)); | ||
| SchedUnlock(); | ||
| } | ||
| SchedUnlock(); | ||
| } | ||
| } | ||
|
|
||
| uint64_t Scheduler::get_global_tick() { | ||
| SchedLock(); | ||
| uint64_t val = global_tick_us_ + Scheduler_global_timer->CNT; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No entiendo porque esto necesita un lock, la lectura del CNT es atomica es imposible que esto se corrompa
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. la lectura del CNT sí pero la lectura de global_tick_us_ no pq es uint64_t |
||
| SchedUnlock(); | ||
| return val; | ||
| } | ||
|
|
||
| inline uint8_t Scheduler::allocate_slot() { | ||
| uint32_t idx = __builtin_ffs(Scheduler::free_bitmap_) - 1; | ||
| if (idx > static_cast<int>(Scheduler::kMaxTasks)) [[unlikely]] | ||
| if (idx >= Scheduler::kMaxTasks) [[unlikely]] | ||
| return static_cast<uint8_t>(Scheduler::INVALID_ID); | ||
| Scheduler::free_bitmap_ &= ~(1UL << idx); | ||
| return static_cast<uint8_t>(idx); | ||
|
|
@@ -272,9 +263,12 @@ void Scheduler::schedule_next_interval() { | |
| return; | ||
| } | ||
|
|
||
| SchedLock(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. esto esta dentro del interrupt del timer no tiene sentido hacer disable al timer |
||
| uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] | ||
| Task& next_task = tasks_[next_id]; | ||
| int32_t diff = (int32_t)(next_task.next_fire_us - static_cast<uint32_t>(global_tick_us_)); | ||
| SchedUnlock(); | ||
|
|
||
| if (diff >= -1 && diff <= 1) [[unlikely]] { | ||
| current_interval_us_ = 1; | ||
| SET_BIT(Scheduler_global_timer->EGR, TIM_EGR_UG); // This should cause an interrupt | ||
|
|
@@ -284,18 +278,18 @@ void Scheduler::schedule_next_interval() { | |
| } else { | ||
| current_interval_us_ = static_cast<uint32_t>(diff); | ||
| } | ||
| Scheduler_global_timer->ARR = static_cast<uint32_t>(current_interval_us_ - 1u); | ||
| while (Scheduler_global_timer->CNT > Scheduler_global_timer->ARR) [[unlikely]] { | ||
| uint32_t offset = Scheduler_global_timer->CNT - Scheduler_global_timer->ARR; | ||
| current_interval_us_ = offset; | ||
| SET_BIT(Scheduler_global_timer->EGR, TIM_EGR_UG); // This should cause an interrupt | ||
| Scheduler_global_timer->CNT = Scheduler_global_timer->CNT + offset; | ||
|
|
||
| Scheduler_global_timer->ARR = current_interval_us_ - 1u; | ||
victor-Lopez25 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (Scheduler_global_timer->CNT > Scheduler_global_timer->ARR) [[unlikely]] { | ||
| uint32_t cnt_temp = Scheduler_global_timer->CNT; | ||
| Scheduler_global_timer->CNT = 0; | ||
| global_tick_us_ += cnt_temp; | ||
| } | ||
| } | ||
| Scheduler::global_timer_enable(); | ||
victor-Lopez25 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| void Scheduler::on_timer_update() { | ||
| inline void Scheduler::on_timer_update() { | ||
| global_tick_us_ += current_interval_us_; | ||
|
|
||
| while (active_task_count_ > 0) { // Pop all due tasks, several might be due in the same tick | ||
|
|
@@ -305,15 +299,20 @@ void Scheduler::on_timer_update() { | |
| if (diff > 0) [[likely]] { | ||
| break; // Task is in the future, stop processing | ||
| } | ||
| pop_front(); | ||
| uint32_t task_bit = 1u << candidate_id; | ||
|
|
||
| SchedLock(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tampoco tiene sentido hacerle disable al timer dentro del interrupt del timer
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tengo que probar si realmente no hace falta, pq es una de las primeras cosas que probé ayer en las placas y la dejé
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Según la prueba de Boris en la LCU no hace falta pero voy a probarlo mañana (?) en las otras placas también |
||
| pop_front(); | ||
| // mark task as ready | ||
| SET_BIT(ready_bitmap_, 1u << candidate_id); | ||
|
|
||
| if ((ready_bitmap_ & task_bit) != 0) [[unlikely]] { | ||
| ErrorHandler("Too slow, could not execute task %u in time", candidate_id); | ||
| } | ||
| SET_BIT(ready_bitmap_, task_bit); | ||
| if (task.repeating) [[likely]] { | ||
| task.next_fire_us = static_cast<uint32_t>(global_tick_us_ + task.period_us); | ||
| insert_sorted(candidate_id); | ||
| } | ||
| SchedUnlock(); | ||
| } | ||
|
|
||
| schedule_next_interval(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No me mola mucho la verdad que el bitmap se limpie despues del callback, si hay problemas de rendimiento y el timer vuelve a hacerle set a la tarea la segunda ejecucion no se ejecuta, por lo demas no veo muchos mas problemas a hacerle clear despues del callback, se podria quedar asi pero solo digo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Era por poner un solo lock, si lo ves mejor poner dos locks y así poder hacerlo antes lo puedo cambiar