Привествую всех.
Нашел новую ошибку в коде ОС. Ошибка не критичная, к падению не приводит.
Вкратце - если прерывание, будящее сервис происходит до того, как вызвалось
прерывание переключателя контекста, усыпляющее этот сервис, то пробуждение
сервиса затягивается (в худшем случае на один тик системного таймера).
Ситуация такая: некий процесс с приоритетом (для примера) pr7 запускает
периферию и уходит в спячку в ожидании, скажем, флага или освобождения mutex. В
спячку он уходит находясь в критической секции через OS::TService::suspend(),
там вызывается sched(). Внутри sched() он выясняет, что максимальный приоритет
из готовых у процесса с более низким приоритетом, например у Idle, заносит
prIDLE в SchedProcPriority, делает raise_context_switch() и разрешает прерывания
для вызова прерывания переключателя контекста.
Если во время действия критической секции сработало прерывание периферии, то в
этот момент вызывается его обработчик, он дергает сервис и в конце концов
вызывает resume_next_ready_isr(), который заносит процесс с pr7 в
ReadyProcessMap. Пока все идет как и задумывалось - переключатель контекста
имеет самый низкий приоритет чтобы избежать лишних перепланировок именно в такой
ситуации.
В обработчике прерывания периферии в деструкторе OS::TISRW вызывается
sched_isr(), там определяется самый приоритетный процесс (pr7) и происходит
сравнение: if(NextPrty != CurProcPriority), а они равны (напоминаю, что
переключатель контекста еще не вызвался, не отработал переключение в prIDLE и
CurProcPriority все еще равна pr7) и исходя из этого sched_isr() ничего не
делает и просто выходит из прерывания.
После этого наконец-то вызывается запланированный переключатель контекста,
который честно отрабатывает переключение контекста на IdleProc (ведь
SchedProcPriority у нас так и остался равным prIdle) и мы при готовом к
выполнению pr7 сидим в prIDLE до следующего прерывания c OS::TISRW или до
следующего тика системного таймера.
Предлагаемое решение - в sched_isr() вынести из-под условия SchedProcPriority =
NextPrty; т.е. заменить
void OS::TKernel::sched_isr()
{
uint_fast8_t NextPrty = highest_priority(ReadyProcessMap);
if(NextPrty != CurProcPriority)
{
SchedProcPriority = NextPrty;
raise_context_switch();
}
}
на
void OS::TKernel::sched_isr()
{
uint_fast8_t NextPrty = highest_priority(ReadyProcessMap);
SchedProcPriority = NextPrty;
if(NextPrty != CurProcPriority)
raise_context_switch();
}
Решение проверено, проблему решает. Есть какие-нибудь возражения?
--
Regards,
Sergey A. Borshch mailto:
sb...@sourceforge.net
SB ELDI ltd. Riga, Latvia