Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Схема перключения задач "scmRTOS_CONTEXT_SWITCH_SCHEME == 1"
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > scmRTOS
Sergey Bold
Выявил неприятное поведение при переключении задач в ОС, порт под msp430X.

Использую схему переключения задач
Код
#define  scmRTOS_CONTEXT_SWITCH_SCHEME 1


В обработчике прерывания используется обвертка TISRW или TISRW_SS.
При выходе из обработчика прерывания вызывается планировщик Kernel.SchedISR();

Код
INLINE void ISR_Exit()
{
     DisableInterrupts();
     if(--Kernel.ISR_NestCount) return;
     Kernel.SchedISR();
}


Установиться флаг прерывания, и должно сработать прерывание по переключению задач.
Но, пока мы находились в предыдущем обработчике, приходит время сработать системному таймеру (его обработчику).
Выходит, по выходу из прерывания мы попадаем в более приоритетное прерывание от таймера, а в нем разрешаются прерывания

Код
#if scmRTOS_SYSTIMER_NEST_INTS_ENABLE == 1
    ENABLE_NESTED_INTERRUPTS();
#endif


и вот уже здесь вызовется обработчик прерывания по переключению задачи.
Ни к чему хорошему это не приводит, так как переменная ядра Kernel.ISR_NestCount будет инкрементирована и после переключения задач уже запорченой.
Как результат из задачи, куда мы переключились мы уже никогда не выйдем - зависнем.
Я правильно понял, что при scmRTOS_CONTEXT_SWITCH_SCHEME = 1 в других прерываниях никогда нельзя разрешать вложенных прерываний? Не только в системном таймере, а в любом прерывании, особенно если в нем используется TISRW или TISRW_SS?
dxp
Цитата(Sergey Bold @ Mar 5 2010, 18:26) *
Ни к чему хорошему это не приводит, так как переменная ядра Kernel.ISR_NestCount будет инкрементирована и после переключения задач уже запорченой.
Как результат из задачи, куда мы переключились мы уже никогда не выйдем - зависнем.
Я правильно понял, что при scmRTOS_CONTEXT_SWITCH_SCHEME = 1 в других прерываниях никогда нельзя разрешать вложенных прерываний? Не только в системном таймере, а в любом прерывании, особенно если в нем используется TISRW или TISRW_SS?

Интересный эффект. Навскидку, обычные прерывания (без контакта с ядром ос) не должны портить картину - ну, возникло внутри них прерывание переключения контекста, управление ушло в другой процесс... когда оно обратно вернется в этот прерванный, выполнение продолжится в этом прерывании. Т.е. с точки зрения целостности выполнения кода ничего фатального нет (хотя надо, конечно, проверять, возможно есть какие-то побочные эффекты). Но вот точки зрения программы это все очень неправильно и нехорошо. Во-первых, прерывание вместо того, чтобы выполниться быстренько, просто "зависло" на непредсказуемое время. Во-вторых, прерывания, как правило не очень реентерабельны. В общем, лучше так не делать.

И вообще, я бы рекомендовал следующее - если процессор аппаратно не поддерживает какие-то средства, то надо очень хорошо подумать при использовании программных "костылей", которые как-то выполняют требуемую функциональность. Это касается, как раз, прерываний: использование отдельного стека на процессоре, где нет аппаратной поддержки отдельного стека прерываний и вложенных прерываний при одноуровнвом неприоритетном контроллере прерываний. В частности, обсуждаемый MSP430 как раз не имеет ни того, ни другого.

Использование отдельного стека прерываний следует применять очень осторожно и соблюдая следующую рекомендацию: не писать в теле обработчика прерываний код, а поместить этот код в отдельную вызываемую функцию (ни в коем случае не встраиваемую, чтобы компилятор не видел ее потрохов в точке вызова) и в теле обработчика сделать вызов. Это на практике гарантирует, что компилятор не производит никаких финтов с указателем стека до вызова переключателя стеков (которые, если имеют место, то приводят к фатальным последствиям). Но лично я придерживаюсь другого подхода - не делать ISR длинным (долгим), выполнить в нем минимум функций и как можно быстрее отдать управление в основную программу (дабы не держать другие ISR) - это позволяет, как правило, и не расходовать много стека в ISR, поэтому необходимости в переключении на отдельный стек в прерывании не возникает.

С вложенными прерываниями - ровно то же самое. Если процессор не имеет аппаратного приоритетного контроллера прерываний, то надо несколько раз подумать об использовании вложенных прерываний. И не только с осью, но и без нее (лично налетал еще на AVR по внешнему прерыванию (в котором было разрешение вложенных сделано), когда из-за помехи на входной пин валился "лес" импульсов и прерывание получилось существенно рекурсивным, а стек не резиновым оказался smile.gif ). Стратегия та же самая - обеспечивать короткое время реакции на прерывание не путем разрешения вложенных, а тем, чтобы сделать прерывания короткими и быстрыми.

