Как стать автором
Обновить

Комментарии 36

Отличная статья, интересно будет прочитать про работу с прерываниями.
С прерываниями там все очень умно и шоколадно устроено. Можно гибко настроить, каким прерываниям можно вытеснять код ядра, а каким — нельзя. При выходе из прерывания можно принудительно переключить контекст, то есть вернуться не в ту задачу, в которая была прервана прерыванием, а в ту, у которой приоритет выше. Например, пришел в UART символ, на него сработало прерывание, и при выходе из прерывания можно сразу принудительно переключить контекст на задачу, которая обрабатывает прием. В общем, FreeRTOS сделана с заботой о нас, о программистах. Просто бери готовенькое на блюдечке.
Как-то так:
image

Константы configKERNEL_INTERRUPT_PRIORITY и configMAX_SYSCALL_INTERRUPT_PRIORITY также настраиваются в файле FreeRTOSConfig.h. Все свежие релизы FreeRTOS поддерживают вложенность и аппаратные приоритеты прерываний (на тех архитектурах, которые предусматривают настройку приоритета аппаратных прерываний).
ИНтересно: какой там планировщик?
Насколько помню, там планировщик с несколькими очередями, по очереди на каждый приоритет. Количество приоритетов настраивается в конфигурационном файле (это константа). И вроде бы обычное приоритетное планирование. Смею предположить, что O(1). Но гарантий дать не могу.

FreeRTOS помимо классического псевдо-параллелизма с жирным стеком для каждой задачи позволяет работать с сопрограммами, которые исполняются кооперативно. Причем сопрограммы в данном случае полноценные, в отличии от имитации их за счет switch-case, как у Эдама Данкелса в Contiki.
Шедулер (планировщик) отвечает за принятие решения о переключении контекста выполнения (т. е. какой задаче передать ресурс процессора). Решение это принимается на основе приоритета задач, а также на основе подсчета времени, которое задача провела в состоянии ожидания (чем дольше задача бездействовала, тем больше у неё прав на запуск). Приоритет назначается при создании задачи (uxPriority, упомянутый в статье), и может быт изменен или считан в ходе выполнения программы через специальные функции API FreeRTOS (vTaskPrioritySet(), uxTaskPriorityGet()).

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

Задачи, которые имеют равный приоритет, имеют одинаковые права на процессор, и переключаются на выполнение по очереди. Задачи, которые имеют более высокий приоритет, вытесняют (preempt) все задачи, которые имеют приоритет меньше. Высокоприоритетные задачи могут принудительно отдать свое процессорное время (вызовом taskYIELD(), если они завершили свою нужную работу), или заблокироваться в ожидании специального события, позволяя тем самым менее приоритетным задачам возможность запуститься. Таким образом во FreeRTOS для переключения задач используется алгоритм приоритетного (с фиксацией приоритета) планирования запуска задач с вытеснением, вытесняющая многозадачность (Fixed Priority Preemptive Scheduling). Однако имеется возможность применить и другой алгоритм переключения задач — кооперативная многозадачность (Co-operative Scheduling). У каждого алгоритма свои достоинства и недостатки, и соответственно разная область применения.

