![](https://habrastorage.org/webt/b_/hz/jv/b_hzjvxfyiqk1hj4znoykfy4iyi.jpeg)
В этой статье продолжается обзор Nucleus SE
Службы
Nucleus SE предоставляет набор средств, которые можно ожидать от любой ОСРВ.
Во-первых, Nucleus SE содержит довольно простой планировщик, однако, благодаря четырем доступным вариантам, он обеспечивает гибкость. Планировщик поддерживает алгоритмы Run to Completion (выполнение до завершения), Round Robin (карусель), Time Slice (квант времени) и Priority (приоритетное планирование).
API Nucleus SE включает в себя около 50 служебных вызовов, которые предоставляют разработчикам доступ к управлению задачами, разделами памяти, сигналами, группами флагов событий, семафорами, почтовыми ящиками, очередями, конвейерами, системным временем, таймерами приложений и диагностикой.
В дополнение к простому планированию задач Nucleus SE (опционально) поддерживает приостановку задач. Эта функция может быть «чистой» (например, как результат заданного в явном виде служебного API-вызова приостановки), может быть функцией «сна» (когда задача приостанавливается на определенный промежуток времени) или может быть результатом другого вызова API, в котором задача блокируется (так называемая «условная» приостановка), ожидая доступа к ресурсу ядра. В отличие от Nucleus RTOS Nucleus SE не поддерживает таймауты при блокировке API-вызовов.
Разнообразие представленных механизмов позволяет выбирать из иерархии средств межзадачной синхронизации и связи: от семафоров до сигналов, флагов событий, почтовых ящиков и очередей/конвейеров.
Предыдущие статьи серии:
Статья #7. Nucleus SE: введение
Статья #6. Другие сервисы ОСРВ
Статья #5. Взаимодействие между задачами и синхронизация
Статья #4. Задачи, переключение контекста и прерывания
Статья #3. Задачи и планирование
Статья #2. ОСРВ: Структура и режим реального времени
Статья #1. ОСРВ: введение.
Проверка параметров
При выборе конфигурации NUSE_API_PARAMETER_CHECKING во все API функции включается код для верификации параметров: проверки нулевых указателей, индексов объектов и т. д. Так как это дополнительный код, требующий дополнительной памяти, будет разумно включить эту функцию при отладке, но выключить в релизной сборке.
Конфигурация
Nucleus SE имеет гибкую структуру, что дает нам два положительных момента. С одной стороны, ядро может иметь мелкомодульную конфигурацию, которая удовлетворяет задачам конкретного приложения благодаря простой настройки доступного функционала и простого управления использованием памяти. С другой стороны, код Nucleus SE легко переносится как между инструментальными средствами, так и между процессорами.
Соглашения об именовании
Так как при разработке Nucleus SE были важны ясность и простота понимания кода, соглашения об именовании были тщательно продуманы. Каждый символ кода имеет префикс NUSE_. Все, что идет за этим префиксом, подчиняется набору простых правил.
Вызовы API
Каждая функция вызова API в Nucleus SE начинается с NUSE_, за которым практически всегда следует тип объекта, затем выполняемая операция в смешанном регистре с разделением при помощи нижнего подчеркивания. Пример — функция NUSE_Queue_Send(), помещающая сообщения в очередь.
Другие функции и переменные
Остальные функции и (глобальные) переменные в коде Nucleus SE также используют префикс NUSE_, но оставшаяся часть названия не всегда имеет «структуру». Это неважно для обычного пользователя ядра, так как ему будет достаточно функций API.
Конфигурационные символы
Так как Nucleus SE конфигурируется с помощью символов #define, они также подчиняются соглашениям об именовании. Они пишутся только в верхнем регистре. Имена активаторов вызовов API совпадают с именами функций и также пишутся в верхнем регистре, например, NUSE_QUEUE_SEND.
Другие символы #define
Любые другие символы #define (например, параметры вызовов API и возвращаемые значения статуса), которые могут быть использованы кодом приложения, подчиняются тем же правилам, они начинаются с NUSE_ и пишутся в верхнем регистре. Например, NUSE_SUCCESS.
Структуры данных
Все ОСРВ имеют набор структур данных, описывающих объекты ядра. В большинстве реализаций они представляют из себя структуры данных в C, которые формируют связанные списки, часто с двунаправленной и даже круговой связью. Это логично, так как важные данные удобно инкапсулируются, а элементы списка можно добавлять или удалять по мере создания и удаления объектов.
В Nucleus SE все объекты статичны, так что организация всех структур данных объектов в простой список было очевидным решением. Это уменьшает объем и сложность прямых и обратных указателей. Однако, я решил усилить оптимизацию системы и отказался от использования структур вовсе. В Nucleus SE все данные объектов ядра представлены несколькими простыми массивами (также называемыми таблицами) различных типов, по одному и больше на каждый тип объекта. Есть несколько аргументов в пользу такого решения:
- Nucleus SE разрабатывалась с учетом совместимости с 8-битными структурами. Большинство небольших CPU не имеют оптимальных инструментов для реализации структур данных в C компилятором. Простые массивы гораздо более эффективны.
- Так как максимальное разрешенное количество объектов каждого типа – 16, а обращение к элементам каждого массива требует четырех бит, часто используется один байт. Это более эффективно, чем адрес, который обычно занимает 16 или 32 бита.
- Необходимо, чтобы постоянные данные объекта хранились в ПЗУ (ROM) и не копировались в ОЗУ (RAM). Поскольку структура не может быть разделена между ПЗУ и ОЗУ (в традиционном переносимом С), каждый тип объекта может иметь две структуры, что является чрезмерно сложным. В Nucleus SE таблицы описания объектов могут находится как в ПЗУ, так и в ОЗУ, в соответствии с требованиями.
- Благодаря высокой конфигурируемости Nucleus SE («сверхвысокой масштабируемости»), некоторые данные описания объектов могут быть опциональными, в зависимости от выбранных средств. Это приводит к широкому использованию условной компиляции. Структурное определение со встроенными директивами условной компиляции очень сложно понять. Управление инстанцированием отдельных массивов при помощи этого метода, в свою очередь, довольно легко понять.
Все таблицы данных объектов подчинены иерархическому соглашению об именовании, упомянутому выше. Таким образом, понимать, какие таблицы логически связаны между собой, довольно просто.
Ключевые отличия от Nucleus RTOS
Несмотря на то, что Nucleus SE разрабатывалась с учетом высокой степени совместимости с Nucleus RTOS, некоторых небольших и более крупных различий избежать не удалось. Они будут подробно описаны в соответствующих статьях, а ниже приведено их краткое описание.
Данные объектов
В Nucleus RTOS объекты создаются и удаляются по запросу. В Nucleus SE все объекты создаются статически и определяются во время сборки.
Количество объектов
В Nucleus RTOS поддерживается неопределенное количество объектов каждого типа. Nucleus SE поддерживает максимум шестнадцать объектов каждого типа.
Имена объектов
Nucleus RTOS позволяет присваивать некоторым типам объектов текстовые имена, которые могут использоваться при отладке. В Nucleus SE такая возможность отсутствует.
Механизм блокировки задач
Механизм блокировки задач API-вызовом в Nucleus SE довольно прост. Когда ресурс освобождается, все ожидающие задачи возобновляются и соревнуются между собой (при помощи планировщика задач) за ресурсы. Проигравшие задачи вновь приостанавливаются (блокируются). В Nucleus RTOS механизм более сложный, в нем продолжаются только важные задачи, что является более эффективным.
Таймаут вызовов API
При вызове API блокировки Nucleus RTOS позволяет разработчику указывать период таймаута, после которого вызов возобновится, даже если ресурс не освободился. В Nucleus SE такая возможность отсутствует.
Планирование задач
Планировщик Nucleus RTOS гибкий, эффективный и строго определенный. Nucleus SE предлагает набор планировщиков, каждый из которых прост и достаточно эффективен для уменьшенного количества поддерживаемых задач: от 1 до 16.
Приоритеты задач
Система, использующая Nucleus RTOS, может иметь произвольное количество задач, которым можно назначить один из 256 уровней приоритетов, при этом несколько задач могут иметь один уровень приоритета. Уровни приоритетов задач также могут меняться во время выполнения. В Nucleus SE, если выбран планировщик по приоритету, каждая задача должна иметь уникальный уровень приоритета, который не может быть изменен динамически. Может существовать только один уровень приоритета на каждую задачу.
Обработка прерываний
Nucleus RTOS поддерживает сложную архитектуру двухуровневого обработчика прерывания, которая обеспечивает эффективное взаимодействие обработчика прерываний и служб ядра. Nucleus SE использует похожий подход, который поддерживает как простые обработчики прерываний, не взаимодействующие с ядром (неуправляемые прерывания), так и обработчики прерываний с полным сохранением контекста, которые могут использовать вызовы API (управляемые прерывания).
Драйверы устройств
Nucleus RTOS имеет хорошо продуманную архитектуру драйверов устройств. Nucleus SE такой архитектуры не имеет, оставляя разработчику задачу распределения управления устройствами между задачами и кодом обработчика прерываний.
Распространение Nucleus SE
Исходные коды Nucleus SE будут публиковаться по мере развития этой серии статей. Доступные файлы будут предоставляться по запросу на электронную почту. Ближе к концу серии статей будет создано хранилище для скачивания всех опубликованных файлов.
Об авторе
Колин Уоллс уже более тридцати лет работает в сфере электронной промышленности, значительную часть времени уделяя встроенному ПО. Сейчас он — инженер в области встроенного ПО в Mentor Embedded (подразделение Mentor Graphics). Колин Уоллс часто выступает на конференциях и семинарах, автор многочисленных технических статей и двух книг по встроенному ПО. Живет в Великобритании. Профессиональный блог Колина, e-mail