Индекс
НазадОглавлениеВперед

Глава 9. Операционная система BeOS

9.1. Короткая история и позиционирование системы

Операционная система BeOS [36] разработана фирмой Be Inc., созданной в 1990 г. Первоначально фирма производила также и собственные компьютеры BeBox на базе процессора AT&T Hobbit, однако компьютеры BeBox не утвердились на рынке, и сейчас компания специализируется на программном обеспечении BeOS и созданном на ее основе пакете BeIA - интегрированном средстве работы в Internet.

Программное обеспечение Be работает на платформах Intel-Pentium, PowerMac и PowerPC. Последним релизом BeOS является версия 5. BeOS v.5 для некоммерческого использования распространяется свободно.

В основу создания BeOS была положена концепция "молодой" ОС, которая не будет обременена многолетним наследством и с самого начала будет построена с учетом некоторых реалий современных подходов к обработке информации - прежде всего мультимедийной информации и Internet. Наверное, в начале истории BeOS ее создатели имели "тайную мысль" создать универсальную ОС для настольного применения. Но выходить на рынок с таким предложением было рискованно, поэтому для новой ОС была найдена "экологическая ниша", в которой, по крайней мере в то время, у BeOS опасных конкурентов почти не было. Этой нишей стала разработка и выполнение мультимедийных приложений. Ориентация на мультимедиа была заложена в самые основы BeOS и продолжала развиваться во всех последующих версиях. В ходе дальнейшего развития BeOS так и не удалось выйти из своей первоначальной экологической ниши. Основной причиной этого, как обычно, называют отсутствие на платформе BeOS достаточного числа известных пользователям приложений. Более того, все более широкое обеспечение универсальных ОС (прежде всего - Windows) мультимедийными приложениями создает серьезную конкуренцию для BeOS и в ее собственной нише. В настоящее время фирма Be пытается внедриться в рынок Internet-вычислений, и эта ее попытка вполне оправдана, так как роль мультимедийной информации в этой области весьма велика и продолжает расти.

Как раз в те дни, когда писалась эта глава, на сайте компании Be появилось сообщение о том, что права интеллектуальной собственности на технологии Be куплены фирмой Palm Inc. Предполагается, что за этим последует полная интеграция Be Inc. в Palm.

Ориентация на мультимедиа наложила определенный отпечаток на структуру BeOS. Подобно QNX, BeOS строится на базе микроядра и процессов-серверов. Независимые серверы в сочетании с объектно-ориентированной структурой системы обеспечивают для ОС гибкость и простоту в наращивании функциональности.

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

BeOS обеспечивает API POSIX, однако нас интересуют прежде всего ее оригинальные системные интерфейсы. К сожалению, сколько-нибудь доступная информация о внутренней структуре BeOS не публикуется. Приводимые далее материалы в основном почерпнуты нами из информации для разработчиков приложений. Однако и они позволяют делать некоторые выводы (пусть косвенные) об устройстве BeOS. Следует отметить, что по своей структуре BeOS является объектно-ориентированной системой, поэтому в ней существует "двойная бухгалтерия" системных вызовов: они могут выполняться через обращения к библиотечным функциям С - и так реализованы интерфейсы POSIX, но могут выполняться также и через обращения к методам библиотечных объектов C++. Оба способа обеспечивают одинаковую функциональность практически во всем.

9.2. Потоки и команды

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

Новая нить порождается системным вызовом spawn_thread(), которому передается имя той функции, которая будет выполняться в нити и указатель на блок параметров функции нити. Созданная таким образом нить еще не выполняется. Она может быть запущена на выполнение системным вызовом resume_thread() или wait_for_thread(). В первом случае нить-потомок выполняется асинхронно, то есть, параллельно с нитью, ее породившей. Второй случай - синхронный запуск, выполнение породившей нити приостанавливается до завершения нити-потомка.