Для обмена данными задача-задача, задача-прерывание, прерывание-задача во FreeRTOS имеются специально предусмотренные объекты — очереди. При обмене данными или событиями предусмотрена синхронизация высокоприоритетной задачи (или прерывания) и менее приоритетной задачи. Синхронизация происходит с помощью блокировки на очереди или семафоре, при этом можно задать время блокировки (таймаута процесса передачи). Для атомарных операций есть возможность создавать критические секции кода.
Эмс… Насколько мне известно, эта же схема с учётом времени ожидания — это не realtime технология, это sharedtime. Как при таком планировании обеспечиваются гарантии времени при реакции на события?
При задании времени ожидания, можно указать, не ждать фиксированное время, а просто находится в ожидании т.е как только пришел сигнал, сразу разблокироваться.
FreeRTOS- это именно system for hard real time, то есть система, СПЕЦИАЛЬНО СПРОЕКТИРОВАННАЯ для того, чтобы обеспечить поддержку ЖЕСТКО ГАРАНТИРОВАННОГО времени отклика на внешние события. Время ожидания в ней действительно учитывается — при принятии решения шедулером о переключении задач, имеющий одинаковый относительно друг друга приоритет. Ни более ни менее. Гарантия времени реакции на события достигается настройкой приоритетов задач и прерываний.
Для меня лично будет очень интересно увидеть статью про работу FreeRTOS+LwIP при активной передаче UDP данных.
На каком процессоре использовался живьём? Как с гарантией latency? Какие характеристики шедулера?
Это самое интересное :)
Использовал на MSP430F5438, с latency в документах по этой РТОС ничего не видел, по другой пишут, что порядка 40мс переключение контекста, здесь думаю примерно также. Глубоко внутрь планировщика не копал т.к. нужно было просто применять, и знаю только, что есть возможность работать в режиме preemptive(мой случай) и cooperative.
> 40мс переключение контекста
Не слишком ли это много для RTOS? Может мкс (микросекунд)?
Кто нибудь тестил low-latency ядро линукс по этому же параметру?
Это время конфигурируется константой времени компиляции configTICK_RATE_HZ в файле FreeRTOSConfig.h, которая представляет из себя частоту в Герцах. Например, если configTICK_RATE_HZ установлена в 100 (Гц), то длительность слайса (тика времени, через которые происходит переключение контекста) составит 10 мс.

Во FreeRTOS переключение контекста выполнения реально может происходить намного чаще, чем каждый слайс времени — при окончании аппаратного прерывания, при добровольной передаче контекста (вызовом taskYIELD()), при наступлении событий.
> каждый слайс времени
Это эквивалентно обновлению TickCount в Windows (16 мс минимум)? Если да, то как я понимаю это не совсем «latency» в контексте разговора про отзывчивость ядра и в контексте low-latency- и rt- ядер линукс. Как я понимаю TickCount для апишной функции винды обновляется редко, но контекст между процессами переключается чаще.
Я путаюсь?
добавлю ещё один момент, FreeRTOS очень не любит циклы, пусть даже и не бесконечные, но которые исполнются дого, напримр есть инфа, которую нужно обработать, ну и вы включаете какой-то алгоритм в цикл while(условие):
void TASK_YYY( void *pvParameters)
{
	while( 1 ){
		while( value != xxx ){
			// алгоритм
		}
	}
}

В таких местах могут быть зависоны, по крайней мере на IAR STM32 бывали, и нужно делать так:
void TASK_YYY( void *pvParameters)
{
	while( 1 ){
		while( value != xxx ){
			// алгоритм
			taskYIELD();
		}
	}
}

Т.е. после каждого перегона алгоритма нужно сделать переключение задачи, а то могут быть проблемы и вообще нужно избегать таких вот «ожидающих» состояний, например когда ожидаются данные с периферии низко скоростного интерфейса
А мне вот отечественный проект один нравится, имя которому Embox. Это, конечно, решение не для самых «бедных» архитектур вроде микроконтроллеров нижнего ценового сегмента, но система заслуживает своего внимания. Код очень качественный, можно легко разобраться с любым компонентом данной ОС. Архитектура модульная, и, в принципе, не возбраняется собрать из этой мозаики что-то свое, подходящее только вам. Здесь в наличии несколько планировщиков, несколько менеджеров памяти на разные случаи жизни, потоки и псевдопроцессы, таймеры и механизмы обработки прерываний. Помимо всего сверху навешена система драйверов, файловая система, стандартная библиотека и набор приложений. Естественно, немного разобравшись, ото всего этого изобилия можно отказаться, получив вполне миниатюрную систему для вашей железки. Врать не буду, нигде не использовал, но активно игрался с x86 версией под эмулятором.
На данный момент с этим работать пересатал, как вернусь обязательно попробую. Я из отечественного немного работал с scmRTOS, которая написана на C++, конечно сверхвозможностей, как у Вашей ОС там нет, но как пример, что можно писать и на C++ пойдет, а также, она тоже очень небольшая, т.е. можно и внутри поковыряться.
Вы немного не поняли, это не моя ОС. А что до отечественных, тут поле довольно широкое. Не все, конечно, заслуживает внимания. Слышал еще про iRTOS; не помню, что, но что-то меня не впечатлило в ней. Может за последнее время что-то изменилось.
У Embox что-то мало поддерживаемых платформ. У FreeRTOS платформ намного больше (только под GCC я насчитал аж 19 наименований). Кроме того, есть коммерческие форки — OpenRTOS и SafeRTOS. Поэтому для разработчика FreeRTOS гораздо привлекательнее. Можно сначала потренироваться на кошечках (FreeRTOS), а потом при необходимости прикупить тяжелую артиллерию (OpenRTOS и SafeRTOS).
Приятно слышать это как одному из разработчиков. :)

