SWD Software Ltd. - официальный дистрибьютор QNX на территории России и стран бывшего СССР Операционная система реального времени QNX
Инструменты для создания надёжных встраиваемых систем и
интеллектуальных устройств любой сложности
QNX Software Systems - разработчик встраиваемой операционной системы QNX
  Стандартная версия

Операционная система Neutrino

Что такое Neutrino?

Это нечто быстрое, может даже быстрее летящей пули, и очень скоро оно сможет пилотировать самолеты или управлять поездами. Проще говоря, Neutrino – это высокопроизводительная ОС реального времени, способная работать со скоростью, требуемой для выполнения работы в реальном масштабе времени. Однако в отличие от других управляющих систем реального времени, Neutrino с самого начала спроектирована под стандарт реального времени POSIX, включая POSIX 1003.1a,1b (стандарт реального времени (realtime standard)), 1c (стандарт нитей (thread standard)) и 1d (эскизный стандарт на дополнительные расширения реального времени (draft standard on additional realtime extensions)). Важно помнить, что Neutrino 1.0 разработана не для того чтобы конкурировать с UNIX’ами, Windows NT или даже QNX 4.23. Вы можете использовать его в традиционных сферах применения систем реального времени, таких как, управление процессами, там, где у Вас есть компьютеры с 32М памяти, но наши изначальные планы нацелены на рынок глубоко встраиваемых систем.

Микроядро Neutrino

Neutrino – это живое доказательство того, что POSIX система может быть маленького размера. Само ядро занимает всего 32К и обеспечивает весь основной набор функций POSIX, необходимый для встраиваемых систем реального времени, включая нити (threads), передачу сообщений (message passing), сигналы (signals), таймеры (timers), обработчики прерываний (interrupt handlers), семафоры (semaphores), взаимоисключения (mutexes) и условные переменные (condvars) (смотрите таблицу). Также микроядро обеспечивает поддержку приоритетных прерываний (preemptable): если запрос на передачу сообщения был прерван, то микроядро возобновит передачу сообщения с того байта, где произошло прерывание.

Функции ядра Neutrino

  • ThreadCreate()
  • ThreadDestroy()
  • ThreadDetach()
  • ThreadJoin()
  • ThreadCancel()
  • ThreadPriv()
  • SchedGet()
  • SchedSet()
  • SchedYield()
  • SyncCreate()
  • SyncDestroy()
  • SyncMutexLock()
  • SyncCondvarWait()
  • SyncCondvarSignal()
  • SyncSemPost()
  • SyncSemWait()
  • SignalKill()
  • SignalReturn()
  • SignalAction()
  • SignalProcmask()
  • SignalSuspend()
  • SignalWaitinfo()
  • MsgSendv()
  • MsgSendvnc()
  • MsgReceivev()
  • MsgReplyv()
  • MsgReadiov()
  • MsgReadv()
  • MsgWritev()
  • MsgSendPulse()
  • MsgDeliverEvent()
  • MsgInfo()
  • MsgKeyData()
  • ChannelCreate()
  • ChannelDestroy()
  • ConnectAttach()
  • ConnectDetach()
  • ConnectServerInfo()
  • ConnectClientInfo()
  • ConnectNetCred()
  • TimerCreate()
  • TimerDestroy()
  • TimerGettime()
  • TimerSettime()
  • TimerGetoverrun()
  • TimerAlarm()
  • TimerTimeout()
  • ClockTime()
  • ClockAdjust()
  • ClockPeriod()
  • InterruptAttach()
  • InterruptDetach()
  • InterruptWait()

Администратор процессов Neutrino (ProcNto)

ProcNto расширяет сервис, предоставляемый ядром Neutrino, обеспечивая поддержку процессов, защиту памяти и администрирование области файловых путей (pathname space management), добавляя всего 32К кода к системе.

Для создания процесса в версии Neutrino 1.0, Вы должны использовать процедуру spawn(), которая описана в стандарте POSIX 1003.1d; версия 1.1 будет поддерживать fork() и exec*(). Как оказывается, имея только spawn() Вы не слишком ограничены в возможностях, так как он является наиболее общим случаем использования двух других функций: после выполнения fork() немедленно следует вызов exec() для создания нового процесса. Фактически, spawn() намного более эффективен, чем метод fork()-затем-exec(). Если у Вас уже есть проект, который использует fork(), чтобы запускать несколько копий кода, Вы можете использовать вызовы нитей (threads). (Мы не поддерживаем fork() в версии Neutrino 1.0, поскольку она требует MMU (Memory Management Unit) для запуска в режиме, где каждый процесс получает свое независимое пространство виртуальных адресов – это будет реализовано в версии 1.1.)

Модели защиты памяти

