|
RTOS, тупые вопросы |
|
|
|
Jun 3 2016, 12:47
|

Местный
  
Группа: Свой
Сообщений: 285
Регистрация: 10-12-04
Из: Earth
Пользователь №: 1 437

|
Привет, друзья!
Вот изучаю как делают RTOS и имею ряд нубских вопросов:
1. Для чего каждая задача в ртосах оформляется в вечный цикл? Чтобы не быть завершенной и забытой "естественным путем"? А если задача больше не нужна, то ее надо прибивать самому с помощью какой-нибудь, условно говоря, os_task_kill(this_task)? 2. Конкретно под Cortex-M4. Как понять какие именно регистры сохранять, а какие - не сохранять при переключении контекста (не считая R0-R3, SP, LR, PC)? 3. Для начала достаточно ли будет делать только переключение контекста в PendSV_Handler шедулером или есть еще какие-либо тонкости? 4. Где физически находятся все эти стеки, на которые указывают регистры?
Спасибо!
|
|
|
|
|
Jun 3 2016, 13:18
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(spectr @ Jun 3 2016, 15:47)  Спасибо! Не в каждой RTOS надо делать в задачах циклы. В MQX RTOS когда задача доходит до конца ее RTOS стирает из системы без следа а заодно и все ресурсы которые задача захватила, и освобождает все объекты синхронизации захваченные задачей и не освобожденные ею. Какие регистры сохранять решает компилятор на основании соглашения с производителем чипов. Для ARM есть такое соглашение которое соблюдают все производители компиляторов под ARM. В вытесняющих RTOS есть как минимум два типа переключателей контекста: переключатель по прерываниям и переключатель программный. Стеки где скажете там и будут. Можно выделить статически, можно динамически при создании задач. Динамически выделяются из менеджеров памяти которые сами память распределяют из статических областей. Сами области указываются в конфигурационном файле линковщика.
|
|
|
|
|
Jun 6 2016, 05:35
|

Местный
  
Группа: Свой
Сообщений: 285
Регистрация: 10-12-04
Из: Earth
Пользователь №: 1 437

|
Цитата(AlexandrY @ Jun 3 2016, 16:18)  Не в каждой RTOS надо делать в задачах циклы. В MQX RTOS когда задача доходит до конца ее RTOS стирает из системы без следа а заодно и все ресурсы которые задача захватила, и освобождает все объекты синхронизации захваченные задачей и не освобожденные ею. Понятно, т.е. если задача не удаляется, то после завершения остается висеть в idle и шедулер ее в общем случае тупо пропускает при переключениях? Цитата(AlexandrY @ Jun 3 2016, 16:18)  Какие регистры сохранять решает компилятор на основании соглашения с производителем чипов. Для ARM есть такое соглашение которое соблюдают все производители компиляторов под ARM. Эммм, извините конечно, но может быть это решает разработчик ОС, а не компилятор? Не просто так же ручками пишется асмовый код для сохранения именно этих, вот этих и еще вон тех регистров. Цитата(yes @ Jun 3 2016, 16:22)  2. в порте RTOS уже сделано. если собираетесь портировать, то вообще-то сохраняют все регистры - так как в общем случае переключение задачи асинхронно к процессу - то есть может произойти в любой момент, а вернуться нужно туда же в том же состоянии. 3. какая RTOS? Не портирую, а пишу свой велосипед. Чисто из интереса и ради лулзов. Цитата(AlexandrY @ Jun 3 2016, 18:14)  Есть и другие ухищрения при переключении контекста для уменьшения количества сохраняемых регистров. А можно парочку примеров?
|
|
|
|
|
Jun 6 2016, 12:05
|

Местный
  
Группа: Свой
Сообщений: 285
Регистрация: 10-12-04
Из: Earth
Пользователь №: 1 437