Будет ли сообществу интересен материал, подобный этому, но про Embox?
Конечно будет, к тому же, можно сделать один простой ход, который позволит вам собрать еще большую аудиторию.

Уж очень много человек одержимы идеей влиться в OSDEV-сцену, и среди пользователей хабрахабра таких также не мало. Часть одержимых идеей пытается прыгнуть чуть выше и пишет для таких же как они сами уроки. В итоге и появляются очередные протуберанцы о работе с защищенным режимом на ассемблере вместо основной темы — разработки ядра операционной системы.

У вас в багаже вполне переносимый код, достаточное множество реализованных алгоритмов, документация, хоть и изобилующая опечатками, страдающая орфографией, но все же вполне качественная. Вы могли бы показать сообществу, как реально устроена операционная система, с примерами кода. Пожевать, чтобы все могли это проглотить. Ну например, взять менеджер физической памяти и рассказать, как он работает, что такое buddy-алгоритм, чем хорош, или переходя уже к более высокому уровню — поведать о механизме slab. Рассказать про виртуальную память на примере своей ОС (хотя насколько помню тут у вас не все еще есть), про виртуальную файловую систему, драйверы, планирование, загрузку ELF. При достаточном качестве материалов они бы были мегапопулярны.

Также, статьи об использовании ОС в своих проектах могут быть очень интересными. Можно преподносить их подобно этому материалу про FreeRTOS. А можно комбинировать рассмотрение внутренностей ОС вместе с применением ее на практике. Например, рассказываете как сделать в вашей ОС что-то конкретное и добавляете немного информации о том, как же оно устроено. Чтобы у людей не складывалось ощущение черного ящика.
Спасибо за статью, материал-то интересный! Хабрахабру нужен большой пинок под зад, ну или серия пинков, которая откроет дорогу новым качественным материалам.
Круто, еще бы хотелось увидеть примеры, когда нужна РТОС. Ну т.е. ситуация, когда я со всей неотвратимостью должен понять — да тут без РТОС не обойтись.

Ну и про стек я лично ничего не знаю — если это не совсем тривиальная вещь, то опиши ПЛЗ — зачем каждой таске свой стек и т.д.
Пример из жизни: было устройство 1 МК, 5 сенсоров, с разными протоколами общения, разной частотой пересылки данных. Привычный подход с использованием while(1){} приносит те еще проблемы по синхронизации приема-обработки-передачи данных, а также по сопровождению и написанию самого кода.

Надуманный пример: на начальном этапе проектирования, заранее неизвестно, о будущем масштабе системы и хотелось бы предусмотреть ее будущий рост, вот РТОС, как раз позволяет сделать это достаточно прозрачно.

А применять ее не стоит в самых тривиальных случаях, например, есть простая логика: контроллер-сенсор, которую можно решить привычным способом, так как KISS никто не отменял :-).

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

