Перейти к содержанию
    

Cortex M3, PendSV и переключение контекста

Привет!

В Cortex-M3 есть прерывание PendSV, в чем его основная цель? В доках нашел "PendSV is an interrupt-driven request for system-level service. In an OS environment, use PendSV for context switching when no other exception is active". Т.е. как я понял оно нужно (рекомендовано ARM-ом) для выполнения переключения контекста операционной системой. Но в операционке все равно задействован SysTick Timer и его прерывание для проверки необходимости переключения на каждый тик, почему контекст нельзя переключать в нем, зачем дополнительно нужно PendSV?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но в операционке все равно задействован SysTick Timer и его прерывание для проверки необходимости переключения на каждый тик, почему контекст нельзя переключать в нем, зачем дополнительно нужно PendSV?

Необходимость переключения контекста в операционной системе может возникать далеко не только по тику таймера. Поэтому данная возможность должна быть доступна в произвольный момент времени.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Необходимость переключения контекста в операционной системе может возникать далеко не только по тику таймера. Поэтому данная возможность должна быть доступна в произвольный момент времени.

 

Именно поэтому таймер лишь генерирует запрос на переключение. Аналогичный запрос может быть сгенерирован и "изнутри" ОС, например, при освобождении какого-то ресурса, ожидаемого процессом. А вот обработка запроса переключения производится из PendSV. Операция вынесена в прерывание чтобы была возможность обеспечить атомарность действий.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Весь сок PendSV,SVC и Systick (pendSTset) поймете, когда захотите lock-free ось написать :)

штука крутая, мне понравилось

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Операция вынесена в прерывание чтобы была возможность обеспечить атомарность действий.

Дело не в атомарности!

Это запрос на переключение контекста, который будет выполнен после выхода из критического участка (где прерывания запрещены) или после выхода из прерывания от устройства где получены данные для приоритетной задачи и т.п.

Очень удобная вещь! А учитывая методы входа/выхода кортекса в прерывания позволяет быстро и удобно переключить задачу после обработки прерываний!

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это запрос на переключение контекста, который будет выполнен после выхода из критического участка

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

... у меня там висит обработчик очереди запросов от хардварных прерываний(у которых приоритет всегда выше,чем у pendsv,systick) на выполнения системных функций.

А можно поинтересоваться в общих чертах, что за прерывания и какие системные функции?

Кроме того, если приоритет выше, значит они должны прерывать pendsv,systick, так?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А можно поинтересоваться в общих чертах, что за прерывания

ну там от DMA, SPI, UART, USB итд.

 

и какие системные функции?

ну там SignalSemaphore, SetSemaphore, CloseMutex итд

 

Кроме того, если приоритет выше, значит они должны прерывать pendsv,systick, так?

да, совершенно верно. И их могут прервать прерывания с еще вышим припритетом.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ну там SignalSemaphore, SetSemaphore, CloseMutex итд

А смысл использовать для этих целей PendSV?

Для этого есть SVCall.

А PendSV это асинхронный запрос, который или из прерывания запрашивается или из критической секции. т.е. из участка кода с более высоким приоритетом чем PendSV иначе PendSV будет себя вести как SVCall.

 

В System Level Programmers’ Model есть глава

SVCall, PendSV and critical region code avoidance

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А смысл использовать для этих целей PendSV?

Для этого есть SVCall.

А PendSV это асинхронный запрос, который или из прерывания запрашивается

так речь и шла о прерываниях:

у меня там висит обработчик очереди запросов от хардварных прерываний(у которых приоритет всегда выше,чем у pendsv,systick) на выполнения системных функций

доступ к системным функциям из обычных тредов ессно через SVC

а критических секций нет, они на cortex-m3 просто не нужны.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы код для семафоров, в таком случае, свой используете? Там же по умолчанию критические секции расставлены.