Наше управление памятью не сегментировано. Это чисто 32-битная плоская (flat), линейная архитектура.

Для большинства систем организация защиты памяти вызывает увеличение цены; однако снижение производительности не так значительно. Все наши исполнительные модули работают как с MMU, так и без него.

Вы можете выбрать любой из четырех уровней защиты памяти:

Тип защиты Затраты памяти на MMU
без защиты нет
система/пользователь (system/user) адресное пространство/4K
пользователь/пользователь (user/user) (основная в версии 1.0) 4K/процесс
пользователь/пользователь личная VM* от 4К до 8К/процесс

* Поскольку Neutrino версии 1.0 нацелена на встраиваемые системы, она не поддерживает эту модель.

Все модели поддерживают функцию spawn(). Мы ожидаем, что наиболее часто используемыми моделями будут модели без защиты (для систем без MMU) и с защитой пользователь/пользователь.

Модель без защиты

В этой модели каждый процесс в системе во время своей загрузки перемещается на абсолютные адреса физической памяти. MMU не используется, так что здесь нет различия или защиты между адресными пространствами пользователя и ядра. Все процессы работают в общем, разделяемом адресном пространстве. ProcNto загружает дополнительные процессы, перемещая их на ходу. В итоге Вы получаете линейное адресное пространство, которое начинается с 0 и идет до конца физической памяти, где каждый процесс может влиять на любой другой.

Такая конфигурация памяти хорошо подходит для дешевых встраиваемых процессоров, которые могут иметь недостаток страничных MMU (например, National Semiconductor NS486SXF, AMD 386SE/DE). Это типичный случай того, что предоставляют большинство программ и ядер реального времени.

И хотя в этой модели нет ни защиты, ни отображения виртуальной памяти, Neutrino предоставляет функцию mmap(), которая адаптируется к той модели памяти, в которой она работает. В результате, без всяких изменений в исходном или объектном коде, приложение может распределить память и использовать ее различными способами (доступ к аппаратной части, разделяемая между процессами память и т.д.), независимо от основных функций защиты памяти.

Модель защиты пользователь/пользователь

Здесь процессы пользователя защищены друг от друга. Все элементы таблицы страниц, кроме тех, которые предназначены для выполняющегося процесса, помечаются как “системные”. Каждый раз, когда возникает переключение контекста процесса, ядро устанавливает системный флаг в таблице страниц для процесса, с которого было произведено переключение, и очищает его в таблице страниц для нового процесса. Такая простая схема защиты памяти прекрасно работает на Intel архитектуре. (Смотрите диаграмму).

Объекты разделяемой памяти

Основой системы памяти являются объекты разделяемой памяти. Вы можете:

  • распределять разделяемую память между процессами
  • распределять непрерывную физическую память
  • отображать физическую память в адресное пространство процессов

Разделяемая память предлагает самый быстрый метод обмена информацией между процессами (IPC), который только может быть. Как только создается объект разделяемой памяти, процессы, имеющие доступ к объекту, могут использовать указатели для прямого чтения и записи в него. Это означает, что доступ к разделяемой памяти является не синхронизированным. Если процесс изменяет область разделяемой памяти, то нужно позаботиться о предотвращении чтения или изменения той же самой области другим процессом. Даже при простом чтении, другой процесс может получить информацию, которая уже изменилась, и является некорректной.

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

Семафоры и взаимоисключения – как раз подходят для того, чтобы выступать в роли синхронизирующих примитивов, предназначенных для работы с разделяемой памятью. Семафоры были представлены в POSIX.1b - стандарте на синхронизацию процессов в реальном масштабе времени; взаимоисключения - в POSIX. 1c - стандарте на синхронизацию нитей. Взаимоисключения могут быть также использованы между нитями в разных процессах. POSIX рассматривает это, как вспомогательную функцию; Neutrino поддерживает ее. Самое важное, что взаимоисключения являются более эффективными, чем семафоры.

Функция mmap() обеспечивает интерфейс непосредственно с разделяемой памятью. Используя ее флаги отображения, процесс может с легкостью распределять память между процессами:

/* Отображение в область разделяемой памяти */

fd = shm_open(“/datapoints”, O_RDWR, 0);