|
Вопрос по стеку задачи. У каждой задачи есть свой стек, в котором хранятся все её локальные переменные, указатели "на куда-то туда и вон туда", а также указатели на стеки вызываемых внутри функций. Верно? Но регистров-то у процессора не бесконечное количество - всего с десяток-другой штук. А если в одной задаче переменных 30 штук используется и регистров не хватит, то что тогда? Цитата(ViKo @ Jun 6 2016, 14:33)  Что-то мне кажется, сохранять все регистры проще, чем шарить по всем функциям задачи, выискивая, какие регистры используются. Ради чего такие муки? Нескольких тактов, нескольких байтов? Согласен что проще сохранять/восстанавливать все подряд. Ну я думал, может это моветон так просто и четко делать.
|
|
|
|
|
Jun 6 2016, 12:19
|
Гуру
     
Группа: Свой
Сообщений: 2 198
Регистрация: 23-12-04
Пользователь №: 1 640

|
Цитата(spectr @ Jun 6 2016, 08:35)  Не портирую, а пишу свой велосипед. Чисто из интереса и ради лулзов. посмотреть советую 1) scmrtos (сильно связана с данным форумом  2) uc-os там есть книжка, которую автор, наверно, писал, когда сам пытался разобраться. на мой взгляд слегка колхозно (не помню уже что и как, но такое впечатление осталось) - но все понятно. 3) freeRTOS - серьезный проект с кучей саппорта и т.д. еще есть всякие ecos, rtems у всего перечисленного ++ в том, что доступны исходники. --------- про MQX - не пользовал. к пропиентарным "осям" испытываю некое предубеждение - когда начнешь разбираться, выяснится, что за что-то нужно платить, лицензировать и т.д. тем более она под тяжелые процессоры (если не ошибаюсь под i.mx-ы), для которых тот же линукс есть...
|
|
|
|
|
Jun 6 2016, 12:38
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(yes @ Jun 6 2016, 15:19)  про MQX - не пользовал. к пропиентарным "осям" испытываю некое предубеждение - когда начнешь разбираться, выяснится, что за что-то нужно платить, лицензировать и т.д. тем более она под тяжелые процессоры (если не ошибаюсь под i.mx-ы), для которых тот же линукс есть... Скорее так: scmrtos - это не то что RTOS, а такой же велосипед как тут думает делать TC. А на велосипеды доки не бывает в принципе. Т.е. это не пример для изучения. uC/OS это безусловно сила. Именно её и надо изучать OSестроителям за интерес. freeRTOS деньги зарабатывает на том, что не дает бесплатно мануала, а продает его. Это очень некрасиво. Куча авторов кое-как и фрагментарно описывают FreeRTOS, но это все не то ради чего стоит копаться. А вот если надо изучить RTOS и одновременно сделать Вещь, то MQX самое то. MQX по движку аналогична uC/OS и freeRTOS. К линуксу никакого отношения не имеет. Если не думать что родство с линуксом определяется по наличию функций read и write в структурах драйверов. Путаница с линуксом может возникнуть от того, что в MQX есть стек межзадачного взаимодействия портированный в частности и на линукс. Поэтому MQX очень легко связать с линуксом в мультикристальных SoC-ах
|
|
|
|
|
Jun 7 2016, 05:51
|
Участник

Группа: Свой
Сообщений: 52
Регистрация: 7-11-05
Из: Чебоксары
Пользователь №: 10 546

|
Цитата(AlexandrY @ Jun 6 2016, 15:38)  MQX по движку аналогична uC/OS и freeRTOS. А кому из них аналогичнее? Возврат из прерывания в MQX происходит как в uC/OS-II через выяснение и переключение на самую приоритетную из задач? Или как во FreeRTOS, прерывание может вернуть управление именно туда, что прервалось, без переключений контекста? MQX сейчас доступен для чего-либо, кроме kinetis? Судя по тому, что freescale.com редиректит на nxp.com, стоит ли ждать MQX для NXP?
|
|
|
|
|
Jun 7 2016, 06:43
|
Частый гость
 
Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462