Ну, а если все же жизнь или предпочтения заставляют пользоваться программными аналогами отсутствующих средств, то надо хорошенько взвешивать решения и действовать осторожно, понимая, что это, в общем-то, не что иное, как хаки.
AHTOXA
Цитата(dxp @ Mar 7 2010, 11:35) *
не писать в теле обработчика прерываний код, а поместить этот код в отдельную вызываемую функцию (ни в коем случае не встраиваемую, чтобы компилятор не видел ее потрохов в точке вызова) и в теле обработчика сделать вызов. Это на практике гарантирует, что компилятор не производит никаких финтов с указателем стека до вызова переключателя стеков


В случае с msp-gcc - не гарантирует sad.gif Именно поэтому пришлось ввести доп. #define TISRW_SS_STACK_PAD, чтоб хоть как-то этим управлять. (Но это для просто msp).
dxp
Цитата(AHTOXA @ Mar 8 2010, 00:40) *
В случае с msp-gcc - не гарантирует sad.gif Именно поэтому пришлось ввести доп. #define TISRW_SS_STACK_PAD, чтоб хоть как-то этим управлять. (Но это для просто msp).

Т.е. если просто вызов:

Код
OS_INTERRUPT void SomeISR()
{
    TISRW_SS isrw;

    some_fun();
}

то все равно резервирует зачем-то в стеке место?
AHTOXA
Цитата(dxp @ Mar 8 2010, 18:31) *
все равно резервирует зачем-то в стеке место?


Да. Для массивного деструктора TISRW_SS.

вот это:
Код
interrupt(ADC_VECTOR) ADC12ISR(void)
{
    OS::TISRW_SS ISRW;
    adc.isr_handler();
}


даёт вот что:
Код
000016fa <ADC12ISR()>:
    16fa:    0f 12           push    r15        
    16fc:    0e 12           push    r14        
    16fe:    0d 12           push    r13        
    1700:    0c 12           push    r12        
    1702:    21 83           decd    r1        
    1704:    3f 40 ec 06     mov    #1772,    r15;#0x06ec
    1708:    df 53 00 00     inc.b    0(r15)    ;0x0000(r15)
    170c:    df 93 00 00     cmp.b    #1,    0(r15);r3 As==01, 0x0000(r15)
    1710:    1e 24           jz    $+62     ;abs 0x174e
    1712:    3f 40 a0 02     mov    #672,    r15;#0x02a0
    1716:    b0 12 8a 12     call    #0x128a    
    171a:    32 c2           dint            
    171c:    3f 40 ec 06     mov    #1772,    r15;#0x06ec
    1720:    ff 53 00 00     add.b    #-1,    0(r15);r3 As==11, 0x0000(r15)
    1724:    20 20           jnz    $+66     ;abs 0x1766
    1726:    5f 42 e0 06     mov.b    &0x06e0,r15    
    172a:    0f 5f           rla    r15        
    172c:    1f 4f e2 06     mov    1762(r15),r15;0x06e2(r15)
    1730:    2f 4f           mov    @r15,    r15    
    1732:    01 4f           mov    r15,    r1    
    1734:    5f 42 e1 06     mov.b    &0x06e1,r15    
    1738:    b0 12 7c 1a     call    #0x1a7c    
    173c:    5f 92 e0 06     cmp.b    &0x06e0,r15    
    1740:    12 24           jz    $+38     ;abs 0x1766
    1742:    c2 4f ed 06     mov.b    r15,    &0x06ed    
    1746:    f2 d0 03 00     bis.b    #3,    &0x0059;#0x0003
    174a:    59 00
    174c:    0c 3c           jmp    $+26     ;abs 0x1766
    174e:    5f 42 e0 06     mov.b    &0x06e0,r15    
    1752:    0f 5f           rla    r15        
    1754:    1e 4f e2 06     mov    1762(r15),r14;0x06e2(r15)
    1758:    0f 41           mov    r1,    r15    
    175a:    8e 4f 00 00     mov    r15,    0(r14);0x0000(r14)
    175e:    3f 40 fc 09     mov    #2556,    r15;#0x09fc
    1762:    01 4f           mov    r15,    r1    
    1764:    d6 3f           jmp    $-82     ;abs 0x1712
    1766:    21 53           incd    r1        
    1768:    3c 41           pop    r12        
    176a:    3d 41           pop    r13        
    176c:    3e 41           pop    r14        
    176e:    3f 41           pop    r15        
    1770:    00 13           reti
Sergey Bold
C переключением стека в прерывании для msp430 действительно как-то многовато кода получается, его не использую.
Его упомянул в связи с тем, что и для TISRW и для TISRW_SS в моем случае одинаковый эффект.
Как только в обработчике используется TISRW и разрешаются прерывания, то с большой вероятностью зависнет.
По этому, использовать схему переключения по прерыванию решил и дальше.
Ну а в обработчиках либо не использовать TISRW, либо не разрешать прерываний (я раньше использовал).
dxp
Цитата(Sergey Bold @ Mar 9 2010, 15:35) *
Ну а в обработчиках либо не использовать TISRW, либо не разрешать прерываний (я раньше использовал).

Да, я тоже предпочитаю не извращаться с возможностями, которых аппаратно нет. Тут все работает без сюрпризов.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.