Мы говорим о нитях - родителе и потомке, однако на самом деле родственные отношения между порождающей и порожденной нитью весьма слабы. Системный вызов spawn_thread() возвращает нити-родителю идентификатор нити-потомка, но не обеспечивает наследования никаких ресурсов, кроме общих для всей команды. Нити выполняются независимо друг от друга, и выполнение нити-потомка продолжается даже после завершения родительской нити. Теоретически, даже завершение нити, в которой выполняется функция main(), не приводит к завершению всех порожденных ею нитей. Но именно нити main выделяются общие для всей команды статические объекты и ресурсы ввода-вывода, так что завершение нити main скорее всего приведет к аварийному завершению остальных нитей команды.

При создании нити ей может быть дано имя. Другая нить, желающая обратиться к данной, независимо от того, находится она в этой же команде или в другой, может использовать системный вызов find_thread(), который по имени нити возвращает ее идентификатор. Но идентификатор нити является уникальным во всей системе, а имя нити - не уникально. Вызов find_thread() возвращает идентификатор первой найденной нити с таким именем. Поэтому более надежным способом получения идентификатора нити является передача его нити-корреспонденту через глобальные переменные, параметры, средства взаимодействия и т.п.

Все нити выполняются параллельно, разделяя процессор (или процессоры) в соответствии с приоритетами. Приоритеты со значениями от 1 до 99 составляют класс приоритетов разделения времени, приоритеты со значениями 100 и выше - класс приоритетов реального времени.

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

Приоритеты реального времени абсолютные. Когда нить с приоритетом реального времени приходит в состояние готовности, она немедленно вытесняет с процессора нить с приоритетом разделения времени или нить с более низким приоритетом реального времени.

Приоритеты являются статическими: они задаются при создании нити и не изменяются в дальнейшем.

Нить может до некоторой степени управлять своим планированием, переходя в состояние приостанова на заданный интервал времени (системный вызов snooze()) или завершаясь (системный вызов exit_thread()).

Управление нитью "со стороны" - из другой нити, которой известен идентификатор управляемой, возможно следующее:

9.3. Средства взаимодействия

При создании каждой нити для нее создается буфер сообщения. Другая нить, знающая идентификатор нити-корреспондента, может записать в этот буфер сообщение системным вызовом send_data(), а нить - владелец буфера выбирает сообщение системным вызовом recive_data(). Однако буфер рассчитан только на одно сообщение, а попытки писать данные в занятый буфер или выбирать данные из пустого буфера приводят к блокировке нити.

Более гибким средством обмена данными между нитями является порт (port). Следует отметить, что порт не является прямым аналогом ни одного из средств взаимодействия процессов, рассмотренных нами в главе 9 части I. Порт представляет собой общесистемную очередь сообщений, работающую по дисциплине "первым пришел - первым вышел". В системе может быть создано сколько угодно портов. Любая нить из любой команды, которой известен идентификатор порта, может записать в порт сообщение (системный вызов write_port()) и прочитать из порта сообщение (системный вызов read_port()). При создании порта (системный вызов create_port()) задается его емкость - число сообщений, которое может сохраняться в порте. Попытка писать в переполненный порт или читать из пустого порта, естественно, приводит к блокировке нити. Однако, есть варианты системных вызовов (write_port_etс() и read_port_etc()), которые к блокировке не приводят. Но система поддерживает общий репозиторий портов, емкость которого равна суммарной емкости всех созданных портов, и переполнение происходит только при заполнении общей емкости.

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

Еще раз подчеркнем, что порт является только FIFO-очередью, и никаких средств неразрушающего чтения из порта не существует.

Семафоры в BeOS представляют собой традиционные общие семафоры. Семафор создается системным вызовом create_sem(), системные вызовы acquire_sem() и release_sem() обеспечивают традиционные семафорные операции P и V соответственно. Начальное значение семафора задается при его создании, но значение семафора может и превысить начальное, если операции release_sem() выполняются чаще, чем acquire_sem(). Семафор принадлежит той команде, в которой он был создан, и автоматически уничтожается с завершением последней нити этой команды. Явным образом семафор может быть уничтожен системным вызовом delete_sem(). Идентификатор семафора, который был возвращен вызовом create_sem(), может быть передан в другую команду, но право владения семафором не передается.