|
Цитата(spectr @ Jun 6 2016, 15:05)  Вопрос по стеку задачи. У каждой задачи есть свой стек, в котором хранятся все её локальные переменные, указатели "на куда-то туда и вон туда", а также указатели на стеки вызываемых внутри функций. Верно? Но регистров-то у процессора не бесконечное количество - всего с десяток-другой штук. А если в одной задаче переменных 30 штук используется и регистров не хватит, то что тогда? Начните с того, что поиграйтесь с дизасмом и посмотрите где и как компилятор размещает глобальные/локальные переменные, аргументы функций и прочее. Очень интересно и по-новому позволяет смотреть на свой код  А по велосипедству: сначала очень полезно почитать классику ( Танненбаум)) и полистать чужие реализации (замечательная статья про TNeo).
|
|
|
|
|
Jun 7 2016, 07:03
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(AHTOXA @ Jun 7 2016, 09:59)  Всё понятно, "Пастернака не читал, но осуждаю". К вашему сведению, scmRTOS издавна поставляется с отличной документацией. ЗЫ. Вам хоть приплачивают за рекламу MQX? Или это вы добровольно?  А вы сколько на scmRTOS зарабатываете?  Цитата(dxp @ Jun 7 2016, 09:51)  Вау! Есть оказывается. Правда объемом со статью на гиктаймсе. Неудивительно что не заметил.
|
|
|
|
|
Jun 7 2016, 07:12
|
Гуру
     
Группа: Свой
Сообщений: 2 198
Регистрация: 23-12-04
Пользователь №: 1 640

|
Цитата(AlexandrY @ Jun 6 2016, 15:38)  К линуксу никакого отношения не имеет. Если не думать что родство с линуксом определяется по наличию функций read и write в структурах драйверов.
Путаница с линуксом может возникнуть от того, что в MQX есть стек межзадачного взаимодействия портированный в частности и на линукс. Поэтому MQX очень легко связать с линуксом в мультикристальных SoC-ах POSIX это не линукс. Линукс - это полноценная ось, в которой не только posix, но и куча всякого разного. то есть то, что сейчас модно называть экосистемой (+ куча народа, который знает эту экосистему). опять же синтетический таргет - то есть перенос кода с ПК. насколько я понимаю, в том же MQX TCP-шный стек уже за деньги? то есть, я хотел сказать, что если i.mx6, то смысл ставить на него переключалку задач имеет только для каких-то специфических приложений
|
|
|
|
|
Jun 7 2016, 09:14
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(dxp @ Jun 7 2016, 10:18)  Покажите статью на гиктаймсе объёмом в 140 страниц А4?
Раньше думал, вы хоть смотрели доку, раз такие смелые выводы делаете. Оказывается, вам это не надо - вам фантазии для этого достаточно. При этом открывшемся обстоятельстве остальные ваши выводы на любые темы вы обесценили сами. Ой извиняюсь. Не заметил кнопку "More Pages". Да и на кой читать всю эту доку. Грамматические ошибки исправлять? Или рецензировать? Со многим согласен, но многое ужасно запутано. Скажем слово 'порт' в разных смыслах без понятного контекста. Или слово 'объект', ну просто не перевариваемое. Причем тоже где-то 'объект', где-то 'элемент', где-то 'совокупность', где-то 'часть'. Нет строгости соблюдения терминологии. У неопытного крыша съедет. Нет, это я бы не рекомендовал.
|
|
|
|
|
Jun 7 2016, 09:30
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
QUOTE (AlexandrY @ Jun 7 2016, 15:14)  Да и на кой читать всю эту доку. Грамматические ошибки исправлять? Найдите хотя бы одну? QUOTE (AlexandrY @ Jun 7 2016, 15:14)  Скажем слово 'порт' в разных смыслах без понятного контекста. Или слово 'объект', ну просто не перевариваемое. Причем тоже где-то 'объект', где-то 'элемент', где-то 'совокупность', где-то 'часть'. Нет строгости соблюдения терминологии. "Порт" употребляется в обычном смысле для ПО и в контексте RTOS, тут всё однозначно. "Объект" употребляется преимущественно в контексте используемого ЯП С++, что тоже даёт однозначность. В остальном обычный русский язык, с терминологией обращение аккуратное. В начале даже приведён список используемых терминов и сокращений, дабы свести к минимуму непонятности. QUOTE (AlexandrY @ Jun 7 2016, 15:14)  У неопытного крыша съедет. Похоже, это и наблюдаем. QUOTE (AlexandrY @ Jun 7 2016, 15:14)  Нет, это я бы не рекомендовал. Как обычно в своём репертуаре: не читал, но не рекомендую. Не знакомы с вопросом - проходите мимо, не нужно шум поднимать по теме, о которой вы ничего не знаете, т.к. не дали себе труда хотя бы бегло ознакомиться с ней. Офтопить прекращаю. Замечу напоследок, что изучать новую тему как правило всегда легче на небольших и неперегруженных примерах и особенно когда имеется подробная документация.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Jun 7 2016, 12:45
|
Знающий
   
Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842