Очередь запросов у вас не переполняется? В чем вообще плюсы от использования lock free оси? Не проще ли использовать QP Framework - там имхо тоже lock free, но честнее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы код для семафоров, в таком случае, свой используете?
конечно свой. ось вообще вся своя.

Там же по умолчанию критические секции расставлены.
у меня по умолчанию ничего не расставлено, по умолчанию у меня пустая папка, где со временем вырастают файлики с кодом :)

Очередь запросов у вас не переполняется?
нет. во первых ошибка переполняния обрабатывается и выводится сообщение. во вторых размер очереди выбирается так, чтобы хватило в самом худшем случаи. контроллеры с меньше,чем 64кб оперативки не беру.

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

Потом гораздо меньше лажи с приоритетами... вернее если код не lock-free, то и приоритеты прерываний можно засунуть по-дальше, толку от них мало.

Потом lock-free у меня только запись в очередь, а чтение и остальные функции wait-free.

Вообще про плюсы и минусы lock-free/wait-free можно почитать в инете, но все зависит от конкретной платформы. на armv7 мне показалось, что это круто, и я не ошибся (касается конкретно только моих проектов).

Не проще ли использовать QP Framework - там имхо тоже lock free, но честнее.
мне сложнее, это надо вьезжать в этот фреймворк,материть его,если что-то мне там не нра итп..

Написать ось, которая будет соответствовать моим требованием займет не более недели времени, что гораздо проще и интереснее, чем драконится с каким-то фреймворком недельку-вторую

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

brag, можете коротенький пример последовательности переключения контекста привести, на примере 2 функций (из одной в другую)?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

конкретный пример вотъ. код вроде простой и понятный...

 

собственно переключение. приоритет самый низкий

F_NAKED void ePendSV(void){
    register U32 rpsp asm("r3");
    asm volatile(" mrs %0,PSP; stmdb %0!,{r4-r11,lr}" :"=r"(rpsp));
    pRunTcb->psp=rpsp;
    pRunTcb=pReadyTcb;
    rpsp=pRunTcb->psp;
    asm volatile(" ldmia %0!,{r4-r11,lr}; msr PSP,%0; bx lr" :"+r"(rpsp));
}

naked и асм.вставки тк gcc тупой не умеет юзать ldm/stm. а кусок сишного кода тк леньки мне и синтакс gas - бей головой дуба :D писать не удобно

также тут исключен код, перегружающий MPU регионы, нету у STM32F1 MPU. на NXP моя ось еще и защищенная ;)

 

постановка задачи,готовой к выполнению в очередь. используется внутри практически всех системных функций (CreateThread,OpenMutex итд). приоритет этих функций всегда выше или равен PendSV.

void tcbEnqueueReady(t_bragOsTcb *tcb){
    U32 prio;
    prio=tcb->priority;
    cdllEnqueue(&readyQueue[prio],&tcb->queueNode);
    readyPrioMsk|=1<<(31-prio);
    if(prio<pReadyTcb->priority){
        pReadyTcb=tcb;
        PendSVset();
    }
}

 

Системные функции могут вызыватся только:

1. из SVC, в данном случаи приоритет выше, чем у PendSV. сделаете иначе - попадете на оооочень неприятные грабли! лень расписывать(много невсемпонятного текста) почему, но скажу пару ключевых слов: Приоритет, Стек, Tail-chainning. Если интересно - порисуйте диаграмки последовательности выполнения и все станет понятно.

2. из Systick. приоритет равен PendSV

Ессно выше приведенный код получается автоматически защищен от race-conditions.

 

Удаление задачи из очереди. Здесь PendSVset выполняется всегда, тк так сложилось, что у меня эта функция удаляет из очереди только ту задачу, которая в данный момент выполняется. но с ее помощью можно удалить любую задачу из очереди, при этом можно сделать проверку, чтобы даром не выполнять пустое переключение контекста,не влияющее на ход работы системы.

