Миро Самек, Роберт Вард "Построение наипростейшего диспетчера задач" (перевод)


Реализация SST

Вначале будет рассмотрена минимальная рабочая конфигурация. Исходные тексты написаны на ANSI C. Для обеспечения переносимости все зависящие от компилятора и процессора детали отделены от остального текста. В данной реализации отсутствуют некоторые возможности, востребованные в реальных приложениях. Основная цель примера - продемонстрировать основные принципы, позволяя в то же время запускать его на любой PC-совместимой машине. Код собирался с использованием компилятора Turbo C++ 1.01, который можно свободно загрузить из музея фирмы Borland [4].

Пример, показанный на рисунке 5, показывает возможности SST по запуску и переключению нескольких потоков. Он состоит из трёх задач и двух обработчиков прерываний. Обработчик прерываний от системного таймера выдаёт таймерное событие ("tick event") каждые 5 миллисекунд. Обработчик прерываний от клавиатуры сообщает о "клавиатурном событии" ("key event") каждый раз, когда клавиша активируется или отпускается, либо воспроизводит его с частотой автоповтора, если клавиша зафиксирована в нажатом состоянии. Два связанных с таймерным событием процесса "tickTaskA()" и "tickTaskB()" получают такое событие и помещают буквы "A" или "B" соответственно в случайном месте правой панели экрана программы. Процесс "kbdTask()", чей приоритет находится между приоритетами "tickTaskA()" и "tickTaskB()", получает скан-коды клавиатуры, формирует соответствующие кодам "цветовые события" и передаёт их таймерным задачам, а те в ответ меняют цвет выводимых букв. Кроме того, по нажатию клавиши "Esc" "kbdTask()" завершает работу приложения.


Рисунок 5. SST, запущенный в среде разработки Turbo C++
Рисунок 5. SST в среде Turbo
          C++

Левая сторона экрана на рисунке 5 отдана под статистику работающей программы. Первые две колонки отображают имя задачи и её приоритет. Отметим большое число неиспользуемых уровней приоритета. Столбец "Calls" показывает три младшие цифры числа вызовов задачи, а последняя колонка "Preemptions" - число случаев асинхронного вытеснения указанного процесса или обработчика прерывания.

Два независимых прерывания (от системного таймера и клавиатуры) используются в данном примере намеренно: они создают условия для асинхронного перехвата управления. Для дополнительного увеличения вероятности перехвата в код вставлены вызовы функции "busyDelay()", которая удлиняет общее время работы задачи с помощью цикла задержки. Число проходов цикла задаётся в командной строке при запуске программы. Увеличивать его следует с осторожностью, так как при слишком больших значениях параметра активные процессы перестанут помещаться во временную сетку и система начнёт пропускать события.

В следующих секциях поясняется код SST и структура приложения. Полный набор исходных текстов состоит из заголовочного файла "include\sst.h" и файла реализации "source\sst.c". Исходные тексты примеров лежат в каталоге "example\" и включают файлы проекта Turbo C++, которые нужны для сборки и отладки программы. (Примечание: в связи с тем, что стандартный обработчик прерывания от клавиатуры заменяется кодом из примера, отладка приложения через среду Turbo C++ может быть затруднена).

Критические секции в SST

SST, как и любая другая операционная система, должен иметь возможность выполнять те или иные действия в непрерываемом режиме. Наипростейший и наиболее эффективный метод защиты участки кода от внешних воздействий - запрет прерываний при входе в защищаемую секцию и разрешение их при выходе из неё. Такие участки кода называют "критическими секциями".

Обычно в процессоре есть команды запрета / разрешения прерываний и используемые программные инструменты должны предоставлять способ выполнения таких действий средствами языка. Некоторые компиляторы позволяют включать в текст ассемблерные вставки, другие объявляют расширения языка, третьи предоставляют библиотечные функции для запрета и разрешения прерываний из языка высокого уровня.

Чтобы скрыть детали реализации в SST включены два макроса для работы с прерываниями. Вот как они определены для компилятора Turbo C++:


    #define SST_INT_LOCK()    disable()  
    #define SST_INT_UNLOCK()  enable()

				

В минимальной версии SST подразумевается самый простой вариант критических секций: безусловное запрещение прерываний на входе и безусловное разрешение их на выходе. Столь примитивные программные конструкции никогда не должны оказываться вложенными одна в другую, так как при выходе из скции прерывания всегда разрешаются без учёта состояния перед входом в неё. Диспетчер SST спроектирован так, чтобы никогда не допускать вложенности, но при использовании для защиты кода макросов "SST_INT_LOCK()" и "SST_INT_UNLOCK()" следует соблюдать осторожность. Указанное ограничение легко обойти, используя чуть более интеллектуальную (и немного более сложную) схему запрета и разрешения прерываний. Следует отметить, что невозможность иметь вложенные критические секции не означает невозможности иметь вложенные прерывания. Если вычислительное устройство содержит внутренний или внешний контроллер прерываний, подобный 8259A PIC в x86-совместимых PC или AIC в ARM-процессорах серии AT91, то становится возможным разрешение прерываний на уровне вычислительного ядра в коде обработчика (что исключает использование вложенных критических секций) и перекладывание забот по регистрации, приоритизации и вложенности прерываний с центрального процессора на аппаратный контроллер прерываний.

ПредпросмотрAttachmentSize
super_simple_tasker.zip293.38 КБ
sst_code.zip43.69 КБ