addr = mmap(0, len, ROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

или распределить память с аппаратной частью, например видео памятью:

/* Отображение в область памяти VGA дисплея */

addr = mmap(0, 65536, PROT_READ|PROT_WRITE,

MAP_PHYS|MAP_SHARED, NOFD, 0xa0000);

или разместить непрерывный DMA буфер для сетевой PCI карты:

/* Размещение физически непрерывного буфера */

addr = mmap(0, 262144, PROT_READ|PROT_WRITE|PROT_NOCACHE,

MAP_PHYS|MAP_ANON, NOFD, 0);

Архитектура файловой системы

Несмотря на то, что они полностью совместимы на уровне структуры данных на диске, файловые системы Neutrino и QNX 4 имеют различную архитектуру. В QNX4, файловая система – это процесс, обращающийся к драйверу; здесь файловая система – управляющий элемент. В Neutrino, драйвер – это процесс, который вызывает код файловой системы; в данном случае драйвер является управляющим элементом.

В нашу эпоху сменных носителей информации, со сменой которых меняется и файловая система, формат же самого носителя остается постоянным, такая архитектура работает превосходно. Допустим, у вас есть EIDE контроллер и драйвер устройств EIDE. Драйвер устройств - это просто код, который общается с EIDE контроллером, и он первый, кто начинает работать при запуске системы. Теперь предположим, что у вас есть сменный носитель, который Вы вставили в устройство. Драйвер устройств видит, что кассета вставлена и говорит: “Теперь мне нужна служба уровня доступа к блокам для их чтения и записи и организации таких устройств как /dev/hd0.” Для этого он привлекает динамически загружаемую библиотеку (DLL) ввода/вывода блоков. Затем он говорит, “Ой, посмотрите сюда… тут же файловая система QNX, и файловая система CD-ROM тоже, и еще куча других файловых систем”. Затем он загружает необходимые DLL, и на лету оживают файловые системы для управления QNX, CD-ROM и всем остальным.

Выбор файловой системы QNX/Neutrino

Когда приходит время выбора файловой системы для Ваших программ, Neutrino предлагает Вам чрезвычайную гибкость (смотри рисунок).

Файловая система на базе имиджа ОС (Image filesystem)

Для встраиваемых систем и многих маленьких систем, Вам не обязательно иметь внешнюю файловую систему. Имидж каждой QNX системы, который включает в себя ProcNto, поддерживает простую систему, предназначенную только для чтения, которая представляет собой набор исполняемых файлов или файлов данных, встроенных в имидж ОС. Если требуются дополнительные файловые системы, Вы можете поместить их как модули внутри имиджа, где они могут запускаться по мере необходимости.

Файловая система на основе объектов памяти (Memory-object filesystem)

ProcNto позволяет Вам создавать файлы в директории /dev/shmem. Эти файлы представляются как объекты в памяти, открывая Вам файловую систему RAM-диска, размер которого может расти или сокращаться динамически. Например, чтобы сделать /tmp RAM диском, Вы можете просто набрать: ln –sP /tmp /dev/shmem.

Файловая система QNX

Поскольку Вы не хотите высокопроизводительных файловых систем с размером кода 160К и с размером кэш 500К, для встраиваемых систем, файловая система QNX – это крошечный вариант файловой системы QNX 4. Эта файловая система поддерживает:

  • структуру данных на диске, полностью соответствующую стандарту POSIX (формат данных полностью совместим с QNX 4)
  • ограниченные эвристики кэш
  • поддержка 48-символьных имен файлов
  • поддержка жестких связей (hard links)
  • полная поддержка символических связей (symbolic link), так что она может обрабатывать, читать и создавать символические связи

Файловая система CD-ROM

Файловая система CD-ROM обеспечивает прозрачный доступ к CD-ROM устройствам, так что Вы можете рассматривать файловые системы CD-ROM, как файловые системы POSIX. Эти файловые системы соответствуют стандарту ISO9660, включая расширения Rock Ridge.

Файловая система для флэш-памяти

Эта файловая система разработана для работы с флэш-памятью. Файлы, записанные на сменный флэш-носитель, такой как PC карты, можно переносить в другие системы, которые поддерживают этот стандарт. Также поддерживаются файлы в сжатом формате.

Файловая система CIFS (Common Internet File System)

Эта файловая система обеспечивает приложениям Neutrino прозрачный доступ к подключенным через сеть Windows 95 или NT серверу. Запросы клиента на доступ к файлу преобразуются в запросы CIFS протокола и передаются серверу через сеть. Сервер принимает запрос, выполняет требуемую операцию над файловой системой, и затем отсылает ответ клиенту.

Символьный ввод/вывод

Любая операционная система реального времени требует высокопроизводительного символьного ввода/вывода.

Поддерживаются следующие символьные устройства:

  • последовательные порты
  • параллельные порты
  • текстовые консоли
  • псевдо-терминалы (ptys)

TCP/IP

У нас есть крошечный, уменьшенный TCP/IP, который помещается в 50К. Он разработан для реализации клиентской части, но никак не сервера. Мы реализовали большую часть RFC, ARP, TCP, ICMP, UDP и IP. Сложные таблицы и динамические протоколы маршрутизации не поддерживаются со стороны клиентской части.

В версии 1.1 мы усовершенствуем производительность благодаря таким свойствам как протокол динамической настройки узла. Мы, конечно, реализуем BSD в полном объеме по мере развития Neutrino и продвижения его от компактной, встраиваемой до полномасштабной системы.

Компиляция для Neutrino

Компиляция Вашего кода для Neutrino полностью аналогична QNX 4, за исключением того, что мы добавили в cc опцию –v nto, чтобы Вы могли указать, какую версию компилятора запускать. Это такая же опция, какую мы представляли в Watcom 10.6, где Вы можете выбирать между версией 9.5 или 10.6.

Опция –v nto также использует заголовки и файлы библиотек Neutrino, и создает исполнительные модули в формате ELF (не в QNX или OMF). Мы выбрали ELF, потому что это 32-х битный многоплатформенный стандарт, имеющий поддержку DLL и модели выполнения-на-месте (execute-in-place), он подходит для виртуальных машин (VM) и систем подкачки страниц, а также широко используется во всех современных UNIX системах.

Инструментальная цепочка Neutrino

Инструментальная цепочка Neutrino похожа на таковую в QNX 4. Например, Вы используете компиляторы Watcom (C, C++, ассемблер) для создания объектного файла OMF. Затем, мы меняем OMF на ELF, и пропускаем его через нашу утилиту, ld (редактор связей, создающий исполняемые модули в формате ELF) и ar (библиотекарь общего назначения).

Отладка

В Neutrino мы предоставляем два метода отладки: на уровне ядра и на уровне процесса. Оба допускают полную символьную отладку.

Отладка на уровне ядра

Вы можете отлаживать всю операционную систему, прикладную программу, а также обработчики прерываний. Когда отладчик производит контрольный останов, вся система замирает – все процессы, нити, система прерываний - и агент отладки берет полный контроль над системой, общаясь с wd (Watcom Debugger). Связь между агентом и самим отладчиком может поддерживаться как через параллельный, так и через и последовательный интерфейс.

Отладка на уровне процесса

На уровне процесса Вы можете отлаживать один или более процессов (включая порожденные процессы), но Вы не можете отлаживать обработчики прерываний. Когда отладчик делает контрольный останов - весь процесс (все нити) останавливаются, но остальная система продолжает работать. Связь между агентом и отладчиком может поддерживаться через параллельный и последовательный интерфейсы, а также через протокол TCP/IP.

Настройка

BIOS не нужен

Для начала работы Neutrino, образ ОС должен быть доступен в линейно адресуемом адресном пространстве памяти. Обычно эту работу выполняет BIOS, но системы, ограниченные в цене не могут его иметь, во-первых, потому, что это требует соответствующего лицензирования, а во-вторых, по соображениям экономии памяти. Принимая во внимание эти причины, мы сделали несколько допущений в Neutrino:

  • Вам не нужен BIOS. Мы снабжаем Вас Загрузчиком Начальной Программы QNX (QNX Initial Program Loader или IPL) для замещения BIOS во встраиваемых системах.
  • Поскольку каждая встраиваемая система уникальна, она требует соответствующей настройки IPL.
  • Вы будете писать свой собственный IPL, – а мы обеспечивать Вас инструментальным пакетом разработчика и всеми исходными кодами, с примерами.

Пользовательские загрузчики

Загрузка Neutrino состоит из трех строго определенных шагов:

  1. Загрузка образа ОС (IPL)
  2. После перезагрузки ЦПУ, IPL получает управление, находит место расположения образа Neutrino, настраивает среду для этапа запуска и инициализирует аппаратное обеспечение для перехода ко второму шагу. IPL написан в позиционно-независимом ассемблерном коде.

  3. Запуск ОС
  4. Этот этап настраивает процессор и аппаратное обеспечение, определяет системные ресурсы, запускает образ ОС, собирает информацию о системе и затем передает управление ProcNto. Функции этого этапа написаны на C.

  5. Запуск исполняемых модулей

Запускаются нужные Вам исполняемые модули.

Сжатие

Мы поддерживаем полное сжатие образа. Мы используем кодирование парными байтами (byte-pair encoding или BPE), которое позволяет сжать образ примерно на 50%.

Будущее QNX/Neutrino

Операционная система Neutrino рассчитана на использование в глубоко встраиваемых системах, где невозможно использование QNX 4. На рынках, на которые мы нацеливаемся в дальнейшем, пользователи хотят иметь возможность взаимодействия с Internet, поддержку TCP/IP и стандартных протоколов. Мы будем работать над этим начиная с 1997 года, продолжая добавление функциональных возможностей в Neutrino:

  • Набор утилит POSIX
  • Photon
  • Willows Win32 API
  • Набор программ для Internet
  • Java
  • инструменты разработки

Dan Dodge, Co-founder, QSSL
Перевод: А. Николаев, С. Ющенко
QNX News 3&4/1996