void tcbDequeueReady(t_bragOsTcb *tcb){
    U32 prio;
    cdllRemove(&tcb->queueNode);
    prio=tcb->priority;
    if(cdllIsEmpty(&readyQueue[prio]))readyPrioMsk&=~(1<<(31-prio));
    pReadyTcb=getNextReadyTcb();
    PendSVset();
}

 

cdllХххх - работа с обычным двусвязным списком.

getNextReadyTcb - достает из головы этого самого списка(у меня их 32,на каждый тредовый приоритет свой список,выбирается не пустой список самого высокого приоритета) адрес tcb

PendSVset используется только в этих двух функциях, ну и еще при инициализации системы, чтобы переключится на первый тред.

 

ну и самый сок, добавление запроса в lock-free очередь. может использоватся любым прерыванием с любым приоритетом.

int SrqEnqueue(U32 a0,U32 a1,U32 svc){
    register U32 r0 asm("r0");
    register U32 r1 asm("r1");
    U32 tail,newtail;
    
   // lockless enqueue
    do{
        asm volatile("ldrex %0,%1" :"=r"(tail) :"m"(srqQueue.tail));
        newtail=(tail+1)%MAX_SRQ_QUEUE_ITEMS;
        if(newtail==srqQueue.head)return ERR_QUEUE_FULL;
        asm volatile("strex %0,%2,%1" :"=&r"(r),"=m"(srqQueue.tail) :"r"(newtail));
    }while(r);
    
   // write data
    r0=a0;r1=a1;
    asm volatile("stmia %3,{%0,%1,%2}" : :"r"(r0),"r"(r1),"r"(svc),"r"(&srqQueue.buf[tail]) :"memory");
    PendSTset();
    return 0;
}

MAX_SRQ_QUEUE_ITEMS кратно степени двойки - % заменяется компиллером на обычный AND.

PendSTset - гыгы :) там выгрузка этой очереди, и системный таймер там же. не хотелось нагружать маленький красивенький pendsv всякой ерундой, пусть pendsv будет именно pendsv и не более ;)

void eSystick(void){
.....    блаблалбла-декларация....

    SrqDequeueRun();
    if(!IsSystick())return;

.....      блаблабла--системный таймер........

IsSystick - это действительно таймер тикнул?

 

выгрузка из очереди. wait-free. выполняется только из eSystick. здесь все просто,никаких хитростей.

void SrqDequeueRun(void){
    register U32 r0 asm("r0");
    register U32 r1 asm("r1");
    U32 a0,a1,svc;
    t_srqItem *data;
    U32 head;
    
    head=srqQueue.head;
    if(head==srqQueue.tail)return;
    
    while(head!=srqQueue.tail){
        data=&srqQueue.buf[head];
        head=(head+1)%MAX_SRQ_QUEUE_ITEMS;
        asm volatile("ldmia %3,{%0,%1,%2}" :"=r"(r0),"=r"(r1),"=r"(svc) :"r"(data));
        a0=r0;a1=r1;
        /*if(svc>=sizeof(svcTable)/sizeof(t_Callback))*/
        a0=((int(*)(U32,U32))svcTable[svc])(a0,a1);
    }
    srqQueue.head=head;
}

 

на RVCT все обходится почти без асма с тем же результатом, он ldm/stm нормально генерит. Только алгоритмический код у него немного тормознее выходит (базового кода моей оси это не касается), или это я просто привык писать под gcc,выработалось чутье его алгоритмов оптимизации :))

 

Мютексы простые, без наследования приоритетов. Мне это не нужно. и производительность в +

Семафоры есть простые и с таймаутом - примитивы только set,signal,wait,wait+timeout

тред можно только создать и убить с другого треда. сам тред может себя остановить на некоторое время или выгрузится. также его могут убить обработчики fault-ов через ту же lock-free srq.

Ну и в принципе все.

Никаких критических секций, никаких циклов поиска итп.

KIS - keep it simple ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...