|
Цитата(Valentine Loginov @ Jun 7 2016, 09:43)  ... и полистать чужие реализации (замечательная статья про TNeo). А вы в своих проектах используете Тнео?
|
|
|
|
|
Jun 8 2016, 10:53
|

Местный
  
Группа: Свой
Сообщений: 285
Регистрация: 10-12-04
Из: Earth
Пользователь №: 1 437

|
Еще вопросы. Значит, написал вот такой код: main.c:Код #define TASK_STK_SIZE 2048 uint32_t task1_stk[TASK_STK_SIZE];
void task1(void* x) { while(1) { led_toggle(led); //printf("@ task1\n"); } }
int main(void) { configure_clocks(); led = led_create(GPIOE, 6); os_add_task("task1", task1, (void*) 0x555, task1_stk, TASK_STK_SIZE); os_start(); while(1); } scheduler.c:Код typedef struct task_descriptor { uint32_t* stk_ptr; uint16_t stk_size; task_handler handler; void* args; task_state state; char* name; } task_descriptor;
static uint8_t tasks_used = 0; static task_descriptor* tasks[MAX_TASKS];
__asm void _run_process(uint32_t* stk_ptr) { LDR R4, [R0, #(4*14)] ADD R0, R0, #(4*16) MSR PSP, R0 MOV R0, #2 MSR CONTROL, R0 CPSIE I BX R4 }
void os_add_task(char* name, task_handler task, void *args, uint32_t* stk_ptr, uint32_t stk_size) { tasks[tasks_used]->name = name; tasks[tasks_used]->handler = task; tasks[tasks_used]->args = args; tasks[tasks_used]->stk_size = stk_size; tasks[tasks_used]->state = RUN; tasks[tasks_used]->stk_ptr = (uint32_t*) ((uintptr_t) stk_ptr & 0xFFFFFFF8); *(--tasks[tasks_used]->stk_ptr) = 0x01000000L; *(--tasks[tasks_used]->stk_ptr) = (uint32_t)(task); tasks[tasks_used]->stk_ptr -= 14; //init_stack(task, &stk_ptr[stk_size-1]); if(tasks_used < MAX_TASKS) tasks_used++; printf("# created task: %s\n", name); }
void os_start(void) { printf("# starting OS...\n"); _run_process(tasks[0]->stk_ptr); } Инициализацию стека задачи и ассемблерный код пока взял из scmrtos (спасибо за наводку!). Мои вопросы вот в чем: 1. Правильно ли я понимаю: стек задачи - это просто область памяти (в моем случае task1_stk), конец которой заполняется таким образом, чтобы получить в ней значения регистров процессора как при переключении контекста (среди прочего там сидит и указатель на задачу). А далее асмовым (как правило) кодом из этого куска памяти значения тупо переписываются в регистры, после чего все как бы указывает на нужную нам задачу. 2. Приведенный выше код вроде как работает - в задачу task1 входит и крутится в ней. Но если раскомментировать printf в задаче task1, то проц уходит в MemFault (MemManage_Handler) сразу же в самой первой команде printf'а (судя по дизассемблеру). Почему так? 3. Не очень понятна запись tasks[tasks_used]->stk_ptr = (uint32_t*) ((uintptr_t) stk_ptr & 0xFFFFFFF8);. Для чего нужно выравнивание по 8 байтам?
|
|
|
|
|
Jun 8 2016, 13:48
|

Местный
  
Группа: Свой
Сообщений: 285
Регистрация: 10-12-04
Из: Earth
Пользователь №: 1 437

|
Цитата(AlexandrY @ Jun 8 2016, 15:34)  Говорю же читайте описание от микриума на uC/OS, это первоисточник. Действительно, в микриуме формирование стека расписано гораздо понятнее: Код CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task, void *p_arg, CPU_STK *p_stk_base, CPU_STK *p_stk_limit, CPU_STK_SIZE stk_size, OS_OPT opt) { CPU_STK *p_stk;
(void)opt; /* Prevent compiler warning */
p_stk = &p_stk_base[stk_size]; /* Load stack pointer */ /* Align the stack to 8-bytes. */ p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8); /* Registers stacked as if auto-saved on exception */ *--p_stk = (CPU_STK)0x01000000u; /* xPSR */ *--p_stk = (CPU_STK)p_task; /* Entry Point */ *--p_stk = (CPU_STK)OS_TaskReturn; /* R14 (LR) */ *--p_stk = (CPU_STK)0x12121212u; /* R12 */ *--p_stk = (CPU_STK)0x03030303u; /* R3 */ *--p_stk = (CPU_STK)0x02020202u; /* R2 */ *--p_stk = (CPU_STK)p_stk_limit; /* R1 */ *--p_stk = (CPU_STK)p_arg; /* R0 : argument */ /* Remaining registers saved on process stack */ *--p_stk = (CPU_STK)0x11111111u; /* R11 */ *--p_stk = (CPU_STK)0x10101010u; /* R10 */ *--p_stk = (CPU_STK)0x09090909u; /* R9 */ *--p_stk = (CPU_STK)0x08080808u; /* R8 */ *--p_stk = (CPU_STK)0x07070707u; /* R7 */ *--p_stk = (CPU_STK)0x06060606u; /* R6 */ *--p_stk = (CPU_STK)0x05050505u; /* R5 */ *--p_stk = (CPU_STK)0x04040404u; /* R4 */
return (p_stk); } И, что интересно, с таким кодом инициализации стека printf из задачи - заработал  UPD: собственно говоря, printf заработал и с кодом от scmRTOS. Ошибка была в строке Код tasks[tasks_used]->stk_ptr = (uint32_t*) ((uintptr_t) stk_ptr & 0xFFFFFFF8); Я неправильно брал вершину стека. Надо так: Код tasks[tasks_used]->stk_ptr = (uint32_t*) ((uintptr_t) &stk_ptr[stk_size] & 0xFFFFFFF8);
|
|
|
|
|
Jun 10 2016, 12:38
|

Местный
  
Группа: Свой
Сообщений: 285
Регистрация: 10-12-04
Из: Earth
Пользователь №: 1 437

|
Правильно ли я понимаю, что PendSV используется так: Ему выставляется нижайший приоритет. Если в данный момент есть что делать - делаем (ну, цикл какой или работа с периферией). Если делать нечего или мы сидим в прерывании и нам нельзя там долго находиться, то что-то делаем по-быстрому и взводим флажок-запрос на PendSV. Как только все остальные работающие в данный момент прерывания завершатся, проц, видя флажок-запрос, автоматом уходит в PendSV, т.к. теперь ему теперь совсем нечем заняться и можно спокойно уйти на обработку самого низкоприоритетного PendSV. В планировщике, если есть живые задачи, также взводится этот флаг, чтобы по наступлению таймаута процессор ушел в PendSV и таким образом выполнил переключение. Либо в коде самой задачи, в ее самом конце (когда она завершила свою работу согласно алгоритму), делается принудительная установка флажка-запроса на PendSV. Все так? Цитата(AlexandrY @ Jun 10 2016, 15:16)  Странно почему вы не видите, во всех вызовах стоят _set_pend_sv Спасибо, рассмотрел.
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|