9.4. Управление памятью

В части управления памятью BeOS обеспечивает сегментную модель для приложений, однако, в ней "просматривается" сегментно-страничная реализация. Любая нить может запросить выделение для нее области (area) памяти. Область представляет собой непрерывный участок виртуальной памяти, размер которого задается в системном вызове create_area(). Размер области должен быть кратен размеру страницы (4 Кбайт). Операция создания области возвращает ее адрес в виртуальном адресном пространстве команды. При создании области нить может явно задать адрес в своем виртуальном адресном пространстве, по которому область должна быть размещена, но адрес размещения области обязательно выравнивается по границе страницы. Кроме того, при создании каждой новой области ей присваивается уникальный во всей системе идентификатор. Этот идентификатор может использоваться в вызове delete_area() или передаваться другим командам для совместного использования области.

Области также может быть присвоено имя. Системный вызов find_area() возвращает идентификатор области с заданным именем. Однако, как и в случае с нитями, имя области не является уникальным, и системный вызов find_area() возвращает идентификатор только первой найденной области.

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

Область явно уничтожается системным вызовом delete_area() или неявно - при завершении всех нитей команды, в которой область была создана. Если, однако, область была клонирована, то ее реальное освобождение происходит при уничтожении (явном или неявном) ее последнего клона.

При создании или клонировании области можно сделать ее защищенной от записи или защищенной от чтения.

При создании области можно также зафиксировать ее в реальной памяти, при этом имеются возможности:

9.5. Образы

Программные коды, готовые для выполнения, называются в BeOS образами (image). Различаются три вида образов:

Образы приложений являются загрузочными модулями программ. Для их загрузки и связывания применяется системный вызов load_image(). Параметром вызова является имя файла, из которого загружается образ приложения. Этот вызов в чем-то подобен вызову spawn_thread(). Он также создает новую нить. В этой нити будет выполняться функция main() приложения. Но этот вызов создает также и новую команду, "возглавляемую" нитью main запускаемого приложения, а следовательно, и новое виртуальное адресное пространство и другие общекомандные ресурсы. Как и spawn_thread(), load_image() возвращает идентификатор нити. Созданная таким образом нить должна быть запущена на выполнение теми же системными вызовами resume_thread() или wait_for_thread().

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

Дополнительные образы также являются совместно используемыми модулями динамической компоновки. Но их загрузка и связывание происходят по требованию, уже в процессе выполнения приложения. Загрузка такого модуля выполняется при помощи системного вызова load_add_on(), которому передается имя файла, содержащего дополнительный образ. Вызов load_add_on() возвращает идентификатор загруженного образа, который далее можно использовать в качестве параметра системного вызова get_image_symbol(), чтобы получить адреса внешних символов и входных точек дополнительного образа.

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

9.6. Устройства и файловые системы

Драйверы в BeOS являются расширениями ядра системы и могут работать в адресном пространстве ядра. В системе различаются три вида драйверов:

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

Обращения к драйверам из приложений выполняются через API POSIX (open(), read(), write() и т.д.). Перевод API POSIX во внутренние системные вызовы ядра BeOS осуществляет "файловая система устройств" devfs. Для того, чтобы драйвер был доступен для devfs, он должен быть записан (опубликован) в соответствующем каталоге иерархической файловой системы.

К сожалению, нам не удалось найти исчерпывающей информации о файловой системе BeOS, но даже та неполная информация, которую нам удалось получить, представляет существенный интерес.

Первая файловая система BeOS не имела иерархической структуры. Вместо этого логическая структура файловой системы поддерживалась "базой данных файлов". Навигация по логической структуре осуществляется средствами, напоминающими средства, принятые в реляционных базах данных - запросами. Поиск файла выполняется запросом, содержащим предикат (иногда довольно сложный), проверяющий значение одного или нескольких атрибутов файла. Хотя бы для одного из атрибутов, участвующих в предикате, должен быть создан индекс. Наряду с запросами, формулируемыми при каждом обращении, в системе существуют и "постоянно живущие" запросы - аналоги представлений (view) в реляционных базах данных. Подобно представлению, постоянный запрос представляет собой не зафиксированную выборку, а зафиксированный предикат, выборка же при каждом обращении выполняется заново. Постоянные запросы представляют собой функциональный аналог каталогов в иерархической файловой системе.

В 1997 г. для BeOS была разработана новая файловая система - BFS. В ней была введена иерархическая структура файловой системы и логическая структура в значительной степени интегрировалась с физической структурой хранения. Однако наряду с иерархической логической структурой BFS поддерживает и индексирование по именам и другим атрибутам файлов и, таким образом, в полном объеме сохраняется возможность альтернативной "реляционной" навигации по файловой системе.

Единицей распределения дискового пространства является блок, размер блока выбирается из ряда: 512 байт, 1 Кбайт, 2 Кбайт, 4 Кбайт, 8 Кбайт. Файл состоит из одного или нескольких экстентов, каждый экстент - целое число последовательных блоков. План размещения файла представляет собой массив описателей экстентов. Каталоги структурированы в виде B+-деревьев. Дескрипторы файлов и элементы каталогов разделены, но несмотря на это, BFS не поддерживает "жесткие" связи (алиасы), а только "мягкие" связи (косвенные файлы). В дескрипторе файла хранятся основные его атрибуты, расширенные же атрибуты хранятся вместе с данными файла.

С введением BFS была введена и концепция виртуальной файловой системы, обеспечивающая для BeOS возможность работы с файловыми системами различных форматов (CDFS и HFS от MacOS). Ядром BeOS формируется корневой каталог виртуальной файловой системы, в котором не могут находится файлы, а только подкаталоги и "мягкие" связи. Другие физические файловые системы монтируются как подкаталоги корневого каталога. Ряд подкаталогов и связей монтируются в корневой каталог автоматически, при загрузке системы. Также автоматически монтируются и еще две виртуальные файловые системы: /dev - виртуальная файловая система устройств и /pipe - виртуальная файловая система программных каналов.

Некоторые другие интересные свойства BFS также определяются спецификой этой файловой системы:

Интересен способ, который использует BeOS для определения типа файла, а следовательно, и приложения, по умолчанию связываемого с визуализацией и обработкой этого файла. В атрибутах файла обеспечивается идентификация типа в соответствии со спецификациями MIME (Multipurpose Internet Mail Extensions). Наряду со стандартными типами MIME, BeOS применяет также и собственные типы, не предусмотренные в MIME, но определяемые также в формате спецификации MIME. При отсутствии у файла MIME-специфицированных атрибутов для определения типа используется расширение файла, и BeOS ведет собственную "базу типов файлов", которые определяют связанные с типом-расширением приложения. BeOS также представляет пользователю возможность назначать собственные интерпретации типа для каждого файла или группы файлов.

Контрольные вопросы

  1. Переведите терминологию BeOS, относящуюся к управлению процессами и нитями, в принятую в части I данного учебного пособия.
  2. Какие оригинальные средства взаимодействия процессов применяются в BeOS?
  3. Какую модель памяти обеспечивает API BeOS?
  4. Сопоставьте "образы" BeOS с "ресурсами" Mac OS. Что между ними общее, в чем различия?
  5. Каковы оригинальные свойства файловой системы BeOS?
  6. Почему в файловой системе настольной BeOS обязательно должна обеспечиваться целостность?
  7. Охарактеризуйте правила диспетчеризации нитей в BeOS. Классифицируйте их в соответствии с классификацией главы 2 части I.

НазадОглавлениеВперед
Индекс