TinyOS
Разработка операционной системы TinyOS [HSW00] связана с появлением новой концепции беспроводной связи – Motes. Motes (в переводе с английского – пылинки, соринки) – это реализация идеи "smart-dust" ("распыленной разумности"), предложенной оборонным агентством Darpa (Defense Advanced Research Projects Agency), в частности, для отслеживания передвижений противника.
Motes разработаны в Калифорнийским университете в Беркли совместно с Intel, и в настоящее время ведутся испытания этих самоорганизующихся сетей, построенных на основе открытых технологий Intel Mote и программного обеспечения TinyOS, TinyDB.
Умные сенсоры Motes, распределенные в пространстве, могут самостоятельно связываться друг с другом, образуя распределенную беспроводную информационную сеть. "Пылинка разума" состоит из 8-битового микроконтроллера семейства Amtel AVR, приемопередающего интегрального модуля TR1000 и двух микросхем средней степени интеграции – энергонезависимой памяти и дополнительного загрузочного микроконтроллера, позволяющего по радиоканалу обновлять ПО центрального процессора – AVR.
"Smart-dust" создавалась для динамических, изменяющихся как в пространстве, так и во времени сетей – для той области, в которой абсолютно неприменимы ни традиционные алгоритмы управления, ни отработанные принципы маршрутизации, ни архитектурные решения, лежащие в основе традиционного системного ПО. Стремление конструкторов сделать ее как можно более компактной (в перспективе – 1 мм3) влечет за собой ряд существенных ограничений, в первую очередь энергетических. Ограниченные вычислительные ресурсы и динамический характер сети приводят к тому, что функциональность "пылинки" надо время от времени изменять, что может быть достигнуто только одним способом – передачей по радиоканалу нужного ПО. С другой стороны, энергетическая дороговизна передачи информации требует сверхкомпактного представления передаваемого кода, в противном случае "пылинки" просто не будут работать из-за быстрого истощения крохотных автономных источников питания.
При проектировании TinyOS основными требованиями являлись достижение энергетической эффективности и создание высокого уровня абстракции системных вызовов для упрощения разработки программ. Эта система обладает всеми отличительными признаками развитой ОС – в первую очередь, крайне простой, но достаточно развитой компонентной моделью. Однако специфика предназначения этой компонентной модели существенно отличается от традиционных разработок, поскольку главной целью компонентности является не облегчение подбора интерфейсов, соответствующих требованиям запрашивающего компонента, а обеспечение развитых и надежных механизмов параллельного выполнения задач в условиях крайне ограниченных ресурсов.
Вышеописанные причины привели разработчиков TinyOS к выбору событийной модели, которая позволяет управлять высокой степенью параллельности выполнения задач в ограниченном пространстве памяти. Подход к управлению многопоточности, основанный на стеках, потребовал бы значительно больших ресурсов памяти, чем предполагалось в данном проекте. Для каждого контекста исполнения потребовалось бы выделение памяти для наихудшего варианта, либо нужно было бы применить какой-либо слишком изощренный и сложный метод управления памятью.
Архитектура TinyOS объединяет такое привычную составляющую, как планировщик задач (scheduler), и оригинальное понятие – компонентный граф. Термин "компонент" здесь одновременно и соответствует общепринятому пониманию, и существенно расширяет его. Так, интерфейс компонента TinyOS состоит из двух множеств – верхнего, предоставляемого этим компонентом, и нижнего, требуемого для его функционирования. Каждое из этих множеств содержит описания команд и событий – синхронных и асинхронных процессов.
Согласно описанию системы, компонент имеет 4 взаимосвязанные части – набор команд, набор обработчиков событий, инкапсулированный фрейм фиксированного размера и пучок простых потоков. Потоки, команды и обработчики событий выполняются в контексте данного фрейма и воздействуют на его состояние.
Кроме того, каждый компонент декларирует команды, которые он использует, и события, о которых он сигнализирует. Эти декларации используются при компоновке для конфигурации системы, настроенной на определенный класс приложений. Процесс композиции создает слои компонентов, где каждый более высокий уровень выдает команды к нижележащему уровню, а нижележащий уровень обращается к более высокому с помощью сигналов, что понимается в данной системе как события. Аппаратное обеспечение является самым низким слоем компонентов.
Написана TinyOS с использованием структурированного подмножества языка C. Использование статического распределения памяти позволяет определять требования к памяти на уровне компиляции и избегать накладных расходов, связанных с динамическим распределением. Кроме того, этот подход позволяет сокращать время выполнения благодаря статическому размещению переменных во время компиляции вместо доступа к ним по указателю во время выполнения.
Команды являются неблокируемыми запросами к компонентам нижележащего слоя. Команда сохраняет необходимые параметры в своем фрейме и может инициировать поток для его последующего выполнения. Чтобы не возникало неопределенных задержек, время ответа от вызванной команды не должно превышать заданного интервала времени, при этом команда должна вернуть статус, указывающий, успешно она завершилась или нет. Команда не может подавать сигналы о событиях.
Обработчики событий прямо или косвенно имеют дело с аппаратными событиями. Самый нижний слой компонентов содержит обработчики, непосредственно связанные с аппаратными прерываниями. Обработчик событий может положить информацию в свой фрейм, запустить потоки, подать сигнал вышележащему уровню о событиях или вызвать команды нижележащего слоя. Аппаратное событие инициирует фонтан обработки, которая распространяется вверх по уровням через события и может вернуться вниз через команды. Чтобы избежать циклов в цепочке команд/событий, команды не могут подавать сигналы о событиях. Как команды, так и события предназначены для выполнения небольшой, строго фиксированной порции обработки, которая возникает внутри контекста выполняющегося потока.
Основная работа возлагается на потоки. Потоки в TinyOS являются атомарными и, в отличие от потоков в других ОС, выполняются вплоть до своего завершения, хотя они и могут быть вытеснены событиями. Потоки могут вызывать команды нижележащего уровня, сигнализировать о событиях более высокому уровню и планировать другие потоки внутри компонента. Семантика потока “выполнение вплоть до завершения” позволяет иметь один стек, который выделяется выполняющемуся потоку, что очень существенно в системах с ограниченной памятью. Потоки дают возможность симулировать параллельную обработку внутри каждого компонента, т.к. они выполняются асинхронно по отношению к событиям. Однако потоки не должны блокироваться или простаивать в ожидании, потому в таких случаях они будут препятствовать развитию обработки в других компонентах. Пучки потоков обеспечивают средство для встраивания произвольных вычислительных обработок в модель, управляемую событиями.
В системе предусмотрена также отдельная абстракция задачи, понимаемая как продолжительный вычислительный процесс. Взаимоотношение между понятиями “команда” и “задача” следующее: команда – это атомарная составляющая задачи. Команда ставится в очередь на исполнение планировщика, затем она выполняется и может быть временно прервана обработкой события.
Планировщик работает по принципу очереди FIFO, т.е. для передачи управления следующей задаче требуется полное завершение предыдущей задачи. Однако, в зависимости от требований приложения, могут использоваться и более сложные механизмы планирования, основанные на приоритетах или на дедлайнах. Ключевым моментом является то, что планировщик ориентирован на энергосбережение: процессор засыпает, если очередь планировщика пуста, а периферийные устройства работают, и каждое из них может разбудить систему. Когда очередь становится пустой, новый поток может быть запущен на исполнение только в результате какого-либо события, которое может возникнуть только в аппаратных устройствах. Планировщик имеет крайне малые размеры – всего 178 байтов, данные планировщика занимают только 16 байтов.
В TinyOS полностью отсутствуют механизмы блокирования исполнения, что означает необходимость введения индикации завершения продолжительной операции соответствующим асинхронным событием. Традиционные приемы построения ОС реального времени и привычные отработанные архитектурные решения здесь оказались неприменимы. В результате вся ОС и ее компоненты построены по принципу конечных автоматов – переходов из состояния в состояние.
Итак, TinyOS состоит из набора компонентов (каждый размером примерно 200 байт), из которых разработчики собирают систему для каждого конкретного сенсора. Для компоновки системы из набора компонентов, которые статически компонуются с ядром, используется специальный описательный язык. После проведения компоновки модификация системы не возможна.
Для обеспечения динамичности во время выполнения была разработана виртуальная машина, которая является надстройкой над ОС TinyOS. Код для виртуальной машины можно загрузить в систему во время выполнения. Для работы этой виртуальной машины необходимы 600 байт оперативной памяти и менее 8 KB памяти команд 8-битового микроконтроллера. Программы виртуальной машины представляются 8-битовыми инструкциями всего трех типов, объединяемых в "капсулы" – атомарные последовательности не более чем двадцати четырех инструкций.
Иерархическая структура сети получается автоматически благодаря тому, что все сенсоры следуют простым правилам, заложенным в TinyOS. Правила эти, к примеру, определяют способ поиска кратчайшего пути до ближайшего стационарного узла, а уже в зависимости от того, где и как расположены сенсоры, сеть принимает привычную для системных администраторов древообразную форму. В TinyOS учитывается также и то, что некоторые виды сенсоров могут работать от солнечных батарей или иных источников энергии, зависящих от погоды, поэтому при потере связи с ближайшим узлом сети происходит смена маршрута, по которому пересылаются пакеты.