Если говорить, не касаясь многозадачности:
1. При вызове подпрограмм в стек кладутся их формальные параметры, а также адрес возврата из подпрограммы. За счет этого подхода мы можем вызывать функции и всегда возвращаться туда, откуда мы их вызывали;
2. Также, на стеке выделяется память для локальных объектов функции;
3. Стек используется для временного сохранения данных из регистров процессора, потому что регистров обычно — не много.

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

Есть подходы, когда регистровый контекст сохраняется вручную, без использования аналогов инструкций push и pop, но это встречается довольно редко. Тем более, многие архитектуры умеют делать это (сохранение части регистрового контекста в стеке на момент обработки прерывания) почти на автомате.
Автору: статья нужная и интересная. Неплохо было бы вначале немного написать — "зачем все это надо?". Я имею в виду — почему появилась FreeRTOS, чем она отличается от обычных операционных систем и от обычной программы, которую пишет программист? Что она вообще дает программисту? В оригинальном руководстве «Using The FreeRTOS Real Time Kernel» Ричарда Барри этот вопрос рассматривается очень хорошо.
Добавил краткое введение.

Увы всё про мягкое и жесткое мы уже слышали…


Интересно всё же как эволюция ЭВМ и развитие операционных систем в частности пришли к тому, что в 2003 г. понадобилось изобрести новую операционную систему.
Казалось бы, FreeRTOS с его простотой, минимализмом, должен был появиться где-то в 60е...

в 60х не было целевой аудитории. Как мне кажется, необходимость FreeRTOS обусловлена широким распространением DIY микроконтроллерных девайсов.

Концепция вытесняющей многозадачности относительно новая, достаточно долго предполагалось, что если считаем задачу, остальные выгружаем. Использование функций ОС в стандарте С было новаторским решением, а это уже 70е. Про историю хорошо пишут Таненбаум и Непейвода, если интересуеесь, очень советую.


Ну и простота с минимализмом это скорее к FemtoOS :) слышал я, как FreeRTOS называли тяжёлой и перегруженной)

"Использование функций ОС в стандарте С"
Раскройте пожалуйста что имеется ввиду…
По моему мнению никаких функций ОС в C99 нет. Как минимум была бы проблема использовать все конструкции языка Си в системах без ОС вообще, однако как раз в таких системах (без ОС) язык Си и используется в основном.

В ANSI C (и даже в K&R C, приложение В) предполагалось, что, например, putc не пишет в регистр, а дергает стандартную библиотеку, уже портированную на платформу, а та дёргает ОС (хотя никто не мешает перенаправить stdout как удобно программисту, но это скорее исключение). В 60е концепция стандартной библиотеки и системных вызовов была новаторской - программы были вполне себе "вещами в себе", и если я не путаю, поддержка многозадачности в ОС появилась раньше стандартизированного доступа к периферии.

Согласен с вами. Спасибо за пояснение.

Прошу исправить абзац насчёт лицензии. Разрешено не публиковать текст приложения, которое использует FreeRTOS, несмотря на то, что OS линкуется с ним. Исходники самой же RTOS должны всегда прикладываться, изменения, внесённые в неё — тоже.
The exception permits the source code of applications that use FreeRTOS solely through the API published on this website to remain closed source, thus permitting the use of FreeRTOS in commercial applications without necessitating that the whole application be open sourced. The exception can only be used if you wish to combine FreeRTOS with a proprietary product and you comply with the terms stated in the exception itself.

As a special exception, the copyright holder of FreeRTOS gives you permission to link FreeRTOS with independent modules that communicate with FreeRTOS solely through the FreeRTOS API interface, regardless of the license terms of these independent modules, and to copy and distribute the resulting combined work under terms of your choice, provided that

  1. Every copy of the combined work is accompanied by a written statement that details to the recipient the version of FreeRTOS used and an offer by yourself to provide the FreeRTOS source code (including any modifications you may have made) should the recipient request it.
  2. The combined work is not itself an RTOS, scheduler, kernel or related product.
  3. The independent modules add significant and primary functionality to FreeRTOS and do not merely extend the existing functionality already present in FreeRTOS.


Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации