· Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб...

160
Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил Уинтерботтом Bell Laboratories, Мюррей Хилл, Нью-Джерси 07974 США Мотивация К середине 80-х годов наметилась тенденция отхода от больших централизованных компьютеров, работающих в режиме разделения времени, и переориентации на сети из небольших персональных машин (как правило, из рабочих Unix-станций). Пользователям надоели вечно перегруженные «бюрократические» машины с разделением времени, и они стремились перейти на небольшие системы, которые могли обслуживать сами, даже если это влекло за собой потерю в вычислительной мощности. Микрокомпьютеры становились быстрее, и эти потери компенсировались. Такой стиль вычислений остается популярным и сегодня. При переходе к персональным рабочим станциям, однако, не были учтены некоторые их недостатки. Во-первых, операционная система Unix была старой и работала в режиме разделения времени; возможности ее адаптирования к новым технологиям, появившимся позже, были весьма ограничены. Графические и сетевые возможности были добавлены к Unix еще в период ее расцвета и оставались плохо интегрированными и трудноуправляемыми. И самое важное, ранняя ориентация на персональные машины сделала невозможной беспроблемную работу сетей, характерную для старых монолитных систем с разделением времени. Разделение времени способствовало централизации управления и амортизации затрат и ресурсов; при появлении персональных вычислений до предела обострились административные проблемы. Выбор старой операционной системы с разделением времени для работы на этих персональных машинах был бы неоправдан. Работы по ОС Plan 9 начались в конце 80-х годов. При этом преследовались две цели: система, построенная из дешевых современных микрокомпьютеров, должна была управляться централизованно и при этом быть недорогой. Идея заключалась в том, чтобы построить систему с разделением времени не только из рабочих станций. Различные компьютеры выполняли бы различные задачи: маленькие дешевые машины в офисах могли бы служить терминалами, обеспечивая доступ к большим, центральным, совместно используемым ресурсам, таким как вычислительные и файловые серверы. Очевидными кандидатами на роль центральных машин представлялись появившиеся многопроцессорные системы с разделением памяти. Проблемы ОС Unix были слишком глубоки, чтобы их можно было разрешить, однако некоторые ее особенности могли бы найти в дальнейшем свое применение. Это, в первую очередь, использование файловой системы для координирования именования ресурсов и доступа к ним, даже тех (например, устройств), интерпретация которых как файлов нетрадиционна. Для Plan 9 мы приняли эту идею, построив протокол сетевого уровня, названный 9Р, так, чтобы обеспечить машинам доступ к файлам на удаленных системах. Сверх того, была разработана система наименования, которая позволяет пользователям и их вычислительным агентам строить собственные представления ресурсов в сети. Именно здесь Plan 9 впервые начала отличаться от других операционных систем: ее пользователь строит

Transcript of  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб...

Page 1:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Plan 9 от Bell LabsРоб ПайкДейв ПресоттоШон ДоруордБоб ФландренаКен ТомпсонГовард ТрикиФил УинтерботтомBell Laboratories, Мюррей Хилл, Нью-Джерси 07974 США

Мотивация

К середине 80-х годов наметилась тенденция отхода от больших централизованных компьютеров, работающих в режиме разделения времени, и переориентации на сети из небольших персональных машин (как правило, из рабочих Unix-станций). Пользователям надоели вечно перегруженные «бюрократические» машины с разделением времени, и они стремились перейти на небольшие системы, которые могли обслуживать сами, даже если это влекло за собой потерю в вычислительной мощности. Микрокомпьютеры становились быстрее, и эти потери компенсировались. Такой стиль вычислений остается популярным и сегодня.

При переходе к персональным рабочим станциям, однако, не были учтены некоторые их недостатки. Во-первых, операционная система Unix была старой и работала в режиме разделения времени; возможности ее адаптирования к новым технологиям, появившимся позже, были весьма ограничены. Графические и сетевые возможности были добавлены к Unix еще в период ее расцвета и оставались плохо интегрированными и трудноуправляемыми. И самое важное, ранняя ориентация на персональные машины сделала невозможной беспроблемную работу сетей, характерную для старых монолитных систем с разделением времени. Разделение времени способствовало централизации управления и амортизации затрат и ресурсов; при появлении персональных вычислений до предела обострились административные проблемы. Выбор старой операционной системы с разделением времени для работы на этих персональных машинах был бы неоправдан.

Работы по ОС Plan 9 начались в конце 80-х годов. При этом преследовались две цели: система, построенная из дешевых современных микрокомпьютеров, должна была управляться централизованно и при этом быть недорогой. Идея заключалась в том, чтобы построить систему с разделением времени не только из рабочих станций. Различные компьютеры выполняли бы различные задачи: маленькие дешевые машины в офисах могли бы служить терминалами, обеспечивая доступ к большим, центральным, совместно используемым ресурсам, таким как вычислительные и файловые серверы. Очевидными кандидатами на роль центральных машин представлялись появившиеся многопроцессорные системы с разделением памяти.

Проблемы ОС Unix были слишком глубоки, чтобы их можно было разрешить, однако некоторые ее особенности могли бы найти в дальнейшем свое применение. Это, в первую очередь, использование файловой системы для координирования именования ресурсов и доступа к ним, даже тех (например, устройств), интерпретация которых как файлов нетрадиционна. Для Plan 9 мы приняли эту идею, построив протокол сетевого уровня, названный 9Р, так, чтобы обеспечить машинам доступ к файлам на удаленных системах. Сверх того, была разработана система наименования, которая позволяет пользователям и их вычислительным агентам строить собственные представления ресурсов в сети. Именно здесь Plan 9 впервые начала отличаться от других операционных систем: ее пользователь строит

Page 2:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

К 1989 году система стала настолько устойчивой, что ее начали использовать в качестве единственной среды вычислений. Это означало необходимость перенесения многих служб и приложений, которые ранее применялись в ОС Unix. Мы использовали эту возможность, чтобы пересмотреть многие вопросы, связанные не только с резидентным ядром, которые Unix, как нам казалось, выполняла недостаточно хорошо. Plan 9 имеет новые компиляторы, языки, библиотеки, оконные системы и разнообразные новые приложения. Многие из старых инструментальных средств были опущены, а те, что оставлены, написаны заново или отлажены.

Почему было необходимо пересмотреть столь многое? Различия между операционной системой, библиотекой и приложением важны для исследователя операционных систем, но неинтересны для пользователей. Для них значение имеет только функциональность. Создавая полностью новую систему, мы смогли решить многие проблемы, которые, по нашему мнению, должны были быть решены. Например, в ядре реально отсутствует «драйвер tty», он является результатом работы оконной системы. В современном мире вычислительные системы в силу необходимости являются многоархитектурными и составлены из продуктов многих поставщиков, однако обычные компиляторы и инструментальные средства предполагают, что программа должна быть построена для работы в локальной среде. Важнее, однако, то, что определенным тестом для системы служит вычислительная среда, которую она предоставляет. Обеспечение большей эффективности при работе старых программ — «рабочих лошадок» Unix — было только делом техники; гораздо более мы были заинтересованы в том, чтобы новые идеи, предлагаемые архитектурой основополагающей системы, способствовали повышению эффективности работы. Таким образом, хотя Plan 9 обеспечивает среду эмуляции для выполнения команд POSIX, это не главное в системе. Большая часть системного ПО разработана в «родной» среде Plan 9.

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

Конструкция

Система построена на трех принципах. Во-первых, ресурсы именуются и к ним можно получить доступ как к файлам в иерархической файловой системе. Во-вторых, имеется стандартный протокол, называемый 9Р, для доступа к этим ресурсам. И, наконец, несвязанные иерархии, обеспечиваемые различными службами, соединяются вместе в единое личное иерархическое пространство имен файлов. Необычные свойства Plan 9 обусловлены целенаправленным последовательным применением этих принципов.

Крупная инсталляция Plan 9 состоит из ряда компьютеров, соединенных в сеть и предоставляющих каждый услуги определенного класса. Совместно используемые многопроцессорные серверы обеспечивают выполнение вычислительных циклов; другие большие машины служат хранилищами файлов. Эти машины расположены в помещении с

Page 3:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

кондиционированием воздуха и соединены высокопроизводительной сетью. Сети с меньшей пропускной способностью, такие как Ethernet или ISDN, соединяют эти серверы с офисными или домашними рабочими станциями или ПК, называемыми в терминологии Plan 9 терминалами. Рис. 1 показывет их размещение

Современный стиль вычислений предполагает наличие для каждого пользователя выделенной рабочей станции или ПК. Plan 9 использует принципиально другой подход. Хотя она может функционировать и на рабочей станции с файлами, хранящимися на локальном диске, такая конфигурация не является канонической. Вместо этого машины с дисплеями, клавиатурами и мышами получают доступ к большинству вычислительных ресурсов и систем хранения по сети, становясь терминалами системы, подобно терминалам старой системы с разделением времени. При использовании Plan 9, терминал временно персонализируется этим пользователем. Принцип построения аппаратуры под пользователя здесь не работает: Plan 9 предлагает возможность программными средствами изменить то, как она пользователем воспринимается. Эта подстройка сопровождается приданием публично видимым ресурсам в сети локальных персональных имен. Plan 9 обеспечивает механизм организации персонального представления общего пространства с локальными именами глобально доступных ресурсов. Так как наиболее важными ресурсами сети являются файлы, модель этого представления ориентирована на файлы.

Локальные пространства имен предоставляют способ реализации представления сети «под себя». Все службы, доступные в сети, экспортируют иерархии файлов. Те из них, которые важны для пользователя, собираются вместе в личное пространство имен; не представляющие в данное время интереса игнорируются. Этот стиль использования отличается от «однородного глобального пространства имен». В Plan 9 имеются известные имена для служб и унифицированные имена для файлов, экспортированных этими службами, однако их представление полностью локально. Примером может служить разница между словосочетанием «мой дом» и четко сформулированным точным адресом. Последний может быть использован каждым, тогда как первое используется только в разговорной речи: смысл фразы меняется в зависимости от того, кто и когда ее произносит, однако она считается понятной. Подобным образом в Plan 9 имя /dev/mouse всегда относится к мыши, а

Page 4:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

/bin/date — это команда вывода даты, но то, какие файлы эти имена представляют, зависит от обстоятельств, например, от архитектуры машины, исполняющей команду date. Plan 9, таким образом, имеет локальные пространства имен, которые подчиняются глобальным соглашениям; именно эти соглашения гарантируют разумное поведение при наличии локальных имен.

Протокол 9Р структурирован как набор транзакций, каждая из которых посылает запрос от процесса клиента локальному или удаленному серверу и возвращает результат. 9Р контролирует файловую систему, а не только файлы; он включает процедуры для различения имен файлов и преобразования иерархии имен файловой системы, предоставляемой сервером. С другой стороны, в отличие от таких систем, как Sprite [7], пространство имен пользователя поддерживается только системой клиента, а не на сервере или с его помощью. Кроме того, доступ к файлам происходит на уровне байтов, а не блоков, что отличает 9Р от таких протоколов, как NFS и RFS. Дальнейшее сопоставление можно найти в работе [13].

Хотя Plan 9 изначально предназначалась для работы с традиционными файлами, ее идеи были распространены и на многие другие ресурсы. Службы Plan 9 по экспорту иерархий файлов включают устройства ввода/вывода, резервного копирования, оконную систему, сетевые интерфейсы и многое другое. Одним из примеров может быть команда файловой системы /proc, которая обеспечивает ясный способ исследования текущих процессов и управления ими. Прекурсорные системы имеют в основе подобную же идею [5], однако в Plan 9 метафора файлов развита много дальше [9]. Модель файловой системы хорошо понятна как разработчикам систем, так и обычным пользователям, так что службы, имеющие файлово-подобные интерфейсы легко построить, понять и использовать. Файлы поступают со знакомыми, унифицированными правилами защиты, наименования и доступа (как локального, так и удаленного), поэтому службы, построенные таким образом, готовы для использования в распределенных системах. (В этом заключается отличие от «объектно-ориентированных» моделей, где с этими аспектами приходится заново иметь дело для каждого класса объектов.) В последующих разделах приведены примеры, иллюстрирующие эти идеи на практике.

Представление на командном уровне

Plan 9 предназначена для использования на машинах с дисплеем и функционирующей оконной системой. Она не имеет представления о «телетайпе» в том смысле, какой присущ Unix. Работа с клавиатурой в основной системе находится на рудиментарном уровне, однако при функционировании оконной системы 8½ [8] текст можно редактировать с помощью операций «вырезать и вклеить» из всплывающих меню, копировать между окнами и т.д. 8½ позволяет редактировать текст в предыдущей, а не только в текущей строке. Редакторские возможности достаточно мощны для перемещения таких специальных функций, как история, в оболочку, для разбивки на страницы и прокрутки и редактирования почты. Окна 8½ не поддерживают адресацию курсора и, кроме одного терминального эмулятора для упрощения связи с традиционными системами, в Plan 9 отсутствует ПО для адресации курсора.

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

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

Page 5:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

графическим ресурсам через файлы типа /dev/mouse, /dev/bitblt и /dev/cons (аналогично /dev/tty в Unix). Эти файлы предоставляются редактором 8½, выступающим в роли файлового сервера. В отличие от системы Х Window, где новое приложение обычно создает новое окно, в котором и исполняется, графическое приложение 8½ обычно выполняется в том окне, где стартует. Возможным и эффективным для приложения является создание нового окна, но это не в стиле системы. В отличие от Х Window, где удаленное приложение для начала выполнения делает сетевой вызов Х-серверу, удаленное приложение 8½ видит файлы mouse, bitblt и cons для окна как обычно в /dev. Оно не знает, локальные ли это файлы, а просто читает и записывает их для управления окном; сетевая связь уже присутствует и мультиплексируется.

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

Набор команд Plan 9 подобен таковому у Unix. Команды разделяются на несколько обширных классов. Некоторые из них представляют собой новые программы для выполнения старой работы: программы, подобные ls, cat и другим, имеют знакомые имена и функции, но это новые, более простые их версии. Команда who, например, является командным файлом, а ps — просто 95 строк кода С. Некоторые команды с необходимостью совпадают с их предшественниками в Unix awk, troff и другие были конвертированы в ANSI С и расширены для обработки Unicode, но все еще представляют собой знакомые инструменты. Другие команды — полностью новые программы, заполняющие старые ниши: командный интерпретатор rc, текстовый редактор sam, отладчик acid и другие заменяют хорошо известные инструменты Unix, выполняя подобные же функции. Наконец, около половины команд совсем новые.

К системе не предъявлялось требование совместимости. Когда старые команды или обозначения казались достаточно хорошими, мы их сохраняли. Когда это было не так, мы их заменяли.

Файловый сервер

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

У файлового сервера три уровня хранения. Центральный сервер в нашей инсталляции имеет буферную память объемом около 100 MB, магнитный диск емкостью 27 GB и дисковод с автоматической сменой WORM-дисков общей емкостью 350 GB как основной накопитель. Магнитный диск — не что иное как кеш-память для WORM-дисковода, а буферная память — кеш для диска; каждый уровень намного быстрее и видит трафик примерно на порядок больший, чем уровень, который он кеширует. Объем адресуемых данных в файловой системе может быть больше, чем объем магнитных дисков, поскольку они являются только кешем; наш главный файловый сервер имеет около 40 GB активного объема хранения.

Page 6:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Наиболее необычная черта файлового сервера обусловлена использованием WORM-устройства для постоянного хранения. Каждое утро в 5 часов автоматически происходит дамп файловой системы. Система замораживается, и все блоки, модифицированные со времени последнего дампа, становятся в очередь для записи на WORM. После этого служба восстанавливается, и в иерархии всех дампов, когда-либо проведенных, появляется корневой каталог выведенной файловой системы с атрибутом «только для чтения», названный по дате создания. Например, каталог /n/dump/1995/0315 — корневой для образа файловой системы в том виде, каком он был на раннее утро 15 марта 1995 года. Создание очереди из блоков занимает несколько минут, однако процесс копирования блоков на WORM, который происходит в фоновом режиме, может занять часы.

Возможны два способа использования дампа файловой системы. Во-первых, сами пользователи могут непосредственно просматривать дамп или присоединять его участки к своему пространству имен. Например, чтобы выявить причину ошибки, естественно попробовать откомпилировать программу из ее состояния три месяца назад или связать программу со вчерашней библиотекой. Имея ежедневную картину всех файлов, легко обнаружить, когда было сделано конкретное изменение или какие изменения были сделаны в конкретный день. Рискуя делать большие изменения в файлах, пользователи чувствуют себя более свободно, сознавая, что они могут вернуться назад с помощью одной команды копирования. Система собственно резервного копирования отсутствует; вместо нее, имея в арсенале дамп в пространстве имен файлов, проблемы резервного копирования можно разрешить с помощью стандартных инструментальных средств, такие как команды ср, ls, grep и diff.

Другое (очень редкое) использование — это резервное копирование всей системы. В случае повреждения, активная файловая система может быть инициализирована из любого дампа очисткой дискового кеша и введением установки, чтобы корневой каталог активной файловой системы был копией корневого каталога дампа. Но не надо думать, что все так просто: кроме потерь всех изменений, сделанных после даты дампа, этот метод восстановления приводит к очень медленной работе системы. Кеш должен быть перезагружен из WORM, который намного медленнее, чем магнитные диски. Файловой системе потребуется несколько дней, чтобы перезагрузить рабочий набор и восстановить полную производительность.

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

После того, как файл записан на WORM-диски, он не может быть перемещен, поэтому наши пользователи никогда не видят сообщения «сотрите, пожалуйста, ваши файлы», и в системе отсутствует команда df. Мы считаем дисковод WORM неограниченным ресурсом. Единственный вопрос заключается в том, сколько времени потребуется на его заполнение. Наш накопитель WORM служил сообществу из почти 50 пользователей в течение 5 лет и поглотил ежедневные дампы, заполнив 65 % своей емкости. Сейчас его производитель улучшил технологию, удвоив емкость отдельных дисков. Если бы мы перешли на новую среду, мы могли бы иметь больше свободного пространства, чем исходный пустой накопитель. В результате развития технологии емкость систем хранения растет быстрее, чем мы можем ее использовать.

Необычные файловые серверы

Plan 9 характеризуется множеством необычных серверов с файловоподобными

Page 7:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Возможно, наиболее заметным файловым сервером в Plan 9 можно назвать оконную систему 8½. Она уже рассматривалась подробно [8], но стоит привести здесь ее краткое описание. 8½ обеспечивает два интерфейса: пользователю, сидящему перед терминалом, она предлагает взаимодействие в традиционном стиле с множеством управляемых с помощью мыши и клавиатуры окон, в каждом из которых выполняется приложение. Для клиентских программ вид также достаточно традиционен: программы, выполняющиеся в окне, видят набор файлов в /dev с именами типа mouse, screen и пр. Программы, которым необходимо напечатать текст в своем окне, производят запись в /dev/cons; чтобы обратиться к мыши, они считывают /dev/mouse. В стиле Plan 9 побитовая графика применятся обращением к файлу /dev/bitblt, куда клиенты записывают кодированные сообщения для исполнения таких графических операций, как bitblt (RasterOp). Необычно то, как это делается: 8½ является файловым сервером, предоставляющим файлы из каталога /dev клиентам, работающим в каждом окне. Хотя каждое из окон выглядит для ее клиентов одинаково, все они имеют отдельные наборы файлов в /dev. 8½ мультиплексирует доступ своих клиентов к ресурсам терминала путем обслуживания множества наборов файлов. Каждому клиенту предоставляется личное пространство имен с различным набором файлов, которые одинаково работают и во всех других окнах. Такая структура имеет много преимуществ. Одно из них заключается в том, что 8½ обслуживает те же файлы, которые необходимы для его собственного внедрения (он мультиплексирует свой собственный интерфейс), и поэтому может работать рекурсивно, как клиент самого себя. Кроме того, рассмотрим внедрение /dev/tty в Unix, требующее специального кода в ядре для перенаправления вызовов open соответствующим устройствам. Вместо этого в 8½ эквивалентная служба выпадает автоматически: 8½ обслуживает /dev/cons как свою основную функцию; ничего другого он не делает. Когда программа хочет считать с клавиатуры, она открывает /dev/cons, но это личный файл, а не совместно используемый со специальными свойствами. Снова это становится возможным из-за локальности пространства имен; соглашения о совместимости файлов делают эту возможность легко осуществимой.

8½ имеет уникальную особенность, вытекающую из ее строения. Реализуясь как файловый сервер, он обладает возможностью отложенного ответа на запросы чтения для конкретного окна. Эта опция переключается зарезервированной клавишей клавиатуры. Нажав ее один раз, вы приостановите чтение клиента из окна; повторное нажатие восстанавливает нормальное чтение, которое построчно поглощает любой текст. Таким образом, пользователь сможет редактировать многострочный входной текст на экране до того, как приложение видит его; устраняется необходимость включения отдельного редактора для подготовки текста, например, почтовых сообщений. С этим связана и возможность ответа на считывания непосредственно из структуры данных, определяющих текст на дисплее: текст можно редактировать до тех пор, пока его конечная новая строка делает подготовленную строку текста считываемой для клиента. Даже в то время, когда строка считывается, текст, который увидит клиент, может быть изменен. Например, после набора в оболочке, пользователь может вернуться назад на конечную новую строку в любое время, пока не кончится работа make и не появится следующее приглашение оболочки перед rm. Пользователь может прервать выполнение команды rm или даже указать мышью до rm и набрать другую команду, чтобы она исполнялась первой.

В Plan 9 отсутствует команда ftp. Вместо нее файловый сервер на уровне пользователя генерирует вызовы ftpfs к узлу FTP, входит в него от имени пользователя и использует протокол FTP для исследования файлов в удаленном каталоге. Для локального пользователя он предлагает иерархию файлов, присоединенных к /n/ftp в локальном пространстве

Page 8:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

имен, отражая содержание узла FTP. Такая реализация рискованна: для эффективности ftpfs придется делать некоторый усложненный захват с использованием эвристического подхода для декодирования информации удаленного каталога. Однако результат стоит того: все локальные средства управления файлами, такие как ср, grep, diff и, конечно, ls, доступны для обслуживаемых FTP-файлов точно так же, как если бы они были локальными файлами. Другие системы, например Jade and Prospero, используют ту же возможность[6; 11].

Один сервер, exportfs, является процессом пользователя, занимающим часть его собственного пространства имен и делающим его доступным для других процессов путем трансляции запросов 9Р в системные вызовы ядра Plan 9. Иерархия файлов, которую он экспортирует, может содержать файлы из множества серверов. Exportfs обычно исполняется как удаленный сервер, инициируемый локальной программой, или import, или cpu. Import производит сетевой вызов удаленной машины, затем стартует exportfs и подсоединяется к локальному пространству имен. Например, команда

import helix /net

делает интерфейс сети Helix видимым в локальной директории /proc, позволяя локальным отладчикам исследовать удаленные процессы.

Команда cpu подключает локальный терминал к удаленному серверу CPU. Она работает в направлении, обратном команде import после вызова сервера, она запускает локальную exportfs и встраивает ее в пространство имен процесса на сервере, обычно через вновь создаваемую оболочку. Затем она перекомпонует пространство имен, чтобы сделать локальные файлы устройства (как те, которые обслуживаются оконной системой терминала) видимыми в каталоге сервера /dev. Эффект действия команды cpu сводится, следовательно, к запуску оболочки на быстрой машине с пространством имен, аналогичном локальному, при наличии еще одной, тесно связанной с файловым сервером. Все локальные файлы устройств видимы с удаленной машины, так что удаленные приложения имеют полный доступ к локальным службам, таким как растровая графика, /dev/cons и т. д. Это не то же, что rlogin, которая не делает ничего для воспроизводства локального пространства имен на удаленной системе, и не то же, что совместное использование файлов при работе, например, с NFS, при котором можно достичь некоторой эквивалентности пространства имен, но не такой же комбинации доступа к локальным аппаратным устройствам, удаленным файлам и удаленным ресурсам вычислительного сервера. Команда cpu является уникальным прозрачным механизмом. Например, разумно запустить систему окон в окне с работающей командой cpu; все окна, созданные в нем, автоматически запускают процесс на вычислительном сервере.

Конфигурируемость и управление

Однородные взаимные связи компонентов в Plan 9 делают возможным конфигурирование инсталляции Plan 9 многими различными способами. Один ПК-лэптоп может функционировать как отдельная система Plan 9, использующая локальный диск для хранения файлов; в другом предельном случае наша система имеет центральные многопроцессорные вычислительные серверы, файловые серверы и множество терминалов в диапазоне от небольших ПК до графических станций высокого уровня. Именно на таких больших системах наилучшим образом проявляется работа Plan 9.

Системное ПО переносимо, и та же самая операционная система может выполняться на любой аппаратуре. Кроме производительности, проявления системы на, скажем, рабочей станции SGI, будут такими же, как и на ноутбуке. Поскольку вычислительные и файловые серверы централизованы, а терминалы не имеют постоянного места хранения файлов, все терминалы функционально идентичны. Таким образом, Plan 9 обладает одним из хороших качеств старых систем с разделением времени, когда пользователь может сидеть перед любой

Page 9:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Центральные файловые серверы централизуют не только файлы, но и их администрирование и обслуживание. В действительности один сервер является главным, содержащим все системные файлы; другие серверы обеспечивают дополнительное место для хранения или доступны для отлаживания и другого специального использования, однако системное ПО размещено на одной машине. Это означает, что каждая программа имеет единственную копию двоичного кода для каждой архитектуры, так что инсталляция новых версий и поиск ошибок достаточно тривиальны. Имеется также единственная база данных пользователя; нет необходимости синхронизировать отдельные файлы /etc/passwd. С другой стороны, зависимость от единого центрального сервера не ограничивает размер инсталляции и непрерывность сервиса. Хотя центральный сервер обычно остается включенным в течение месяцев, когда он выключен, зависящие от него машины не могут функционировать.

Другим примером мощи централизованной файловой службы является то, как Plan 9 управляет сетевой информацией. На центральном сервере существует директория /lib/ndb, которая содержит всю информацию, необходимую для управления локальной сетью Ethernet и другими сетями. Все машины используют для обращения к сети одну и ту же базу данных; нет необходимости управлять распределенной системой наименований или сохранять параллельные файлы до последнего момента. Чтобы инсталлировать новую машину в локальную сеть Ethernet, надо выбрать имя и IP-адрес и добавить их к единственному файлу в /lib/ndb; все машины в инсталляции смогут обратиться к ней сразу же. Чтобы начать работу, подсоедините машину к сети, включите ее и используйте ВООТР и TFTP для загрузки ядра. Все остальное произойдет автоматически.

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

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

Программирование на С

Утилиты Plan 9 написаны на нескольких языках. Некоторые из них представляют собой сценарии оболочки rc [2], многие написаны на новом языке-конкуренте, подобном С, названном Alef и описанном ниже. Большая же часть написана на диалекте ANSI С. Из них большинство являются полностью новыми программами, однако происхождение некоторых идет от Unix-кода, предшественника ANSI С. Эти части были обновлены до ANSI С и переработаны для большей мобильности и чистоты.

Page 10:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Диалект Plan 9 имеет некоторые небольшие добавления, описанные ранее [10], и несколько основных ограничений. Наиболее важные из них — это требование компилятора, чтобы все определения функций имели прототипы ANSI и все вызовы функций появлялись в контексте прототипной декларации функций. Как стилистическое правило, прототипная декларация помещена в файл заголовка, включенный во все файлы, которые вызывают функцию. Каждая системная библиотека имеет ассоциированный файл заголовка, декларирующий все функции в этой библиотеке. Например, стандартная библиотека Plan 9 называется libc, так что все файлы-источники включают <libc.h>. (Имена файлов заголовка не соответствуют ANSI С.) Эти правила гарантируют, что все функции вызываются с аргументами, имеющими ожидаемые типы, что не было свойственно программам на языке, предшествующем ANSI С.

Другое ограничение заключается в том, что для компиляторов С приемлем только поднабор препроцессорных директив, требуемых ANSI. Основное опущенное звено — #if, поскольку мы считаем, что оно никогда не было необходимым и часто использовалось неправильно. Кроме того, его эффект лучше достигался другими средствами. Например, #if, используемый для переключения характеристик во время компиляции, может быть переписан как обычный оператор if, основанный на свертке с константой времени компилирования и исключении мертвого кода для отбрасывания объектного кода.

Условная компиляция, даже с #ifdef, в Plan 9 используется как резервная. Единственные зависимые от архитектуры операторы #ifdef в системе находятся в процедурах низкого уровня в графической библиотеке. Мы избегали таких зависимостей или, когда это было необходимо, выделяли их в отдельные файлы-источники или библиотеки. Кроме того, что применение #ifdef делает код трудночитаемым, становится невозможным узнать, какой источник скомпилирован в двоичный вид или будет ли источник, защищенный ими, компилироваться или работать правильно. Они также затрудняют поддержку ПО.

Стандартная библиотека Plan 9 перекрывается во многом с ANSI С и POSIX, но расходится с ними при адаптации к целям или реализации Plan 9. Когда изменялась семантика функции, мы изменяли также и имя. Например, вместо оператора Unix create, Plan 9 имеет функцию create, которая воспринимает три аргумента — два исходных, плюс третий, который, подобно второму аргументу open, определяет, должен ли возвращенный дескриптор файла быть открыт для чтения, записи или того и другого. Такой подход был вынужденным из-за способа, которым 9Р выполняет создание, однако он упрощает также общее использование create для инициализации временного файла.

Другое отступление от ANSI С заключалось в том, что Plan 9 использует 16-разрядный набор символов, называемый Unicode. Хотя мы совершенно прекратили полную интернационализацию, Plan 9 обрабатывает представление всех основных языков однородно по всему своему ПО. Для упрощения обмена текстами между программами, символы скомпонованы в поток битов путем сконструированной нами процедуры кодировки, названной UTF-8, которая в настоящее время начинает приниматься в качестве стандартной. Она имеет несколько привлекательных свойств, включая независимость от порядка байт, обратную совместимость с ASCII и легкость внедрения.

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

Небольшой класс программ Plan 9 не следует соглашениям, обозначенным в этом разделе. Это программы, импортированные из сообщества Unix или им поддерживаемые;

Page 11:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

представительным их примером является TeX. Чтобы избежать многократного конвертирования таких программ всякий раз, когда выпускается новая версия, мы создали переносимую среду, названную ANSI C/POSIX Environment (АРЕ) [13]. АРЕ включает отдельные файлы, библиотеки и команды, соответствующие насколько можно более точно спецификациям ANSI С и базового POSIX. Для возможности переносимости сетевого ПО, такого как Х Window, к этим спецификациям было необходимо добавить некоторые дополнения, такие как сетевые функции BSD.

Переносимость и компиляция

Plan 9 переносима на множество процессорных архитектур. В рамках одного сеанса расчетов, общим правилом является использование нескольких архитектур. Возможна оконная система, работающая на процессорах Intel, соединенных с вычислительным сервером на основе MIPS с файлами, размещенными на системе SPARC. Для прозрачности такой разнородной системы должны существовать соглашения относительно обмена данными между программами; чтобы поддержка ПО была прямой, должны быть соглашения о кросс-платформной компиляции.

Чтобы избежать проблем с порядком байт, данные передаются между программами как тексты всякий раз, когда это оправдано. Иногда, однако, объем данных достаточно велик для того, чтобы был необходим двоичный формат, такие данные передаются как поток байт с заранее определенным кодированием многобайтовых значений. В редких случаях, когда формат достаточно сложен, чтобы определяться структурой данных, эта структура никогда не передается как единый блок; вместо этого она раскладывается на индивидуальные поля, закодированные как упорядоченный поток данных, и затем переупорядочивается реципиентом. Эти соглашения влияют на данные в диапазоне от информации о состоянии ядра или прикладной программы до промежуточных объектных файлов, сгенерированных компилятором.

Программы, включая ядро, часто представляют свои данные через интерфейс файловой системы — механизм доступа, который изначально переносим. Например, библиотечная функция time (системный вызов time отсутствует) читает файл и конвертирует его в двоичный. Подобным же образом, вместо кодирования состояния прикладного процесса в серии флагов и битов в персональной памяти, ядро представляет текстовую последовательность в файле, называемом status в файловой системе /proc, ассоциированной с каждым процессом. Команда Plan 9 ps тривиальна: она распечатывает содержимое файлов статуса после некоторого небольшого переформатирования; более того, после команды

import helix /proc

локальная команда ps выдает отчет о состоянии процессов Helix.

Каждая поддерживаемая архитектура имеет свой собственный компилятор и загрузчик. Компиляторы С и Alef производят промежуточные файлы, которые для переносимости закодированы; их содержимое уникально для конечной архитектуры, однако формат файла независим от типа компилирующего процесса. Когда компилятор для данной архитектуры откомпилирован на процессоре другого типа и затем использован для компиляции программы там же, то промежуточный файл, созданный на новой архитектуре, будет идентичен таковому, созданному на другом процессоре. С точки зрения компилятора, каждая компиляция является кросс-компиляцией.

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

Page 12:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

возможно выполнение компилятора MIPS на процессоре 486, а затем использование загрузчика MIPS на SPARC-станции для получения исполняемого на MIPS файла.

Поскольку Plan 9 работает на множестве архитектур, даже одиночная инсталляция, различающая имена компиляторов и промежуточных файлов, упрощает многоархитектурную разработку из единого дерева-источника. Компиляторы и загрузчики для каждой архитектуры имеют уникальные имена; команда сс отсутствует. Имена получаются путем конкатенации символа кода, ассоциированного с конечной архитектурой, с именем компилятора или загрузчика. Например, символ кода для процессоров Intel x86 — «8», соответствующий компилятор С назван 8с, компилятор Alef — 8al, а загрузчик — 8l. Подобным же образом, промежуточные файлы имеют суффиксы .8, а не .о.

Программа Plan 9 mk, родственная make, читает имена текущей и конечной архитектур из переменных окружения, названных 8cputype и $objtype. По умолчанию, текущий процессор является целевым, однако подстановка $objtype в имя другой архитектуры перед вызовом mk приводит к кросс-созданию:

objtype=sparc mk

создает программу для архитектуры SPARC независимо от исполняющей машины. Значение $objtype выбирает файл зависящих от архитектуры определений переменных, который конфигурирует создание для использования соответствующих компиляторов и загрузчика. Эта методика, хотя и простая по идее, хорошо работает и на практике: все приложения в Plan 9 созданы из единого дерева-источника и возможно создание различных параллельных архитектур без конфликтов.

Параллельное программирование

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

В новых ОС имеется тенденция вводить два класса процессов: обычные, как в Unix, процессы и легковесные нити. Вместо этого в Plan 9 предложен единый класс процессов, допускающий тонкий контроль за разделением ресурсов, таких как память и дескрипторы файлов.

Основные требования параллельных программ таковы: управление разделяемыми ресурсами; наличие интерфейса к планировщику; детализированная синхронизация с использованием взаимоблокировок. У команды rfork предусмотрен аргумент, битовый вектор, устанавливающий, какие из ресурсов родительского процесса должны быть использованы совместно, скопированы или созданы заново в дочернем процессе. К числу этих ресурсов относятся: пространство имен, окружение, таблица дескрипторов файлов, память и пометки (аналог механизма сигналов Unix). Один из бит определяет, действительно ли rfork создаст новый процесс: если бит выключен, дальнейшая модификация ресурсов будет выполняться в том же процессе, который выполнил вызов. Alef поддерживает ветвление, в котором все ресурсы, включая память, совместно используются родительским и порожденным процессами, по аналогии с порождением нитей во многих системах.

Доказательством правильности модели rfork является множество способов, какими она используется. В отличие от канонического использования fork, трудно найти два обращения к rfork с одинаковым набором бит. Система с двумя типами процессов — обычными и нитями — не была бы столь гибкой.

Есть два способа разделения памяти. Во-первых, специальный флаг rfork делает доступной

Page 13:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Системный вызов rendezvous обеспечивает синхронизацию процессов. Alef использует его для организации коммуникационных каналов, блокировок создания очередей, множественных блокировок «чтение/запись» и механизма перевода в состояние ожидания и активизации. У rendezvous два аргумента, тэг и значение. Вызов rendezvous с некоторым тэгом переводит процесс в состояние ожидания, до тех пор пока другой процесс не представит соответствующий тэг. Когда между тэгами в паре имеется соответствие, происходит обмен их значениями между двумя процессами и оба вызова возвращают управление. Эта примитивная схема достаточна для построения полного набора средств синхронизации.

Взаимоблокировки обеспечиваются архитектурно-зависимой библиотекой, доступной пользователю. Большинство процессоров снабжены набором инструкций, которые могут использоваться для введения блокировок на «атомарном уровне». Исключением является MIPS R3000: процессоры семейства SGI Power Series имеют специальную аппаратную блокировку на шине.

Независимо от «веса», процесс Plan 9 будет блокироваться. Это означает, что, когда программа хочет считать из медленного устройства без блокировки всех вычислений, она должна разветвить процесс, чтобы сделать для него чтение. Решение заключается в том, чтобы начать сопутствующий процесс, который произведет ввод/вывод и выдаст результат в основной процесс путем совместно используемой памяти или, возможно, конвейера. Это звучит тяжеловато, но на практике работает легко и эффективно; в действительности, большинство интерактивных приложений Plan 9, даже относительно обычных, написанных на С, таких как текстовый редактор sam, исполняются как многопроцессные программы.

Поддержка ядром параллельного программирования в Plan 9 заключена в нескольких сотнях строк переносимого кода; куча простых примитивов позволяет отслеживать проблемы на уровне пользователя. Хотя эти C-примитивы и работают хорошо, создание и управление подчиненными процессами куда проще запрограммировать на Alef. Высокоуровневая поддержка параллельного программирования на языке уровня пользователя, а не в ядре способствует согласованности интерфейсов между всеми компонентами. Сравните такой подход с системным вызовом select в Unix: select применим только к ограниченному набору устройств, не может быть обобщен на сетевые задачи, труден в использовании.

Параллельное программирование в Plan 9 важно еще и потому, что многопотоковые файловые серверы уровня пользователя являются предпочтительным средством организации служб.

Реализация пространств имен

Пространство имен организуется при помощи трех вызовов: mount, bind и unmount. Вызов mount присоединяет дерево, обслуживаемое файловым сервером, к текущему пространству имен, расширяя его; bind копирует часть существующего пространства имен в другую точку в пространстве имен; unmount отменяет действие mount или bind.

При использовании вызовов bind или mount, в одной точке пространства имен может быть организован стек из нескольких каталогов. В терминологии Plan 9 это называется объединенным каталогом, который ведет себя подобно конкатенации составляющих его каталогов. Специальный аргумент bind и mount устанавливает положение нового каталога в объединении, допуская добавление новых элементов в начало или конец объединения, причем каждый его элемент ищется поочередно и берется первый подходящий. Объединенные каталоги являются одним из наиболее широко используемых свойств

Page 14:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

организации пространства имен Plan 9. Например, каталог /bin построен как объединение каталогов /$cputype/bin (двоичные коды), /rc/bin (командные файлы) и, возможно, других, включенных пользователем. Это устраняет необходимость в переменной окружения PATH.

Один из вопросов, связанных с объединением каталогов, — в какой элемент объединения попадает вновь созданный файл. Проанализировав несколько вариантов, мы решили следующее. Каталогу, добавляемому к объединению, можно приписать разрешение на создание файла — как свойство пространства имен. Когда в объединении создается файл с новым именем, он попадает в первый каталог объединения, обладающий таким признаком.

Универсальный протокол 9Р объединяет компоненты Plan 9, образуя распределенную систему. Вместо изобретения уникального протокола для каждой службы, такого как rlogin, FTP, TFTP и X Window, Plan 9 реализует службы как операции над файловыми объектами и затем использует единый, хорошо документированный протокол для обмена информацией между компьютерами.

Будучи внешне похожим на NFS, 9Р, однако, воспринимает файлы как последовательность байт, а не блоков. Кроме того, в отличие от NFS, клиенты выполняют вызовы удаленных процедур для установки указателей на объекты в удаленном файловом сервере. Эти указатели называются файловыми идентификаторами, которые используются для идентификации объекта в удаленной файловой системе.

Протокол 9Р определяет 17 сообщений, обеспечивающих средства для аутентификации пользователей, навигации по иерархии файловой системы, копирования файлов, выполнения ввода/вывода, изменения атрибутов файлов и их создания и удаления. Процедура для получения доступа к иерархии имен, предоставляемой сервером, такова. Связь с файловым сервером устанавливается через конвейер или сетевое соединение. Начальное сообщение session выполняет двустороннюю аутентификацию между клиентом и сервером. Сообщение attach затем подсоединяет файловый идентификатор, предлагаемый системой клиента, к корневому каталогу дерева файлов сервера. Одновременно с этим проверяется идентичность пользователя. Соединение могут разделять несколько пользователей, однако каждый должен выполнять операцию подсоединения, чтобы установить свою идентичность.

Сообщение walk перемещает файловый идентификатор через один уровень иерархии файловой системы. Сообщение clone порождает копию идентификатора, которая указывает на тот же файл как на оригинал. Цель этого шага — переход к файлу в каталоге без потери указателя на сам каталог. Сообщение open блокирует идентификатор некоторого файла, проверяет разрешения на доступ и подготавливает его к вводу/выводу. Сообщения read и write выполняют операции ввода/вывода. Сообщение clunk указывает, что клиент не может больше использовать идентификатор. Сообщение remove приводит к удалению файла и перераспределению ресурсов сервера должен быть распределен заново.

Протокол 9Р имеет две формы: сообщения RPC, посылаемые по конвейеру или сетевому соединению, и процедурный интерфейс внутри ядра. Поскольку драйверы устройств помещены в ядро, они адресуемы непосредственно, и для связи с ними нет необходимости посылать сообщения; вместо этого каждое действие 9Р выполняется путем прямого вызова процедуры. Такое раздвоение дает, по меньшей мере, пару преимуществ. Первое — повышенная скорость адресации локальных устройств. Второе — возможность обойтись одной реализацией RPC: системный механизм вызова удаленной процедуры объединен с мультиплексированием сообщений 9Р в единый компонент.

Для каждого идентификатора файла ядро поддерживает его локальное представление в структуре данных, называемое каналом (channel), так что все операции над файлами, выполняемые ядром, включают канал, соединенный с этим идентификатором. Простейший пример: дескрипторы файлов процесса пользователя, отображаемые в набор каналов.

Page 15:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Таблица в ядре представляет список, имеющийся для каждого устройства, точек входа, соответствующих сообщениям 9Р. Системный вызов (например read) переводится в один или больше вызовов процедур согласно этой таблице, индексированных по типу, сохраняемому в канале: procread, eiaread и т.д. Специальное устройство монтирования ядра (mount device) позволяет перевести вызовы процедур в сообщения, то есть конвертирует локальные вызовы процедур в удаленные. В сущности, этот специальный драйвер становится локальным замещением для файлов, обслуживаемых удаленным файловым сервером. Указатель канала в локальном вызове переводится в ассоциированный файл в переданном сообщении.

Драйвер монтирования — механизм, присущий только RPC. Он демультиплексирует сообщения протокола для клиентов, разделяющих коммуникационный канал с файловым сервером. Для каждого исходящего сообщения RPC этот драйвер назначает буфер, помеченный небольшим уникальным целым числом, называемым тэг (tag). Ответ в RPC помечается тем же самым тэгом.

Каждый файл в Plan 9 однозначно идентифицируется набором целых чисел: типом сервера (сохраняемого в канале и используемого как индекс в таблице вызовов функций), номером сервера или устройства, различающего сервер от других такого же типа (разрешимый локально драйвером), и идентификатором, образованный двумя 32-разрядными числами, называемыми путем (path) и версией (version). Путь является уникальным номером файла, присвоенным драйвером устройства или файловым сервером при создании файла. Номер версии обновляется при модификации файла; он может быть использован для поддержания когерентности кеша между клиентами серверами.

Тип и номер устройства аналогичны большому и малому номерам устройства в Unix; комбинация путь-версия аналогична идентификатору i-number. Устройство и тип связывают канал с драйвером устройства, а путь-версия идентифицирует файл в пределах этого устройства.

Cообщения протокола 9Р Сообщение

9Р Описание

Nop Нет операции; используется для отладки.

Session Установить соединение.

Attach Проверить пользователя и присоединить идентификатор к корневому каталогу.

Clone Дублировать идентификатор файла.

Walk Продвинуть идентификатор на один уровень в иерархии каталогов.

Open Проверить разрешения на доступ и разрешить чтение и запись.

Create Создать новый файл (или каталог).

Read Считать содержимое файла, ассоциированного с идентификатором.

Write Записать содержимое файла, ассоциированного с идентификатором.

Clunk Освободить идентификатор.

Remote Удалить файл, ассоциированный с идентификатором.

Stat Считать свойства файла, ассоциированного с идентификатором.

Wstat Модифицировать свойства файла, ассоциированного с идентификатором.

Flush Сбросить выведенное сообщение 9Р.

Error (Только ответ) Возвратить сообщение об ошибке из неудачного вызова.

Page 16:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Clwalk Используется только специальными серверами по низкоскоростным линиям.

Кеширование файлов

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

Поле версий при модификации файла изменяется слабо, что делает возможным осуществление некоторых слабо когерентных форм кеширования. Наиболее важной из них является кеширование сегментов текста и данных исполняемых файлов на клиенте. Когда процесс выполняет вызов exec, файл открывается заново и поле версии сравнивается с версией в кеше; если они соответствуют друг другу, используется локальная копия. Такой же метод может быть использован для организации локального кеширующего файлового сервера. Этот сервер уровня пользователя является посредником в соединениях 9Р с удаленным сервером и отслеживает трафик, копируя данные на локальный диск. Когда он встречает команду чтения известных данных, он отвечает непосредственно, тогда как записи проходят немедленно (кеш со сквозной записью), чтобы центральная копия всегда была обновленной. Эта процедура прозрачна для процессов на терминале и не требует изменений для 9Р; он работает хорошо и на домашних машинах, соединенных последовательными линиями. Подобный метод может быть также использован и для организации общего клиентского кеша в неиспользуемой локальной памяти, однако в Plan 9 этого сделано не было.

Сети и коммуникационные устройства

Сетевые интерфейсы являются файловыми системами, резидентно размещенными в ядре. Установка и отмена вызова достигаются посредством записи текстовых последовательностей в управляющий файл, ассоциированный с устройством; информация посылается и принимается путем чтения и записи файла данных. Структура и семантика устройств едина для сетей всех типов.

Следующий пример илюстрирует структуру TCP устройства:

% ls -lp /net/tcpd-r-xr-xr-x I 0 bootes bootes 0 Feb 23 20:20 0d-r-xr-xr-x I 0 bootes bootes 0 Feb 23 20:20 1--rw-rw-rw- I 0 bootes bootes 0 Feb 23 20:20 clone% ls -lp /net/tcp/0--rw-rw---- I 0 rob bootes 0 % ls -lp /net/tcpd-r-xr-xr-x I 0 bootes bootes 0 Feb 23 20:20 0d-r-xr-xr-x I 0 bootes bootes 0 Feb 23 20:20 1--rw-rw-rw- I 0 bootes bootes 0 Feb 23 20:20 clone% ls -lp /net/tcp/0--rw-rw---- I 0 rob bootes 0 Feb 23 20:20 ctl--rw-rw---- I 0 rob bootes 0 Feb 23 20:20 data--rw-rw---- I 0 rob bootes 0 Feb 23 20:20 listen--r--r--r-- I 0 bootes bootes 0 Feb 23 20:20 local--r--r--r-- I 0 bootes bootes 0 Feb 23 20:20 remote--r--r--r-- I 0 bootes bootes 0 Feb 23 20:20 status%

Верхний каталог /net/tcp содержит файл clone и ряд последовательно пронумерованных подкаталогов. Каждый подкаталог соответствует IP-соединению. Открытие clone

Page 17:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

резервирует неиспользованное соединение и открывает его управляющий файл. Чтение управляющего файла возвращает номер соединения в текстовой форме, так что процесс пользователя может построить полное имя вновь назначенного каталога соединения. Файлы local, remote и status являются диагностическими: например, remote содержит адрес (для ТСР/IP — адрес и номер порта) удаленного узла.

Вызов инициируется записью сообщения о соединении с конкретным сетевым адресом в качестве его аргумента; например, чтобы открыть сеанс Telnet (порт 23) с удаленной машиной с IP-адресом 135.104.9.52, последовательность должна быть такой:

connect 135.104.9.52!23

Запись в управляющий файл блокируется до тех пор, пока поддерживается соединение; если адресат недостижим, команда записи возвращает ошибку. Как только соединение установлено, приложение telnet считывает и записывает файл data, чтобы общаться с удаленным демоном Telnet. С другой стороны, демон Telnet стартует путем записи

announce 23

в свой управляющий файл, чтобы указать свою готовность к получению вызовов на этот порт. В Plan 9 такой демон называется слушатель (listener).

Однородная структура для сетевых устройств не может скрыть все детали адресации и коммуникации для различающихся сетей. Например, Datakit использует текстуальные иерархические адреса, отличающиеся от 32-разрядных адресов IP, так что определенный приложением управляющий файл должен все же знать, какую сеть он представляет. Вместо того, чтобы каждое приложение знало адресацию каждой сети, Plan 9 скрывает эти детали в сервере соединений (connection server), называемом cs. Cs — это файловая система, смонтированная в известном месте. Этот механизм позволяет приложению установить соединение с хостом. Приложение передает символьный адрес и имя службы, например net!kremvax!telnet, и получает в ответ имя открываемого файла и представляемый ему адрес, например /net/tcp/clone 111.123.112.94!23. Если машины связаны несколькими сетями, cs представляет список возможных сетей и адресов, которые будут последовательно перебираться; порядок определяется эвристически. Например, первым представляется вариант с наибольшей пропускной способностью.

Для установления соединения с cs используется единая библиотечная функция, названная dial. Приложение, применяющее dial, не требует никаких изменений, даже перекомпиляции, для адаптации к новым сетям; все детали при этом скрыты интерфейсом к cs.

Благодаря однородной структуре сетей в Plan 9 для организации сетей достаточно команды import.

Поддержка сетей на уровне ядра

В ядре для построения коммуникационных каналов Plan 9 предусмотрен специальный механизм, называемый потоками (streams). Поток — это двунаправленный канал, соединяющий физическое или псевдоустройство с процессом пользователя. Процесс пользователя вводит и удаляет данные на одном конце потока; процесс ядра, действующий от имени устройства, выполняется на другом конце. Поток включает линейный список обрабатывающих модулей (processing modules). Каждый модуль обладает процедурой продвижения данных как вверх (к процессу), так и вниз (к устройству). Вызов этой процедуры модуля на любом конце потока вводит в него данные. Каждый модуль вызывает последующий для посылки данных вверх или вниз по потоку. Подобно потокам Unix, потоки Plan 9 могут быть сконфигурированы динамически.

Page 18:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Протокол IL

Протокол 9Р должен выполняться поверх надежного транспортного протокола. 9Р не имеет механизма для восстановления после ошибок передачи, и система предполагает, что каждое считывание из коммуникационного канала возвратит единственное сообщение 9Р; она не анализирует поток данных для определения границ сообщений. Конвейеры и некоторые сетевые протоколы уже имеют эти возможности, но стандартный протокол 9Р — нет. TCP не разделяет сообщения, тогда как UDP не обеспечивает надежной упорядоченной доставки.

Мы разработали новый протокол, названный IL (Internet Link), для передачи сообщений 9Р поверх IP. Это основанный на предварительном соединении протокол, обеспечивающий надежную передачу упорядоченных сообщений между машинами. Так как процесс может иметь только один ожидающий выполнения запрос 9Р, в IL нет необходимости в управлении потоком. Подобно ТСР, в IL предусмотрены адаптивные задержки: он изменяет времена квитирования и ретрансляции, согласуя их с пропускной способностью сети. Это позволяет протоколу хорошо работать в сетях как Internet, так и в локальных Ethernet. Кроме того, IL не затемняет повторную передачу, чтобы не вызвать дополнительной перегрузки сети.

В Plan 9 использование IL меньше и быстрее, чем ТСР. IL является нашим основным транспортным протоколом Internet.

Аутентификация

Аутентификация устанавливает идентичность пользователя, запрашивающего доступ к ресурсам.

С каждым пользователем Plan 9 ассоциирован ключ аутентификации DES; идентичность пользователя подтверждается его способностью кодировать и декодировать специальные сообщения, называемые вызовами. Так как знание ключа пользователя дает доступ к ресурсам этого пользователя, протоколы аутентификации Plan 9 никогда не передают сообщения, содержащие чисто текстовый ключ.

Процесс аутентификации двусторонний: в конце аутентификационного обмена каждая сторона приобретает убежденность в идентичности другой. Каждая машина начинает обмен, имея в памяти ключ DES. В случае вычислительных и файловых серверов ключ, имя пользователя и имя домена для сервера считываются из постоянной памяти. В случае терминалов ключ порождается из пароля, набираемого пользователем во время загрузки. Специальный компьютер, известный как сервер аутентификации (authentication server), поддерживает базу данных ключей для всех пользователей в своем административном домене и участвует в процедуре аутентификации.

Процедура аутентификации в чем-то подобна системе Kerberos, но в отличие от нее не завязана на синхронизацию часов. Кроме того, в отличие от Kerberos, аутентификация Plan 9 поддерживает связь типа «говорить за», которая позволяет одному пользователю получать полномочия другого; именно таким образом вычислительный сервер выполняет процессы от имени своих клиентов.

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

Аутентификация внешних соединений

Обычный протокол аутентификации Plan 9 не подходит для текстовых служб, таких как Telnet или FTP. В этих случаях пользователи Plan 9 проходят аутентификацию с помощью DES-калькулятора (используется продукт SecureNet Key компании Digital Pathways).

Page 19:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Аутентификатор содержит ключ, отличный от обычного ключа пользователя. Пользователь идентифицируется аутентификатором по четырехзначному значению PIN (индивидуального идентификационного номера). Правильный PIN позволяет аутентификатору обмениваться вызовом/ответом с сервером. Поскольку правильный обмен действителен только один раз и ключи никогда не посылаются по сети, эта процедура не чувствительна к отражению попыток нарушения защиты, однако совместима с протоколами типа Telnet и FTP.

Специальные пользователи

В Plan 9 нет суперпользователей. Каждый сервер ответственен за поддержание своей собственной безопасности, обычно позволяя доступ только с консоли, которая защищена паролем. Например, в файловых серверах предусмотрен пользователь с именем adm, со специальными привилегиями, которые применимы только к командам, набираемым с собственной консоли сервера. Эти привилегии относятся к таким служебным операциям, как добавление новых пользователей и конфигурирование дисков и сетей. Привилегии не включают возможность модифицировать, исследовать или изменять разрешения каких-либо файлов. Если файл защищен пользователем от чтения, только этот пользователь может разрешить доступ к нему.

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

Наконец, специальный пользователь с именем none не имеет пароля и ему всегда разрешено соединение; именем none может назваться каждый. Такой пользователь имеет ограниченные права; например, ему не разрешено изучать дампы; он может читать только общедоступные файлы.

Эта идея аналогична анонимному пользователю в службах FTP. В Plan 9 серверы-гости FTP в дальнейшем сохраняются в специальном ограниченном пространстве имен. Она разъединяет пользователей-гостей и системные программы, такие как содержимое каталога /bin, однако позволяет сделать локальные файлы доступными для гостей, связывая их явно в пространстве. Ограниченное пространство имен более безопасно, чем обычная методика экспорта специального дерева каталогов; результатом является нечто вроде клетки вокруг пользователей, не внушающих доверия. Тем не менее бдительность по-прежнему необходима; Plan 9 облегчает построение безопасной системы, но не гарантирует этого.

Аутентификация с посредником

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

Page 20:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

имени Peter. Сервер аутентификации выдаст билеты только в том случае, если административный пользователь вычислительного сервера имеет разрешение говорить за пользователя с именем Peter.

Права доступа к файлам

Одно из преимуществ построения служб как файловых серверов заключается в том, что проблемы владения и прав разрешаются естественным образом. Как и в Unix, с каждым файлом или каталогом связаны отдельные разрешения на чтение, запись и выполнение/поиск для владельца файла, группы и других пользователей. Трактовка группы необычна и состоит в том, что имя одного из пользователей может быть выделено как лидера группы (group leader). Если группа имеет лидера, то этот пользователь обладает специальными правами, такими как возможность изменения групповых прав файлов этой группы. Если лидер не установлен, члены группы считаются равными, как если бы каждый был лидером.

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

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

Другим необычным применением прав на файл является файловая система дампов, которая не только обслуживается тем же самым файловым сервером, что и исходные данные, но и представлена той же самой базой данных пользователя. Файлам в дампе, следовательно, дана защита, идентичная файлам в обычной файловой системе; если пользователь владеет файлом и тот защищен от чтения, та же самая картина сохранится и в файловой системе дампов. Кроме того, поскольку файловую систему дампов нельзя заменить, файл не может быть изменен; он навсегда останется защищенным от чтения.

Обсуждение

Plan 9 имеет относительно традиционное ядро; новизна системы заключается в компонентах вне ядра и в том, как они взаимодействуют. Наилучшим примером этого является протокол 9Р, который централизует наименование, доступ и аутентификацию. 9Р действительно является сердцем системы: можно сказать, что ядром Plan 9 является в первую очередь мультиплексор 9Р.

В Plan 9 основное внимание уделено файлам; предложенный механизм именования является основным фактором ее выразительности. В частности, при распределенных вычислениях принятый для наименования способ оказывает глубокое влияние на систему. Комбинация локального пространства имен и глобальных соглашений о взаимосвязи сетевых ресурсов позволяет избежать трудностей поддержания глобального однородного пространства имен, тогда как наименование всего как файлов делает понимание системы легкой даже для новичков. Рассмотрим файловую систему дампов, которая тривиальна в использовании для каждого, кто знаком с иерархической файловой системой. На более глубоком уровне, построение всех ресурсов над единым однородным интерфейсом делает интероперабельность легкой. Как только ресурс экспортирует интерфейс 9Р, он может прозрачным образом сочетаться с любой другой частью системы для построения необычных приложений; детали при этом остаются скрытыми. Это может звучать подобно объектно-ориентированному подходу, но на самом деле кое в чем от него отличается. Во-первых, 9Р

Page 21:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

определяет фиксированный набор «методов»; он не является расширяемым протоколом. Более важно то, что файлы хорошо определены и понятны и поступают предварительно скомпонованными со знакомыми методами доступа, защиты, наименования и обращения в сети. Объекты, несмотря на их общность, не поступают с этими определенными атрибутами. Редуцируя «объект» в «файл», Plan 9 без дополнительных усилий получает определенную технологию.

Тем не менее есть опасность развить идею вычислений, основанных на файлах, слишком далеко. Преобразование каждого ресурса в системе в файловую систему является в каком-то смысле метафорой, а метафоры могут приводить к конфузам. Хорошим примером ограничений является /proc, который только внешне выглядит как процесс, но не представляет его. Для исполнения процессов необходимы все еще обычные вызовы fork и exec, а не чего-то, подобное

cp /bin/date /proc/clone/mem

Проблема с такими примерами в том, что для них нужно, чтобы сервер работал не под их управлением. Способность придавать значение командам, подобным указанным, не подразумевает, что это значение естественно выпадет из структуры ответов на запросы 9Р, которые она генерирует. Так, например, Plan 9 не помещает сетевые имена компьютеров в пространство имен файлов. Сетевые интерфейсы обеспечивают совершенно другую модель наименования, поскольку использование команд open, read и write над такими файлами не предоставляет подходящего места для кодирования всех деталей установки вызова для произвольной сети. Это не значит, что сетевой интерфейс не может быть файловоподобным, просто он должен иметь более четко определенную структуру.

Plan 9 имеет только один «официальный» механизм RPC, интегрированный с 9Р. По сравнению с системами с более общим RPC, такой подход имеет недостатки: полный вызов RPC должен быть реализован как write, за которым следует read, то есть требует вдвое больше команд; и некоторые специфичные формы RPC могут быть громоздкими. Например, реализация /dev/bitblt, которая имеет специальный RPC-подобный уровень, встроенный над 9Р, не может совместно использовать ни один из кодов для выстраивания сообщений 9Р и требует наличия сервера для сохранения состояния после некоторых вызовов write для возврата информации последующему вызову клиента read. С другой стороны, устройству Plan 9 присущи простота и общность, и (с некоторыми предосторожностями) ему не требуются компиляторы заглушек или какая-либо поддержка на языковом уровне. Громоздкость, подобная /dev/bitblt, на практике встречается редко и никогда не является ограничением. Более того, /dev/bitblt сама является примером, когда избыточность несущественна, т.к. основная масса вызовов устройств включает write без последующей read. Наконец, возможно наиболее важной является легкость написания сервера 9Р. Код, реализующий протокол, занимает всего 500 строк и обычно адаптируется из существующего сервера, а не пишется заново.

Что бы мы сделали по-другому в следующий раз? Некоторые элементы реализации нас не удовлетворили. Использование потоков для введения сетевых интерфейсов в ядре допускает, чтобы протоколы были связаны динамически, например для привязки одного и того же драйвера TTY к соединениям с TCP, URP и IL, но в Plan 9 такая способность к перестройке конфигурации не используется. (Она эксплуатировалась, однако, в том самом варианте ОС Unix, для которого и были изобретены потоки.) Замена потоков статичными запросами ввода/вывода упрощает код и делает его быстрее.

Хотя основное ядро Plan 9 переносимо на многие машины, файловый сервер реализуется отдельно. Это вызвано несколькими причинами: драйверами, которые должны быть написаны дважды, ошибками, которые тоже должны быть выявлены дважды, и худшей переносимостью кода файловой системы. Решение просто: для реализации файловой службы

Page 22:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Хотя Plan 9 поддерживает отдельное пространство имен для каждого процесса, она не имеет никакого механизма для передачи описания пространства имен процесса другому процессу, кроме прямого наследования.

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

Одна из причин успеха Plan 9 заключается в том, что она использовалась в каждодневной работе, а не только в качестве инструмента исследований. Активное использование вынуждало разрешать проблемы по мере их возникновения и адаптировать систему к решению наших задач. Благодаря этому процессу, Plan 9 стала удобной, продуктивной программной средой, а также средством для дальнейших системных исследований.

Литература

[1] American National Standards for Information Systems - Programming Language С, American National Standards lnstitute, lnc., New York, 1990.[2] АТ&T Bell Laboratories, UNIX Time-Sharing System Programmer's Manual, Research Version, English Edition, Volume 1, Murray Hill, NX, 1985. [3] TomDuff, Rc - А Shell for Plan 9 and UNIX systems, Proc. of the Summer 1990 UKUUG Ccmf., London,July, 1990, рр.21-33. [4] IEEE, Information Technology - Portable Operating System Interface (POSIX) Part 1: System Application Program Interface (API) [С Language], New York, 1990. [5] T.J. Killian, Processes as Files, USENlX, Summer 1984 Conf. Proc., June 1984, Salt Lake City, UT. [6] В. Clifford Neuman, The Prospero File System, USENIX File Systems Workshop Proc., Ann Arbor, 1992, рр.13-28. [7] John Ousterhout, Andrew Cherenson, Fred Douglis, Mike Nelson, and Brent Welch, The Sprite Network Operating Systems Operating System, IEEE Computer, 21(2), 23-38, Feb. 1988. [8] Rob Pike, 8½, the Plan 9 Window System, USENIX Summer Conf. Proc., Nashville, June, 1991, рр. 257-265. [9] Rob Pike, Dave Presotto, Ken Thompson, Howard Trickey, and Phil Winterbottom, The Use of Name Spaces in Plan 9, Ор. Sys. Rev., Vol. 27, No. 2, April 1993, рр. 72-76. [10] Rob Pike, How to use thePlan 9 C Compiler, Plan 9 Programmer's Manual, Volume 2, АТ&Т Bell Laboratories, Murray Hill, N, 1995. [11] Herman Chung-Hwa Rao, The Jade File System, (Ph D. Dissertation), Dept. of Сомр. Sci, University of Arizona, TR 91-18. [12] Robert W. Scheifler and Jim Gettys, The Х Window System, АСМ Trans. on Graph, 5(2), рр. 79-109, 1986. [13] Howard Trikey, АРЕ - The ANSI/POSIX Environment, Plan 9 Programmer's Manual, Volume 2, АТ&Т Bell Laboratories, Murray Hill, NJ, 1991. [14] Brent Welch, А Comparison of Three Distributed File System Architectures Vnode, Sprite, and Plan 9, Computing Systems, 7(2), рр. 175-199, Spring, 1994.

Copyright © 2001 Lucent Technologies Inc. All rights reserved.Источник: Открытые системы

Page 23:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

READMEБрайан В. Керниган[email protected]

Задача этого документа — помочь вам начать использовать операционную систему Plan 9. Он написан обычным пользователем Plan 9, который ни коим образом не имеет отношения к группе ее разработчиков. Документ нацелен на аудиторию пользователей с Unix прошлым.

Приступаем

Предполагается: (1) что вы или кто-нибудь, кому вы доверяете, прочитал, разобрался и выполнил процедуру установки Plan 9; (2) что вы хотя бы просмотрели обзорный документ Plan 9 от Bell Labs, в котором дается общее описание Plan 9. Также много полезных объяснений и примеров содержит документ Использование пространства имен в Plan 9. Также предполагается, что не далеко от вас находится первый том руководства по Plan 9, так как вам потребуется читать man-страницы команд, когда их названия будут появляться здесь.

Ваши действия после включения терминала зависят от того, как установлена ваша система Plan 9; детали различаются для автономной системы и терминала, соединенного с файловым сервером и CPU сервером. Далее речь идет как раз об этом.

Также как .profile выполняется оболочкой в Unix системах, когда вы начинаете сеанс работы, файл lib/profile выполняется оболочкой в Plan 9. Для создания пользовательского эккаунта используется команда newuser, которая создает домашний каталог $home, а в нем несколько подкаталогов (bin, bin/rc, lib и tmp), затем устанавливает файл профиля lib/profile. Последний выглядит примерно вот так:

bind -a $home/bin/rc /binfont = /lib/font/bit/pelm/euro.9.fontswitch($service){case terminal prompt=('term ' ' ') exec 8½case cpu bind -b /mnt/term/mnt/8½ /dev prompt=('cpu ' ' ')}

Большинство интересных особенностей Plan 9 представлено именно в этом файле.

Оконная система 8½

Оконная система Plan 9 называется 8½; выбор terminal в операторе case профиля запускает 8½ командой

exec 8½

8½ обеспечивает меньшую «гибкость» и несомненно значительно меньшие возможности, чем xterm в X терминалах, но я, все же, предпочитаю использовать именно ее.

Оконная система обрабатывает весь текст на экране одинаково; с помощью мыши вы можете редактировать все что видите, у вас есть возможность редактировать и повторно использовать введенные команды, перенаправлять вывод или ввод программы и вновь использовать их, и т.п. Эта способность редактирования предыдущих команд освобождает от потребности их повторного ввода, и вам никогда не захочется вернуться назад к чему-нибудь вроде xterm.

Page 24:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

8½ может работать рекурсивно: вы создаете новое окно, в нем запускаете 8½, и все что вы там делаете будет изолировано от среды. В системе 8½ нет аналога управлению виртуальными окнами, к примеру, как у VTWM и его огромного множества (или даже нескольких) иконок, но вы можете перемещать окно даже за пределы экрана, скрывать его, а затем вызывать из всплывающего меню, что само по себе является свободным эквивалентом иконизации.

В 8½ есть нечто вроде автозагрузки, т.е. вы даете запрос запускать файл с командами во время загрузки системы; большинство пользователей вставляют свои запросы в профиль:

exec 8½ -i lib/windows

Это свойство может быть полезным при установке часто используемых окон:

#!/bin/rcwindow 'x0 y0 x1 y1' командная строка...

где x0,y0 и x1,y1 — координаты окна. Window создает окно в указанном месте, а затем запускает в нем команду. Для непосредственной вставки команд в файл может использоваться программа wloc, которая выводит имена и размещения всех окон в правильном формате. Нужным образом разместите окна программ, после этого запустите wloc и скопируйте (snarf) ее вывод.

Команды

Большинство стандартных команд Unix существуют в почти той же форме в Plan 9, это команды: cat, ls, cd, pwd, cp, mv, diff, grep и awk. Вы заметите незначительные различия в их поведении, но в большинстве случаев вам не стоит об этом беспокоиться.

Оболочка rc

Одной из главных программ любой операционной системы является оболочка, в Plan 9 используется оболочка под названием rc. Для запуска команд интерактивно она почти эквивалентна оболочкам Bourne или Korn, так что метасимволы вроде * и ? — ведут себя предсказуемо, простые перенаправления >, >> и | — также функционально одинаковы. Более простое использование кавычек: все заключается в одинарные кавычки; двойные кавычки и обратная косая черта не имеют специального назначения. Что увидеть одну кавычку, заключенную в кавычки, удвойте ее:

echo ''''

В программировании, rc имеет мало общего с sh, что досадно. В частности, у них различаются управляющие структуры if и for.

Все сценарии должны начинаться со строки:

#!/bin/rc

Установка переменных окружения:

var = 'значение'

при чем кавычки могут опускаться, если значение не содержит пробелов. Переменные окружения доступны как $var: определенные переменные инициализируются в начале работы, включая user (ваше имя), home (ваш домашний каталог), и service, принимающая значение terminal, если вы работаете на терминале и CPU, если вы работаете на CPU сервере.

Page 25:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Каталоги и пути поиска

Одной из объединяющих идей в Plan 9 считается доступ ко всем ресурсам как к файловым системам. Основой ее является управление пространством имен, так что у вас появляется возможность выборки и размещения ресурсов, необходимых для использования.

Пространство имен управляется командами bind и mount. В частности, команда

bind -a $home/bin/rc /bin

в профиле связывает каталог $home/bin/rc с /bin, формируя союзный каталог. (Точнее, она делает /bin псевдонимом для этого союза.) Кроме текущего каталога, оболочка выполняет поиск программ только в /bin, реально же она проходит по всем каталогам, которые были соединены вместе. По соглашению, ваши собственные сценарии оболочки находятся в $home/bin/rc.

Когда вы начинаете сеанс роботы, несколько каталогов связываются с /bin, включая /rc/bin, содержащий сценарии оболочки, и /$cputype/bin, содержащий двоичные файлы для вашего типа процессора. Переменная cputype содержит информацию о типе процессора, который вы используете, типично это 386, sparc, mips или 68020. Когда вы запускаете программу вроде ls, производится поиск версии для вашего процессора в /bin и ее выполнение. Если вы впоследствии выполните команду cpu для доступа к CPU серверу, в этом процессе и запущенных им, переменная cputype будет содержать тип процессора CPU сервера и команда ls (вновь из /bin), которую вы запустите там, будет правильным двоичным файлом для этого процессора.

Механизм союзных каталогов заменяет путь поиска (переменная PATH) стандартных оболочек Unix. Насколько вы поняли, все исполняемые программы находятся в /bin. Введите

lc /bin

чтобы увидеть список имен всех доступных исполняемых программ.

Интересные файловые системы

Одной из главных идей Plan 9 является представление системных ресурсов и служб в виде файлов в иерархии каталогов. Она идет от Unix и еще лучше разработана в Linux, но Plan 9 заходит дальше всех. Файлами выглядят не только устройства, но и такие объекты, как серверы имен Internet.

Если вы посмотрите в каталог /dev, то увидите знакомые имена. К примеру, попробуйте выполнить

cat /dev/time

несколько раз. Или же, после того как вы скопировали какой-нибудь текст, введите

cat /dev/snarf

Вы заметите, что файлы типа cons и mouse появляются по несколько раз, это происходит из-за того что /dev является союзным каталогом и в нем присутствуют многочисленные совпадения одинаковых файлов. Первый /dev/mouse имеет отношение к текущему окну, следующий — к включаемому окну (вероятно, это весь экран). Введите

cat /dev/mouse

а затем попробуйте передвигать мышь внутри и вне текущего окна.

Page 26:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Окружение оболочки хранится в каталоге под названием /env; каждая переменная окружения хранится в файле. К примеру, введите

cat /dev/font

Запущенные процессы находятся в /proc; каждый процесс представляет собой каталог, а каждый файл такого каталога доступен процессу. Например, файл status содержит текстовую информацию о статусе процесса. Введите

awk '{print $1}' /proc/*/status

чтобы получить список запущенных процессов.

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

И наконец, стоит заглянуть в каталог /sys, который является стандартной файловой системой, он содержит каталоги исходных текстов программ, библиотек и заголовков, man-страницы, документацию и тому подобное. Он приблизительно эквивалентен аналогичным каталогам Unix систем.

Шрифты

Один аспект 8½, который вы можете изменить, — это шрифт отображения текста. В системе существует шрифт по-умолчанию, но обычно переменная font устанавливается явно в профиле:

font = /lib/font/bit/pelm/euro.9.font8½ -f $font

Шрифт euro.9.font — это набор почти всех символов европейских языков, включая кириллицу, греческий язык и группу специальных символов. Существуют также другие шрифты, которые включают восточные языки и даже ряд размеров.

Plan 9 использует символьный набор Unicode, который позволяет системе и ряду программ комфортабельно работать с очень большим символьным набором. (Сравните 16 bit символов и 64 KB.) Так что если вы желаете редактировать файлы с языками, в которых используется больше символов, чем может позволить ASCII, или запускать grep или awk для них, тогда Unicode — это то, что вам нужно. У вас могут возникнуть проблемы при печати таких символов на стандартных принтерах, но на экране они выглядят отменно.

Редактирование

Стандартный текстовый редактор Plan 9 называется sam, его характеристики: хорош при редактировании нескольких файлов; обеспечивает синтаксис регулярных выражений, схожий с таковым в ed (который, к слову, также в наличии); возможность копирования и вставки текста между окнами 8½. Мышиные идиомы sam и 8½ одинаковые. Если есть сетевое соединение, он может редактировать файлы на других системах.

Между прочим, регулярные выражения в Plan 9 были приведены в порядок — все программы кроме rc поддерживают одинаковые регулярные выражения, которые достаточно близки к таковым в egrep Unix систем.

Page 27:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

CPU сервер

В мире Plan 9 интерактивные программы вроде редакторов запускаются на терминале, а вычислительные программы вроде компиляторов — на CPU сервере, который работает быстрее и имеет более высокую полосу пропускания к файловому серверу. Команда cpu соединяет вас с CPU сервером и ваши вычисления выполняются быстрее, при этом все остальное остается без изменений. Удаленный вход в систему (не сохраняющий пространство имен, с которым вы работаете) и доступ к сетевой файловой системе (не изменяющий процессор) достаточно сильно отличаются. Строка

bind -b /mnt/term/mnt/8½ /dev

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

Соединение с Unix системами

Вероятно ваша система Plan 9 будет соединена какой-нибудь сетью с Unix системой (или системами). Команда con соединяет Plan 9 с другой системой (типично это Unix); команда rx предназначена для выполнения одной команды на другой машине (нечто вроде rsh в Unix).

Если вы взаимодействуете с Unix системой, есть возможность подмонтировать ее файловую систему в пространство имен Plan 9, таким образом файлы Unix стороны станут доступными в Plan 9. Команда

9fs машина

устанавливает соединение и монтирует файлы; после ее выполнения корневая файловая система объекта будет находится в каталоге /n/машина.

CPU серверы Plan 9 отвечают на запросы FTP, rlogin и telnet. Если вы желаете установить свои собственные привилегии доступа, тогда вам необходимо отвечать на вызовы, используя ключ SecureNet или эквивалентный ему; в противном случае, пользователь none получит большие привилегии, достаточные для доступа ко многим доступным глобально серверам и базам данных (см. раздел 7 руководства). Подобные ограничения присутствуют и когда вы получаете доступ к файловым серверам Plan 9 через NFS; в этом случае программа 9auth будет вести диалог вызов/ответ.

Если ваша система Plan 9 делит диск с MS-DOS, что возможно для архитектуры PC, то вы можете получить доступ к файловой системе DOS через каталог /n/c:, и другим дискам через /n/a:, и т.п. Это удобный способ получения информации в или из мира PC.

Резервирование и восстановление

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

9fs dump

то она подмонтирует эту файловую систему в каталог /n/dump. Таким образом, вы можете вернуться (командой cd) в прошлое:

cd /n/dump/1995/0401/usr/вы

Page 28:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

ls -l

При этом вы переместитесь в ваш домашний каталог, каким он был 1 апреля 1995 года. Это файловая система настоящая, так что все обычные команды работают нормально; вы можете сравнивать (команда diff) файлы, копировать старые версии в настоящее. В Plan 9 нет программ ни резервирования, ни восстановления, механизм взятия дампов включает и полностью заменяет их.

Программирование в Plan 9

В основном программирование в Plan 9 выполняется по стандарту ANSI C с поддержкой обычных инструментальных средств типа YACC. Программа make была полностью вытеснена mk, и, также как с оболочкой, требуется время, чтобы привыкнуть к ней.

Для каждого поддерживаемого типа процессора существует компилятор C (в названии используется одна буквенная мнемоника), а также версия, которая может выполняться на любом типе процессора. Mkfile нормально скрывает эти данные, каталог /sys/src/cmd содержит примеры, которые вы легко можете адаптировать.

Хотя существует поддержка ANSI C, библиотеки Plan 9 написаны не на нем и стандартные заголовочные файлы ANSI отсутствуют в системе. Компиляция программ в Plan 9 очень отличается от таковой в Unix, так что перед началом этой процедуры обязательно прочитайте документ «Как использовать компилятор Plan 9 C» (How to Use the Plan 9 C Compiler, /sys/doc/comp.ps).

Если вам нужно импортировать или экспортировать программу на языке C, то вам придется использовать среду ANSI/POSIX («APE»), которая и предназначена для этих целей. Она включает полный набор POSIX-совместимых библиотек и некоторые инструментальные средства POSIX. Драйвер компилятора называется pcc. Команда

ape/psh

связывает нужные файлы и запускает POSIX-совместимую оболочку.

Хотя эти средства POSIX и полезны для обмена программ с внешним миром, чтобы быть более продуктивными используйте (по возможности) исконные инструментальные средства Plan 9.

Выводы

Plan 9 это не Unix. Если вы думаете что это Unix, то часто будете удивляться (с отвисшей челюстью и широко открытыми удивленными глазами — прим пер.), потому что какие-то вещи здесь не доступны или работают совсем по-другому. Если же вы будете думать о ней как о новой операционной системе, то поймете, что многое работает очень гладко, и здесь есть поистине хорошие идеи, которые стоит использовать.

Copyright © 1995 Lucent Technologies. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Page 29:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Использование пространства имен в Plan 9Роб ПайкДейв ПресоттоКен ТомпсонГовард ТрикиФил Уинтерботтом Bell Laboratories, Murray Hill, NJ, 07974 USA

АБСТРАКТНО

Plan 9 — это распределенная операционная система, созданная в научно-исследовательском центре вычислительной техники AT&T Bell Laboratories (сейчас Lucent Technologies, Bell Labs) несколько лет тому назад. Цель проекта — представление качественной системы для разработки программного обеспечения и общих вычислений, используя разнородные аппаратные средства и минимум программных. Аппаратной основой Plan 9 являются CPU и файловые серверы, соединенные высокоскоростными сетями. Низкоскоростные сети используются для терминалов, которые представляют собой машины класса рабочих станций. Проект Plan 9 показал, что из нескольких тщательно реализованных абстракций можно построить небольшую операционную систему, обеспечивающую поддержку для больших систем на разнотипных архитектурах и сетях. Программная основа системы построена на двух идеях: пространства имен процессов и простой, ориентированный на сообщения протокол файловой системы.

Операционная система для CPU серверов и терминалов имеет традиционное ядро: скомпилированный образ, содержащий код управления ресурсами и процессами, виртуальной памятью и вводом-выводом. Так как файловый сервер является отдельной машиной, его ядро включает управление пространствами имен и атрибутами процессов, но не включает саму файловую систему. Ядро для многопроцессорной машины SGI Power Series занимает 25 тыс. строк кода на С, наибольшая часть которого — код для четырех типов сетей, включая Ethernet с блоком Internet протокола. Менее 1,5 тыс. строк специфичны для машины, и функциональное ядро с минимумом ввода-вывода могут быть собраны вместе в итоговых 6 тыс. строк. [3]

Система сравнительно небольшая по нескольким причинам. Первая, система полностью новая: не было необходимости и времени для обрастания как многочисленными исправлениями, так и характеристиками других систем. Также, кроме сетевого протокола, система не придерживается внешнего интерфейса, в частности, она не совместима с Unix(!). Темпы развития экономики руководили тщательным выбором всех сервисов и интерфейсов. И наконец, по возможности, Plan 9 строилась на двух принципах: каждый ресурс в системе, будь то локальный или удаленный, представлен в виде иерархической файловой системы; пользователь или процесс создают свой вид системы путем сбора пространств имен файлов, которые соединяют эти ресурсы. [2]

Файловый протокол

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

Page 30:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Интерфейс к файловым системам описан специальным протоколом под названием 9P, аналогичным по функциям с NFS. Протокол 9Р воспринимает файлы как последовательность байт, а не блоков; при соединении с корневым каталогом файлового сервера сообщения 9P управляют иерархией файлов, открывают файлы для ввода-вывода, и читают или записывают произвольные байты в файлы. 9P содержит 17 сообщений: три для инициализации и аутентификации соединения и четырнадцать для управления объектами. Сообщения генерируются ядром в ответ на запросы ввода-вывода пользовательского или ядерного уровней. Опишем в нескольких словах основные типы сообщений. Сообщения auth и attach аутентифицируют соединение и проверяют идентичность пользователя. В результате получается аутентифицированный канал, указывающий на корневой каталог сервера. Сообщение clone выполняет дублирование канала, который затем помещается в файл на сервере с использованием сообщения walk (перемещение по уровням иерархии файловой системы). Сообщения stat и wstat читают и записывают атрибуты в файл, указанный каналом. Сообщение open подготавливает канал для последующих сообщений: read и write — для доступа к содержимому файла, и create и remove — для соответственно создания и удаления файла. Сообщение clunk отвергает канал без влияния на файл. Ни одно из сообщений 9P не производит операций кеширования, при необходимости, файловые кеши предусматриваются или сервером (централизированное кеширование), или путем реализации кеша как прозрачной файловой системы между клиентом и соединением 9P к серверу (клиентское кеширование).

Соединения с локальными ядро резидентными файловыми системами называются устройствами, они являются постоянными, а не удаленными процедурными вызовами. Процедуры отображаются один-в-один с типами сообщений 9P. Локально каждый канал имеет связанную структуру данных, которая хранит тип поля, используемого для индексирования таблицы процедурных вызовов, один комплект на тип файловой системы, аналогично для выбора метода, установленного для объекта. Одно устройство монтирования ядра транслирует вызовы локальных процедур 9P в сообщения RPC для удаленных сервисов, при этом используется отдельный протокол передачи данных наподобие TCP или IL, новый надежный протокол дейтаграмм, или же канал к пользовательскому процессу. Вызовы чтения и записи выполняют передачу сообщений через транспортный уровень. Устройство монтирования считается исключительным мостом между процедурным интерфейсом, который видят пользовательские программы, и сервисами локального и пользовательского уровней. Он выполняет все ассоциированные операции, включая управление буфером и мультиплексирование, и представляет собой единственный неотъемлемый механизм RPC в Plan 9. Устройство монтирования — это эффективный объект полномочий. В системе отсутствует компилятор RPC, взамен устройство монтирования и все серверы используют библиотеку, которая выполняет упаковку и распаковку сообщений 9P.

Примеры

В Plan 9 существует один из типов файловых систем, который служит как средство постоянного хранения данных главного файлового сервера. Это автономная многопроцессорная система включает дисковод с автоматической сменой WORM-дисков общей емкостью 350 GB как основной накопитель, двухуровневый блочный кеш на магнитном диске емкостью 7 GB и 128 MB RAM. Клиенты подключаются к файловому серверу через любые типы сетей и протоколов и, используя 9P, получают доступ к его файлам. Файловый сервер работает с четкой операционной системой, в которой присутствует поддержка пользовательских процессов и стандартный набор команд, доступных в консоли. Все, что он делает, это отвечает на сообщения 9P от клиентов.

Page 31:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Один раз в сутки, в 5:00 утра, файловый сервер выполняет разметку кеш блоков и маркирует dirty блоки копирования-для-записи. Он создает каталог в корне файловой системы и присваивает ему название, используя текущую дату, например 1995/0314. Затем он запускает фоновый процесс копирования dirty блоков на WORM диск. В результате сервер возвращает образ файловой системы, какой она была этим утром. Набор устаревших каталогов доступен при использовании 9P, таким образом, используя обычные команды, клиент может работать с резервными копиями файлов. Благодаря использованию сервиса резервирования, реализованного в виде простой файловой системы, мы получили ряд преимуществ, наиболее очевидное из которых состоит в том, что к файлам возможен доступ обычными командами. К примеру, чтобы увидеть когда была устранена ошибка, выполните команду наподобие этой

grep 'mouse bug fix' 1995/*/sys/src/cmd/8½/file.c

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

Файловый сервер — это лишь один из типов файловых систем. Большее число необычных сервисов применяются вместе с ядром как локальные файловые системы. Эти сервисы не ограничиваются лишь устройствами ввода-вывода как, к примеру, диски. Они включают сетевые устройства и связанные с ними протоколы, растровый экран и мышь, представление процессов схожих с /proc [1], пары имя/значение, формирующие «окружение», которую получает новый процесс, профилевые сервисы и их ресурсы. Каждый из них представляет собой файловую систему, т.е. каталог, содержащий набор файлов, но эти файлы, все же, отличаются от обычных тем, что они не являются постоянными хранилищами на диске. Взамен, они близки по свойствам к файлам устройств Unix.

К примеру, консольное устройство содержит файл /dev/cons, схожий с /dev/console в Unix. При записи, /dev/cons добавляется к консольному машинописному тексту, при чтении, он возвращает символы, введенные с клавиатуры. Другие файлы в консольном устройстве включают /dev/time — количество секунд с начала эпохи, /dev/cputime — процессорное время, используемое процессом при чтении устройства, /dev/pid — идентификатор процесса, читающего устройство, и /dev/user — логин пользователя, который получил доступ к устройству. Все эти файлы являются текстовыми, так что их использование не влечет проблем с порядком байт. При чтении их содержимые синтезируются по требованию, при записи они вызывают модификации в структурах данных ядра.

Процессовое устройство Plan 9 содержит по одному каталогу на каждый действующий локальный процесс. Эти каталоги получают названия от числовых идентификаторов их процессов: /proc/1, /proc/2, и т.д., каждый из них содержит набор файлов для доступа к процессу. К примеру, в каждом каталоге файла mem находится образ виртуальной памяти процесса, который может быть прочитан или записан для отладки. Файл text представляет собой некий сорт ссылки на файл, из которого будет выполняться процесс, он открывается при чтении таблиц символов для этого самого процесса. Для управления выполнением процесса в файл ctl записываются текстовые сообщения вроде stop или kill. В файле status находится строка специального формата, которая содержит информацию о процессе: его название, владелец, состояние и т.д. Текстовые строки, записываемые в файл заметок, доставляются процессу как специальные сообщения, аналогично сигналам в Unix. Эти сервисы реализованы текстовым вводом-выводом над файлами, а не системными вызовами (наподобие, скажем, kill) или специализированными операциями (наподобие ptrace). Процессовое устройство упрощает реализацию отладчиков и связанных программ. Например, команда

Page 32:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

cat /proc/*/status

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

Растровое устройство содержит три файла: /dev/mouse, /dev/screen и /dev/bitblt, обеспечивающих интерфейс для локального растрового дисплея (если таковой имеется) и координатное устройство. Файл mouse возвращает запись специального формата, содержащую 1 байт для состояния кнопки и 4 байта для каждой позиции мыши (координаты по x и y). Если мышь не перемещалась с момента последнего чтения этого файла, последующее чтение будет блокировано. В файле screen находится растровый образ содержимого экрана, а файлом bitblt обеспечивается процедурный интерфейс. Вызовы к графической библиотеке транслируются в сообщения, которые впоследствии записываются в файл bitblt для выполнения операций с растровой графикой. (Это, по существу, вложенный протокол RPC.)

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

mount(int fd, char *old, int flags)

аутентифицирует пользователя и подключает файловое дерево сервиса к каталогу под названием old. Fd — это файловый дескриптор, который хранит открытый соединительный канал для сервиса. Аргумент flags определяет способ подключения к old: (1) замена текущего содержимого; (2) появление перед текущим содержимым каталога; (3) появление после текущего содержимого каталога. Каталог с несколькими подмонтированными сервисами носит название союзного каталога. Вызов

bind(char *new, char *old, int flags)

делает часть существующего пространства имен видимым в new, будь то файл или каталог, а также в old. Например, команда

bind("1995/0301/sys/include", "/sys/include", REPLACE)

выполняет перекрытие каталога включаемых файлов (include files) с его дамповым содержимым от первого марта.

Создание процесса выполняет системный вызов rfork, его аргумент — битовый вектор, описывает какие атрибуты процесса будут разделены между порождающим и порожденным процессом (взамен их обычному копированию в Unix). Одним из атрибутов является пространство имен, при его разделении, изменения одного процесса оказывают влияние на другой, изменения независимы только при копировании.

Хотя глобального пространства имен и не существует, для нормального функционирования процесса локальные пространства имен должны придерживаться глобальных соглашений. Следует также отметить тот факт, что использование локальных пространств имен критично для системы. Для иллюстрации этих идей подходит использование пространства имен для управления гетерогенностью. Двоичные файлы для данных архитектур находятся в каталоге, который имеет название от типа архитектуры (например, /mips/bin), при работе этот каталог связывается с /bin. (В связи с этим нет нужды в использовании специализированной переменной окружения PATH.) Локальные связи (bindings) также полезны при отладке.

Page 33:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Оконная система 8½ [5] — это сервер для файлов типа /dev/cons и /dev/bitblt. Каждый клиент видит четкие копии этих файлов в своем пространстве имен. Каждый пример /dev/cons подается 8½ в локальном пространстве окна. Вновь, 8½ реализует сервисы, используя локальные пространства имен плюс использование ввода-вывода для стандартно названных файлов. Каждый клиент соединяет свой стандартный ввод, вывод и файлы ошибок с /dev/cons, аналогичные операции используются для доступа к растровой графике. Такая реализация весьма отличается от реализации драйвера /dev/tty в Unix, который выполняется специальным кодом в ядре, перезагружает файл при открытии, со стандартными вводом или выводом процесса. При этом чтобы вести себя предсказуемо с /dev/tty оконная система Unix должна подвергаться специальным преобразованиям.

Среда 8½ обеспечивает клиентам точно такую же среду, в которой она сама реализована, т.е. стандартный набор файлов в /dev. Это дает возможность оконной системе запускаться рекурсивно в одном из своих окон, что вновь удобно при отладке. Также это означает, что если файлы экспортируются на другую машину, как будет описано ниже, оконная система или клиентские приложения могут запускаться прозрачно на ней, даже при отсутствии графического оборудования как такового. Этот механизм использовался при реализации оконной системы X Window в Plan 9: X запускается как клиент 8½, часто на удаленной машине с большим количеством оперативной памяти. Мы произвели некоторые подсчеты и выяснилось, что при использовании Ethernet для соединения машин MIPS, коэффициент снижения производительности запуска X на Plan 9 машине равен от силы 10 %, комментарии излишни.

Примером использования этих идей считается файловая система сбора статистики, реализованная командой iostats. Работа этой команды заключается в изоляции процесса в локальном пространстве имен и проверке запросов 9P, идущих от процесса к внешнему миру. После завершения работы iostats выводит использование и файловую активность данного процесса. К примеру, выполнение команды таким образом

iostats 8½

выводит сколько ввода-вывода оконная система тратит на растровое устройство, файлы шрифтов и т.п.

Команда import соединяет часть пространства имен удаленной системы с локальным пространством имен. Ее задача заключается в подключении к удаленной машине и запуске на ней процесса, который, используя 9P, обслуживает удаленное пространство имен. Затем она вызывает mount для присоединения этого пространства имен к локальному и, наконец, завершает свою работу. Import часто используется для получения доступа к устройствам, не доступным локально. Например, для записи файла на удаленную дискету можно выполнить следующее

import lab.pc /a: /n/doscp foo /n/dos/bar

Первая строка импортирует файловое дерево /a: машины lab.pc (которая должна поддерживать 9P) в локальный каталог /n/dos. Вторая посредством простого копирования записывает файл foo на дискету.

Еще одно применение import заключается в удаленной отладке:

import helix /proc

делает доступной локально файловую систему процессов машины helix; после этого команды наподобие ps взамен локальным процессам будут иллюстрировать процессы helix, и отладке можно будет поддать удаленный процесс:

Page 34:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

db /proc/27/text /proc/27/mem

Также доступна и кросс архитектурная отладка. Таким образом есть возможность перекрестной отладки процесса машины little-endian i386 на, скажем, big-endian MIPS.

Сетевые интерфейсы реализованы тоже как файловые системы [4]. Например, /net/tcp — это каталог в чем-то схожий с /proc, он содержит набор нумерованных подкаталогов, по одному на каждое соединение. Каждый из каталогов содержит файлы для передачи и управления соединением. Посредством доступа к файлу /net/tcp/clone процесс распределяет новое соединение. Здесь также происходит оценка неиспользуемых соединений. Чтобы сделать вызов, процесс записывает текстовое сообщение вроде «connect 135.104.53.2!512» в файл ctl, а затем читает и записывает файл с данными. Сервис rlogin может быть реализован в нескольких строках кода в оболочке.

Такая структура делает легким сетевое шлюзование. Мы используем машины с интерфейсами Datakit, а не Internet. Вот так

import helix /nettelnet tcp!ai.mit.edu

Первая строка использует Datakit для импорта TCP интерфейса с helix, который затем может использоваться непосредственно. Нотация tcp! обязательна, поскольку мы программно используем многочисленные сети и протоколы в Plan 9, здесь она определяет сеть, в которой адрес ai.mit.edu является корректным.

На практике мы не используем ни rlogin, ни telnet между машинами Plan 9, взамен мы пользуемся командой cpu, которая эффективно заменяет процессор в окне на процессор другой машины (типично это быстрый многопроцессорный CPU сервер). Такая реализация воссоздает пространство имен на удаленной машине, используя эквивалент команды import для соединения частей пространства имен терминала с процессом (оболочкой) на CPU сервере, она делает терминал файловым сервером для CPU. CPU-локальные устройства вроде быстрых соединений файловых систем все еще локальны, импортированию поддаются лишь терминало резидентные устройства. Такой механизм чужд как Unix rlogin, который перемещается в четкое пространство имен на удаленной машине, так и разделению файлов с NFS, при котором пространство имен остается без изменений, но процессы выполняются локально. Связи в /bin могут изменяться поскольку меняются процессорные архитектуры, связанные сети также могут отличаться на различном аппаратном обеспечении, при этом получается эффект повышения скорости процессора в текущем пространстве имен.

Позиция

Все вышеописанные примеры иллюстрируют то, как идеи представления ресурсов в виде файловых систем и пространства имен процессов могут использоваться для решения определенного класса проблем, при этом часто приходится прибегнуть к достаточно экзотическим механизмам. Все же в Plan 9 существуют операции, которые не имеют отображения в файловом вводе-выводе. Примером тому операция создания нового процесса, детали создания окружения которого: открытые файлы, использование памяти и т.д. — слишком сложные и описать их в простой операции ввода-вывода очень трудно (почти невозможно). Как результат, новые процессы в Plan 9 создаются довольно стандартными системными вызовами rfork и exec, при этом каталог /proc используется лишь для представления существующих процессов и управления ими.

Plan 9 не отображает сетевые пространства имен в пространство имен файловой системы по нескольким причинам. Во-первых: разные правила адресации для различных сетей и протоколов не могут одинаково отображаться в иерархическое файловое пространство имен. Во-вторых: даже если бы это было возможно, различные механизмы аутентификации, выбора

Page 35:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

сервисов и управления соединением не смогли бы последовательно отображаться в операции над файлом.

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

И все-таки, несмотря на эти небольшие ограничения, файловые системы и пространства имен предлагают эффективную модель, вокруг которой можно построить распределенную систему. При удачном использовании они могут обеспечить однородный, знакомый, прозрачный интерфейс для разнообразного набора распределенных ресурсов. Они имеют представление о правах доступа, безопасности и схеме присваивания имен. Интеграция устройств в иерархическую файловую систему была отличной идеей в Unix. Plan 9 намного дальше продвигает эти концепции и показывает, что при изобретательном использовании файловые системы имеют много граней для продуктивных исследований.

Литература

[1] T. Killian, Processes as Files, USENIX Summer Conf. Proc., Salt Lake City, 1984[2] R. Needham, Names, in Distributed systems, S. Mullender, ed., Addison Wesley, 1989[3] R. Pike, D. Presotto, K. Thompson, H. Trickey, Plan 9 from Bell Labs, UKUUG Proc. of the Summer 1990 Conf., London, England, 1990[4] D. Presotto, Multiprocessor Streams for Plan 9, UKUUG Proc. of the Summer 1990 Conf., London, England, 1990[5] Pike, R., 8.5, The Plan 9 Window System, USENIX Summer Conf. Proc., Nashville, 1991

Copyright © 2000 Lucent Technologies Inc. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Сетевая организация в Plan 9Дейв ПресоттоФил Уинтерботтом

presotto,[email protected]

АБСТРАКТНО

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

1. Введение

Plan 9 [1] представляет собой многопользовательскую портабильную распределенную систему общего назначения, функционирующую на разнообразных компьютерах и сетях.

Page 36:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Plan 9 отличается от других систем своей организацией, перед которой ставились две цели: уменьшение администрирования и продвижение совместного использования ресурсов. Одним из факторов успеха Plan 9 как распределенной системы является организация и управление сетями.

Система Plan 9 состоит из файловых серверов, CPU серверов и терминалов. Файловые и CPU серверы обычно представляют собой централизованные многопроцессорные машины с большим количеством памяти и высокоскоростными взаимосвязями. Различные машины класса рабочих станций служат терминалами, соединенными с центральными серверами посредством нескольких сетей и протоколов. Архитектура системы нуждается в иерархии сетевых скоростей, соответствующих требованиям компонентов. Соединения между файловыми и CPU серверами — волоконные связи точка-точка, обладающие высокой пропускной способностью. Соединения от серверов развертываются к локальным терминалам с использованием сетей средней скорости, наподобие Ethernet [4] и Datakit [5]. Низкоскоростные соединения через Internet и базовую сеть AT&T обслуживают пользователей в Орегоне и Иллинойсе. Сеть типа ISDN и последовательные линии на 9600 baud обеспечивают медленные связи с пользователями на дому.

Поскольку CPU серверы и терминалы используют одно и то же ядро, у пользователей есть выбор: запускать программы локально на своих терминалах или удаленно на CPU серверах. Организация Plan 9 скрывает детали системной связности, позволяя и пользователям, и администраторам конфигурировать свою среду, чтобы получить распределения или централизацию, по их усмотрению. Простые команды поддерживают конструкцию локально представленного пространства имен, которое распределяется на много машин и сетей. На работе пользователи используют свои терминалы как рабочие станции, запуская интерактивные программы локально и резервируя CPU серверы для заданий интенсивной обработки данных, типа компиляции и вычисления шахматных эндшпилей. Дома или при соединении через медленную сеть, пользователи для снижения траффика на медленных связях выполняют большую часть работы на CPU сервере. Задача сетевой организации состоит в обеспечении одинаковой среды для клиентов (пользователей) независимо от используемых ресурсов.

2. Сетевая поддержка в ядре

Сети играют важнейшую роль в любой распределенной системе. В особенности, это применимо к Plan 9, где большинство ресурсов организованы во внешние по отношению к ядру серверы. Значение сетевого кода в пределах ядра отражено в его размере; 25 тыс. строк ядерного кода, из которых 12,5 тыс. приходится на сеть, протокол и связанные средства. Сети непрерывно добавляются и доля кода, отведенного коммуникациям, постоянно растет. Кроме того, сетевой код достаточно сложный. Реализации протокола почти полностью состоит из синхронизации и управления динамической памятью, это область, требовательная к стратегиям, которым присущее тонкое восстановление ошибок. На сегодня ядро имеет поддержку Datakit, волоконных связей типа точка-точка, Internet (IP) протокола и ISDN. Разнообразные сети и машины подняли вопросы, которые ранее не были адресованы другими системами, запущенными на коммерческом аппаратном обеспечении с поддержкой только Ethernet или FDDI.

2.1 Протокол файловой системы

Центральной идеей Plan 9 является представление ресурсов в виде иерархической файловой системы. Каждый процесс создает вид системы путем построения пространства имен [2], объединяющего используемые им ресурсы. Файловые системы не должны представлять дисковые файлы; фактически, большинство файловых систем Plan 9 не имеют постоянной памяти. Типичная файловая система динамически представляет некоторые ресурсы подобно

Page 37:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

набору сетевых соединений или таблице процессов. Связь между ядром, драйверами устройств и локальными или удаленными файловыми системами обеспечивает протокол под названием 9P. Протокол состоит из 17 сообщений, описывающих операции над файлами. Ядро-резидентное устройство и драйверы протокола используют процедурную версию протокола, в то время как внешние файловые серверы используют форму RPC. Почти весть траффик между системами Plan 9 составляют сообщения протокола файловой системы. 9P основан на различных свойствах лежащего в его основе транспортного протокола. Он отвечает за надежную и последовательную доставку сообщений с сохранением разделителей.

Структура данных ядра, канал (channel), обрабатывается файловым сервером. Операции над каналом генерируют следующие сообщения 9P. Сообщения session и attach аутентифицируют соединение, установленное внешними по отношению к 9P средствами, и подтверждают пользователя. Результатом является аутентифицированный канал, указывающий на корневой каталог сервера. Сообщение clone создает новый канал, идентичный существующему (это сообщение во многом схоже с системным вызовом dup). Канал может быть перемещен в файл на сервере с помощью сообщения walk. Сообщения stat и wstat читают и записывают атрибуты в файл, указанный каналом. Сообщение open подготавливает канал для последующих сообщений read и write, отвечающих за доступ к содержимому файла. Create и remove выполняют соответствующие названиям действия над файлом, указанный каналом. Сообщение clunk отвергает канал без влияния на файл.

Драйвер монтирования — это ядро-резидентный файловый сервер, который преобразует процедурную версию 9P в версию RPC. Системный вызов mount представляет файловый дескриптор, который может быть конвейер пользовательского процесса или сетевым соединением с удаленной машиной, для ассоциирования с точкой монтирования. После монтирования, операции над файловым деревом ниже точки монтирования отправляются на файловый сервер в виде сообщений. Драйвер монтирования управляет буферами, выполняет упаковку и распаковку параметров из сообщений, и демультиплексируется среди процессов с использованием файлового сервера.

2.2 Ядерная организация

Сетевой код ядра разделен на три слоя: аппаратный интерфейс, обработка протокола и программный интерфейс. Драйвер устройства обычно использует потоки для соединения двух интерфейсных слоев. Для обработки протоколов, модули дополнительного потока могут выталкиваться в устройстве. Каждый драйвер устройства является ядро-резидентной файловой системой. Простые драйверы устройств подаются в виде одноуровневого каталога, содержащего всего несколько файлов; например, мы представляем каждое UART устройство файлами данных и управления.

cpu% cd /devcpu% ls -l eia*--rw-rw-rw- t 0 bootes bootes 0 Jul 16 17:28 eia1--rw-rw-rw- t 0 bootes bootes 0 Jul 16 17:28 eia1ctl--rw-rw-rw- t 0 bootes bootes 0 Jul 16 17:28 eia2--rw-rw-rw- t 0 bootes bootes 0 Jul 16 17:28 eia2ctlcpu%

Ctl файл используется для управления устройством; запись строки b1200 в файл /dev/eia1ctl устанавливает скорость передачи данных 1200 baud.

Мультиплексные устройства представлены структурой с более сложным интерфейсом. К примеру, Ethernet драйвер LANCE подается в виде двухуровневого файлового дерева (Рис. 1), обеспечивая:

• управление и конфигурацию устройства;

Page 38:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

• протоколы пользовательского уровня наподобие ARP; • диагностические интерфейсы для программного обеспечения осмотра.

Верхний каталог содержит файл clone и по каталогу для каждого соединения, пронумерованные от 1 до n. Каждый каталог соединения соответствует типу пакета Ethernet. За открытием файла clone следует поиск неиспользуемого каталога соединения и открытие его ctl файла. Чтение управляющего файла возвращает ASCII номер соединения; пользовательский процесс может использовать это значение для создания соответствующего каталога соединения. В каждом каталоге соединения файлы ctl, data, stats и type обеспечивают доступ к соединению. Запись строки connect 2048 в ctl файл устанавливает тип пакета 2048 и ориентирует соединение для приема всех IP пакетов, отправленных машине. Последующие чтения файла type дадут строку 2048. Файл data имеет отношение к устройству, его чтение возвращает следующий пакет выбранного типа. Запись файла ставит в очередь передачи пакет, чей заголовок, содержащий исходный адрес и тип, был добавлен. Файл stats возвращает ASCII текст, который содержит следующие данные: адрес интерфейса, количество ввода-вывода пакета, статистику ошибок и общую информацию о состоянии интерфейса.

Если несколько соединений в интерфейсе сконфигурированы под конкретный тип пакета, тогда каждое будет получать копию входящих пакетов. Специальный тип пакета -1 выбирает все пакеты. Для приема всех пакетов из Ethernet необходимо в ctl файл записать строки promiscuous и connect -1.

Хотя интерфейс драйверов может показаться несколько сложным, представление устройства как набора текстовых файлов и использование ASCII строк для коммуникаций имеет несколько преимуществ. Любой механизм, поддерживающий удаленный доступ к файлам, позволяет удаленной машине использовать наши интерфейсы как шлюзы. При использовании ASCII строк для управления интерфейсом избегаются проблемы с порядком байт, обеспечивается единое представление устройств на одной машине, а также удаленный доступ к устройствам. Представление разнородных устройств в виде одинакового набора файлов позволяет общим средствам работать в различных сетях и интерфейсах. Программы вроде stty заменены на echo и переадресацию оболочки.

2.3 Устройства протокола

Сетевые соединения представлены как псевдо-устройства, которые называются устройствами протокола. Драйверы устройств присутствуют для протокола Datakit URP и каждого из Internet IP протоков TCP, UDP, и IL. IL, описанный ниже, является новым протоколом связи и используется в Plan 9 для передачи удаленных процедурных вызовов файловой системы. Все драйверы протокола выглядят одинаково, так что пользовательские программы не содержат специфического для сети кода.

Каждый драйвер устройства протокола подан в виде структуры каталогов аналогичной таковой в драйвере LANCE. Верхний каталог содержит файл clone и по каталогу для каждого соединения, пронумерованные от 0 до n. Каждый каталог содержит файлы управления, передачи и приема информации для одного соединения. Каталог соединения TCP выглядит таким образом:

cpu% cd /net/tcp/2cpu% ls -l--rw-rw---- I 0 ehg bootes 0 Jul 13 21:14 ctl--rw-rw---- I 0 ehg bootes 0 Jul 13 21:14 data--rw-rw---- I 0 ehg bootes 0 Jul 13 21:14 listen

Page 39:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

--r--r--r-- I 0 bootes bootes 0 Jul 13 21:14 local--r--r--r-- I 0 bootes bootes 0 Jul 13 21:14 remote--r--r--r-- I 0 bootes bootes 0 Jul 13 21:14 statuscpu% cat local remote status135.104.9.31 5012135.104.53.11 564tcp/2 1 Established connectcpu%

Файлы local, remote и status содержат информацию о состоянии соединения. Файлы data и ctl обеспечивают доступ к процессовому концу потока, реализующего протокол. Файл listen используется для приема входящих вызовов из сети.

Следующие шаги устанавливают соединение.

1. Клон устройства соответствующего каталога протокола открыт для резервирования неиспользуемого соединения.

2. Файловый дескриптор возвращается открытыми указателями в ctl файл нового соединения. Чтение файлового дескриптора возвращает номер соединения.

3. Специфичный для протокола/сети. ASCII строка с адресом записывается в ctl файл. 4. Путь к файлу data создан посредством номера соединения. Соединение

устанавливается, когда открывается файл data.

Процесс может читать и записывать этот файловый дескриптор в передаваемые и принимаемые сообщения из сети. Если процесс открывает файл listen, то происходит блокировка, пока не будет получен входящий вызов. Адрес строки записывается в ctl файл, перед тем как listen выберет порты или сервисы, которые процесс готов принимать. За приемом входящего вызова следует завершение открытия и возвращение файлового дескриптора, указывающий на ctl файл нового соединения. Чтение ctl файла дает номер соединения, который используется для создания пути к файлу data. Соединение остается установленным, пока любой из файлов в каталоге соединения является ссылочным или пока из сети не пришло сообщение close.

2.4 Потоки

Поток [3, 7] — это двунаправленный канал, соединяющий физическое или псевдо-устройство с пользовательскими процессами. Пользовательские процессы вставляют и удаляют данные из одного конца потока. Ядро обрабатывает действие на стороне устройства, вставляя данные в другой конец. С использованием потоков реализованы асинхронные каналы связи типа каналов, обмены информацией TCP, Datakit, и линии RS232.

Поток включает линейный список обрабатывающих модулей. Каждый модуль имеет две подпрограммы вставки (называемые также put-процедурами): поток-вверх (по отношению к процессу) и поток-вниз (по отношению к устройству). Вызов подпрограммы вставки модуля на любом конце вставляет данные в поток. Каждый модуль вызывает последующую отправку данных вверх или вниз в поток.

Пример обрабатывающего модуля представлен парой очередей, по одной для каждого направления. Очереди указывают на подпрограммы вставки и могут использоваться для поочередной передачи информации в потоке. Некоторые подпрограммы вставки выполняют локальное чередование данных, затем отправляя их в поток, это происходит или из-за последующего вызова, или асинхронного события, наподобие повторной передачи, или прерывания устройства. Обрабатывающие модули создают helper процессы ядра помощники для обеспечения контекста для управляющих асинхронных событий. К примеру, helper процесс ядра приводит к периодическому выполнению любых необходимых повторных передач TCP. Использование процессов ядра взамен серийным запуск-до-завершения

Page 40:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

процедурным службам отличается от реализации Unix потоков. Процедурные службы Unix не могут использовать любые блокирующие ресурсы ядра и в них отсутствует локальное долговечное состояние. Helper процессы ядра решают эти проблемы и существенно упрощают код потоков.

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

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

2.4.1 Пользовательский интерфейс

На пользовательском уровне поток представляют два файла: ctl и data. Фактические имена могут быть изменены драйвером устройства с использованием потока, как мы ранее продемонстрировали в примере с драйвером UART. Первый процесс, открывающий любой из файлов, автоматически создает поток. Последнее закрытие уничтожает его. Запись файла data приводит к копированию данных в блоки ядра и их передачи подпрограммой вставки поток-вниз в первый обрабатывающий модуль. Запись менее 32 KB гарантировано поместится в один блок. Параллельные записи в один поток не синхронизируются, хотя размер блока в 32 KB гарантирует элементарные записи большинства протоколов. Последний записанный блок имеет разделитель для предупреждения о границах записи модулей потока-вниз. В большинстве случаев первая подпрограмма вставки вызывает вторую, вторая вызывает третью и т.д., пока данные не закончатся. В результате, большинство данных выводятся без контекстного переключения.

Считывание файла data возвращает данные, организованные в очередь на верху потока. Считывание прекращается, когда количество чтений достигнуто или когда получен конец разделительного блока. Блокировка считывания потока приводит к тому, что только один процесс может читать из потока в данный момент времени и гарантирует, что прочитанные байты были непрерывными байтами из потока.

Подобно Unix потокам [7], потоки Plan 9 могут динамически конфигурироваться. Потоковая система перехватывает и интерпретирует следующие управляющие блоки:

push имя добавляет пример имени обрабатывающего модуля к верху потока

pop удаляет верхний модуль потокаhangup отправляет сообщение о зависании в поток из конца устройстваДругие управляющие блоки являются модуле-специфичными и интерпретируются каждым обрабатывающим модулем после передачи.

Свернутые синтаксис и семантика системного вызова Unix ioctl убедили нас оставить его вне Plan 9. Вместо него используется файл ctl. Запись информации в ctl файла идентична записи в файл data за исключением блоков, которые имеют тип управление. Обрабатывающий модуль выполняет грамматический разбор каждого управляющего блока, представленному ему. Командами в управляющих блоках служат ASCII строки, таким образом, когда одна система управляет потоками в пространстве имен, реализованном на другом процессоре, порядок байт не имеет значения. Поскольку управляющие операции редкие, то время грамматического разбора управляющих блоков роли не играет.

Page 41:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

2.4.2 Интерфейс устройства

Модуль на нижнем конце потока есть частью интерфейса устройства. Сведения интерфейса изменяются для каждого устройства. Большая часть интерфейсов устройств состоит из подпрограммы прерываний, подпрограммы вставки вывода, и процесса ядра. Подпрограмма вставки вывода предоставляет данные для устройства и запускает устройство, если оно остановлено. Подпрограмма прерываний будит процесс ядра всякий раз, когда устройство имеет ввод для обработки или нужно предоставить больше вывода. Процесс ядра помещает информацию в верх потока или предоставляет больше данных для вывода. Разделение труда на различные части изменяется в зависимости от того, как много должно быть сделано на уровне прерываний. Тем не менее, подпрограмма прерываний не должна распределять блоки или вызывать подпрограмму вставки, пока оба действия нуждаются в контексте процесса.

2.4.3 Мультиплексирование

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

Это схоже с реализацией мультиплексоров потоков Unix. Основное различие заключается в том, что у нас нет общей структуры, которая соответствует мультиплексору. Каждая попытка создания универсального мультиплексора производит более усложненную структуру, показывая тем самым основную трудность обобщения этого механизма. Сейчас мы кодируем каждый мультиплексор после периода бездействия и отдаем предпочтение чаще простоте, а не общности.

2.4.4 Отражения

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

Потоки остаются в нашем ядре, поскольку мы не в состоянии разработать лучшую альтернативу. X-ядро Ларри Питерсона (Larry Peterson) [6] является ближайшим кандидатом, но преимуществ, которые мы можем получить при переключении на него, недостаточно. Если бы код потоков поддавался обновлению, то для уменьшения сложности мы бы статически распределили ресурсы для большого фиксированного числа обменов информацией и сжигания памяти.

3. Протокол IL

Ни один из стандартных IP протоколов не пригоден для передачи сообщений 9P через сети Ethernet или Internet. У TCP слишком большие потери данных и он не сохраняет разделители сообщений. UDP, при низкой стоимости и сохранении разделителей сообщений, отличается ненадежной доставкой дейтаграмм. Во время реализации IP, TCP и UDP в нашей системе мы

Page 42:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

пробовали выбрать протокол, пригодный для переноса сообщений 9P. Необходимыми были такие свойства:

• Надежный сервис дейтаграмм с упорядоченной доставкой • Работа поверх IP • Низкая сложность, высокая производительность • Адаптивные тайм-ауты

Так как протокол, удовлетворяющий таким требованиям, не был найден, то мы разработали новый. IL — это легкий, изолированный от IP, протокол. Он основан на соединениях и обеспечивает надежную передачу упорядоченных сообщений. Поскольку протокол предназначен для передачи сообщений RPC между клиентом и сервером, то отпадает необходимость в средствах управления потоками. Нас вполне устраивает структура с присущими потоковыми ограничениями. Уменьшенное окно для нераспределенных сообщений предотвращает от буферизации слишком большого количества входящих сообщений; сообщения за пределами окна отвергаются и должны быть переданы повторно. Установка соединения использует дуплексное квитирование связи для генерации начальных последовательных номеров в каждом конце соединения; чтобы получатель мог изменять порядок сообщений, последующие сообщения данных увеличивают последовательные номера. В отличие от других протоколов, IL избегает слепые повторные передачи, таким образом не происходит продублирование сообщений. Это свойство повышает производительность протокола в перегруженных сетях, где слепые повторные передачи могут вызывать дальнейшие перегрузки. Подобно TCP, IL имеет адаптивные тайм-ауты, в результате чего протокол работает одинаково хорошо как в Internet, так и в Ethernet.

Для сохранения минимализма конструкции остальной части ядра, IL имеет небольшой размер. Код всего протокола составляет 847 строк, по сравнению с 2200 строками для TCP.

4. Сетевая адресация

Единого интерфейса для протоколов и устройств не достаточно для поддержки необходимой нам масштабируемости. Так как в каждой сети используется своя схема адресации, то ASCII строки, записываемые в управляющий файл, не имеют общего формата. В результате, каждое средство должно знать особенности сетей, которые оно способно адресовать. Кроме того, поскольку каждая машина поставляет подмножество доступных сетей, каждый пользователь должен быть осведомлен о том, поддерживаются ли сети каждым терминалом и сервером. Это неприемлемо.

Было создано и отвергнуто несколько возможных решений поставленной задачи. Мы могли бы использовать файловый сервер пользовательского уровня для представления сетевого пространства имен в виде файлового дерева Plan 9. Глобальная схема именования была реализована в других распределенных системах. Файловая иерархия обеспечивает пути к каталогам, которыми служат сетевые домены. Каждый каталог содержит файлы, которые являются именами машин в этом домене; примером может служить путь /net/name/usa/edu/mit/ai. Каждый файл машины содержит информацию типа IP адреса машины. Эта идея была отвергнута нами по нескольким причинам. Первая, трудно разрабатывать иерархию, охватывающую все представления различных сетевых схем адресации единым образом. Адресные строки Datakit и Ethernet не имеют ничего общего. Вторая причина, адрес машины часто составляет самую малую часть информации, требуемую для подключения к сервису на машине. К примеру, IP протоколы требуют символические имена сервисов для отображения в числовые номера порта, некоторые из которых привилегированные и следовательно, специальные. Информацию такого рода трудно представить в терминах операций над файлами. И, наконец, размер и количество представляемых сетей обременяют пользователя неприемлемо большим объемом

Page 43:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

информации об организации сетей и их связности. В таком случае представление ресурса как файл не уместно.

Если средства будут независимыми от сетей, сторонний сервер должен разрешать сетевые имена. Сервер на каждой машине, с локальным знанием, может выбрать лучшую сеть для любого конкретного расположения машины или сервиса. Поскольку сетевые устройства представляют общий интерфейс, то единственной операцией, которая отличается между сетями, является разрешение имен. Символическое имя должно переводиться в путь аналогичного файла устройства протокола и адресную ASCII строку для записи в ctl файл. Сервер соединений (connection server, CS) обеспечивает такой сервис.

4.1 Сетевая база данных

В большинстве систем сетевую информацию хранят несколько файлов наподобие /etc/hosts, /etc/networks, /etc/services, /etc/hosts.equiv, /etc/bootptab и /etc/named.d. Большую часть времени и усилий затрачивается на администрирование этих файлов и поддержку их взаимной последовательности. Программные средства пытаются автоматически создать один или более файлов из информации других файлов, но эксплуатация продолжает усложняться и иметь склонность к ошибкам.

Так как мы писали полностью новую системы, то могли свободно пробовать более простой метод. Одна база данных на распределенном сервере содержит всю информацию, требуемую для сетевого администрирования. Два текстовых файла включают основную базу данных: /lib/ndb/local содержит локально управляемую информацию и /lib/ndb/global содержит информацию, импортируемую из других мест. Файлы содержат комплекты пар атрибут/значение формы атр=значение, где атр и значение — текстовые строки. Системы описаны многострочными записями; строка-заголовок в левом поле начинает каждую запись предваренными нулем или более отступов парами атрибут/значение, которые определяют имена, адреса, свойства и т.п. Например, запись для нашего CPU сервера определена доменным именем, IP адресом, Ethernet адресом, Datakit адресом, загрузочным файлом и поддерживаемыми протоколами.

sys = helix dom=helix.research.bell-labs.com bootf=/mips/9power ip=135.104.9.31 ether=0800690222f0 dk=nj/astro/helix proto=il flavor=9cpu

Если некоторые системы делят записи вроде сетевой маски и шлюза, тогда взамен системы мы определяем эту информацию с сетью или подсетью. Следующие записи описывают IP сеть класса B и несколько подсетей, производные от нее. Запись для сети определяет IP маску, файловую систему и аутентификационный сервер для всех систем сети. Каждая подсеть определяет ее IP шлюз по умолчанию.

ipnet=mh-astro-net ip=135.104.0.0 ipmask=255.255.255.0 fs=bootes.research.bell-labs.com auth=1127authipnet=unix-room ip=135.104.117.0 ipgw=135.104.117.1ipnet=third-floor ip=135.104.51.0 ipgw=135.104.51.1ipnet=fourth-floor ip=135.104.52.0 ipgw=135.104.52.1

Записи базы данных также описывают отображение сервисных имен в номера портов для

Page 44:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

TCP, UDP и IL.

tcp=echo port=7tcp=discard port=9tcp=systat port=11tcp=daytime port=13

Все программы читают базу данных непосредственно, как результат, проблемы стабильности редки. Тем не менее, файлы базы данных могут увеличиваться в размерах. Наш глобальный файл, содержащий всю информацию об обеих Datakit и Internet системах в AT&T, имеет 43 тыс. строк. Для ускорения поиска, мы построили файлы хэш таблиц для каждого атрибута, поиск по которым производиться чаще других. Записи хэш файла указывают на записи в основных файлах. Каждый хэш файл содержит время модификации основного файла, так что мы можем избежать использования устаревших хэш таблиц. Поиски по атрибутам, которые не прохэшированы или чьи хэш таблицы устарели, все еще работают, они просто выполняются немного дольше.

4.2 Сервер соединений

В каждой системе процесс сервера соединений пользовательского уровня, CS, преобразует символические имена в адреса. Для преобразования имен, CS использует информацию о доступных сетях, сетевой базе данных и других серверах (вроде DNS). CS — это файловый сервер, обслуживающий всего-лишь один файл, /net/cs. Клиент записывает символическое имя в /net/cs, затем читает одну строку для каждого соответствующего места назначения, достижимого из этой системы. Строки представляют собой форму имя файла сообщение, где имя файла — это путь открываемого аналогичного файла для нового соединения и сообщение — это строка, запись который приводит к созданию соединения. Следующий пример иллюстрирует это. Программа ndb/csquery выводит приглашения для записи строк в /net/cs и выводит ответы.

% ndb/csquery> net!helix!9fs/net/il/clone 135.104.9.31!17008/net/dk/clone nj/astro/helix!9fs

CS обеспечивает преобразование мета-имен для выполнения сложных поисков. Специальное сетевое имя net выбирает любую сеть между источником и местом назначения, поддерживающую указанный сервис. Имя хоста в форме $атр — это имя атрибута в сетевой базе данных. Поиск в базе данных возвращает значение соответствующей пары атрибут/значение, наиболее близко связанной с хостом источником. Наиболее близко связанная пара описана в сетевой основе. К примеру, символическое имя tcp!$auth!rexauth заставляет CS выполнить поиск атрибута auth в записи базы данных для исходной системы, затем в ее подсети (если есть) и затем в ее сети.

% ndb/csquery> net!$auth!rexauth/net/il/clone 135.104.9.34!17021/net/dk/clone nj/astro/p9auth!rexauth/net/il/clone 135.104.9.6!17021/net/dk/clone nj/astro/musca!rexauth

Обычно CS получает информацию именования из файлов своей базы данных. Тем не менее для доменных имен CS сначала обращаться к другому процессу пользовательского уровня, серверу доменных имен (DNS). Если нет DNS, то CS полагается на свои собственные таблицы.

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

Page 45:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

обслуживающий один файл, /net/dns. Клиент записывает запрос в форме доменное-имя тип, где тип — это ресурс сервиса доменного имени. DNS выполняет рекурсивный запрос через систему доменных имен Internet, представляя по одной строке на каждую найденную запись ресурса. Клиент читает /net/dns для извлечения записей. Также как и другие серверы доменных имен, DNS кеширует информацию, полученную из сети. DNS реализован как многопроцессовое приложение с совместным использованием памяти, отдельные процессы которого прослушивают сетевые и локальные запросы.

5. Библиотечные подпрограммы

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

5.1 Подключение

Библиотечный вызов dial устанавливает соединение с удаленным местом назначения. Он возвращает дескриптор открытого файла для файла data в каталоге соединения.

int dial(char *dest, char *local, char *dir, int *cfdp)

dest Символическое имя/адрес места назначения

localЛокальный адрес. Так как большинство сетей не поддерживают его, обычно установлен в нуль.

dir Указатель на буфер хранения путевого имени каталога протокола, представляющего соединение. Dial заполняет этот буфер, если указатель не нуль.

cfdpУказатель на файловый дескриптор для ctl файла соединения. Если указатель не нуль, dial открывает управляющий файл и выталкивает файловый дескриптор сюда.

Большинство программ вызывают dial с именем места назначения и всеми другими аргументами-нулями. Dial использует CS для преобразования символического имени во все возможные адреса назначений и пытается подключится к каждому из них. Указание специального имени net в сетевой части позволяет CS выбрать общую пару сеть/протокол для места назначения, на котором доступен запрашиваемый сервис. К примеру, система research.bell-labs.com имеет адрес nj/astro/research и IP адреса 135.104.117.5 и 129.11.4.1. Вызов

fd = dial("net!research.bell-labs.com!login", 0, 0, 0, 0);

пытается подключиться к nj/astro/research!login в Datakit и обоих 135.104.117.5!513 и 129.11.4.1!513 через Internet.

Dial принимает адреса взамен символическим именам. Например, имена tcp!135.104.117.5!513 и tcp!research.bell-labs.com!login являются эквивалентными ссылками на одну машину.

5.2 Прослушивание

Для прослушивания входящих соединений используется четыре подпрограммы. Сначала программа объявляет (announce()) свое намерение приема соединений, затем выполняет прослушивание (listen()) вызовов и, наконец, принимает (accept()) или отвергает (reject()) их. Announce возвращает дескриптор открытого файла для ctl файла соединения и заполняет dir путем к каталогу протокола для объявления.

int announce(char *addr, char *dir)

Page 46:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Addr — это объявленное символическое имя/адрес, если оно не содержит сервис, то объявление для всех сервисов выполняется неявно. Таким образом, любой может легко написать эквивалент программы inetd без необходимости в объявлении каждого отдельного сервиса. Объявление остается в силе, пока управляющий файл закрыт.

Listen возвращает дескриптор открытого файла для ctl файла и заполняет ldir информацией о пути к каталогу протокола для принятого соединения. Она приходит в dir из объявления.

int listen(char *dir, char *ldir)

Accept и reject вызываются с дескриптором управляющего файла и ldir, возвращенного вызовом listen. Некоторые сети вроде Datakit принимают также причину для отказа; IP сети игнорируют третий аргумент.

int accept(int ctl, char *ldir)int reject(int ctl, char *ldir, char *reason)

Приведенный ниже код реализует типичный TCP слушатель. Он объявляет себя, прослушивает соединения и порождает копию нового процесса для каждого из них. Новый процесс дублирует данные соединения, пока удаленный конец не закроет его. Символ «*» в имени означает, что объявление доступно для любого адреса, связанного с машиной, на которой запущена программа.

intecho_server(void){ int dfd, lcfd; char adir[40], ldir[40]; int n; char buf[256];

afd = announce("tcp!*!echo", adir); if(afd < 0) return -1;

for(;;){ /* прослушивание на предмет вызова */ lcfd = listen(adir, ldir); if(lcfd < 0) return -1;

/* создание копии процесса для дублирования данных */ switch(fork()){ case 0: /* принятие вызова и открытие файла data */ dfd = accept(lcfd, ldir); if(dfd < 0) return -1;

/* дублирование данных, пока не встречен символ конца файла EOF */ while((n = read(dfd, buf, sizeof(buf))) > 0) write(dfd, buf, n); exits(0); case -1: perror("forking"); default: close(lcfd); break; }

Page 47:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

}}

6. Пользовательский уровень

Связь между машинами Plan 9 реализуется почти исключительно посредством терминов сообщений 9P. При этом используется только два сервиса: cpu и exportfs. Сервис cpu аналогичен rlogin. Тем не менее, в отличие от эмуляции сеанса терминала через сеть, cpu создает процесс на удаленной машине, чье пространство имен эквивалентно пространству имен окна, в котором он был вызван. Exportfs — это сервер пользовательского уровня, который позволяет экспорт пространства имен из машины к машине через сеть. Он используется командой cpu для обслуживания файлов в пространстве имен терминала, когда они доступны из CPU сервера.

По соглашению, файловые системы протокола и драйверов устройств монтируются в каталог /net. Хотя пространство имен процесса позволяет пользователям конфигурировать произвольный вид системы, на практике их профайлы формируют стандартное пространство имен.

6.1 Exportfs

Exportfs запускается входящим сетевым вызовом. Слушатель (Plan 9 эквивалент inetd) перед запуском exportfs запускает профайл пользователя, запрашивающего сервис для создания пространства имен. После того как начальный протокол установил корень экспортируемого файлового дерева, удаленный процесс монтирует соединение, позволяя exportfs действовать в роли главного файлового сервера. Операции в импортируемом файловом дереве выполняются на удаленном сервере с возвращением результатов. Вследствие чего пространство имен удаленной машины экспортируется в локальное файловое дерево.

Команда import вызывает exportfs на удаленной машине, монтирует результат в локальное пространство имен и завершает работу. Для обслуживания монтирований не требуется локальный процесс; сообщения 9P генерируются драйвером монтирования ядра и отправляются непосредственно через сеть.

Exportfs должен быть многониточным, поскольку системные вызовы open, read и write могут вызывать блокировки. В Plan 9 отсутствует системный вызов select, но система позволяет совместное использование файловых дескрипторов, памяти и других ресурсов. Exportfs плюс конфигурируемое пространство имен реализуют совместное использование (другими словами, распределение) ресурсов между машинами. Это строительный блок для создания комплексных пространств имен, сформированных из многих машин.

Простота интерфейсов способствовала наивным пользователям эксплуатировать потенциал богато соединенной среды. При использовании этих средств шлюзование между сетями представляется довольно таки легкой задачей. К примеру, терминал с одним Datakit соединением может импортировать из сервера helix:

import -a helix /nettelnet ai.mit.edu

Команда import создает Datakit соединение с машиной helix, на которой запущен пример exportfs для представления /net. Import монтирует удаленный каталог /net после (опция -a команды import) существующего содержимого локального каталога /net.

Page 48:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Каталог содержит союз локальных и удаленных содержимых /net. Локальные данные заменяются удаленными с тем же именем, так что сети в локальной машине выбраны с предпочтением удаленности. Тем не менее, уникальные данные в удаленном каталоге теперь доступны в локальном каталоге /net. Все сети, соединенные с helix, т.е. не только Datakit, теперь доступны с терминала. Эффект в пространстве имен показан в следующем примере:

philw-gnot% ls /net/net/cs/net/dkphilw-gnot% import -a musca /netphilw-gnot% ls /net/net/cs/net/cs/net/dk/net/dk/net/dns/net/ether/net/il/net/tcp/net/udp

6.2 Ftpfs

Мы решили реализовать наш интерфейс протокола FTP в виде файловой системы, а не традиционной команды. Наша команда ftpfs подключается к FTP порту удаленной системы, запрашивает логин и пароль, устанавливает образный режим и монтирует удаленную файловую систему в /n/ftp. Для уменьшения траффика, файлы и каталоги поддаются кешированию. Кеш обновляется всякий раз, когда создается файл. Ftpfs работает с TOPS-20, VMS и различными реализациями Unix как с удаленными системами.

7. Волоконные связи Cyclone

Файловые и CPU серверы соединены связями типа точка-точка высокой пропускной способности. Связь состоит из двух карт VME, соединенных парой оптических волокон. Картами VME используются процессоры Intel 960 33 MHz и волоконные трансмиттеры/ресиверы AMD TAXI для управления линиями на скорости 125 Mbit/сек. ПО в VME уменьшает время ожидания посредством копирования сообщений из системной памяти в волокно без промежуточной буферизации.

8. Эффективность

Мы проводили измерения времени ожидания и производительности чтения и записи байт между двумя процессорами на различных маршрутах. Тесты проводились на двух- и четырехпроцессорных CPU серверах SGI Power Series с процессорами MIPS 3000 25 MHz. За время ожидания принималось время задержки отправки байт от одного процесса к другому и обратно. Измерения производительности проводились с использовании 16 KB записей от одного процесса к другому.

Таблица 1 — эффективность

тест производительность,

MByte/сек время ожидания,

мили сек

pipes 8,15 0,255 IL/ether 1,02 1,42

URP/Datakit 0,22 1,75

Page 49:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Cyclone 3,2 0,375

9. Выводы

Представление всех ресурсов в виде файловых систем в связке с ASCII интерфейсом оказалось более мощным новацией, чем мы первоначально полагали. Ресурсы могут использоваться любым компьютером в наших сетях независимо от порядка байт или типа процессора. Сервер соединений обеспечивает изящные решения использования несвязанных средств в сетях. Пользователи успешно используют Plan 9 без знания топологии системы или сетей, используемых ими. Больше информации о 9P может быть найдено в разделе 5 руководства программиста Plan 9, первый том.

Литература

[1] R. Pike, D. Presotto, K. Thompson, H. Trickey, Plan 9 from Bell Labs, UKUUG Proc. of the Summer 1990 Conf., London, England, 1990. [2] R. Needham, Names, in Distributed systems, S. Mullender, ed., Addison Wesley, 1989. [3] D. Presotto, Multiprocessor Streams for Plan 9, UKUUG Proc. of the Summer 1990 Conf., London, England, 1990. [4] R. Metcalfe, D. Boggs, C. Crane, E. Taf and J. Hupp, The Ethernet Local Network: Three reports, CSL-80-2, XEROX Palo Alto Research Center, February 1980. [5] A. G. Fraser, Datakit - A Modular Network for Synchronous and Asynchronous Traffic, Proc. Int'l Conf. on Communication, Boston, June 1980. [6] L. Peterson, RPC in the X-Kernel: Evaluating new Design Techniques, Proc. Twelfth Symp. on Op. Sys. Princ., Litchfield Park, AZ, December 1990. [7] D. M. Ritchie, A Stream Input-Output System, AT&T Bell Laboratories Technical Journal, 68(8), October 1984.

Copyright © 2000 Lucent Technologies Inc. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Page 50:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

APE — среда ANSI/POSIXГовард Трики[email protected]

Введение

Среда ANSI/POSIX, сокращенно APE, используется при необходимости портирования большого по размеру или часто-обновляемого программного обеспечения в Plan 9 или из нее. APE — это набор заголовков и объектного кода библиотек, построенных на стандарте ANSI C (ANSI X3.159-1989) и стандарте интерфейса операционных систем POSIX (IEEE 1003.1-1990, ISO 9945-1), POSIX часть описывает основные функции операционной системы. Использование APE влечет низкую скорость компиляции и выполнения кода, так что если импорт или экспорт ПО производится довольно редко и скорость имеет значение, то более приемлемым является использование обычной среды компиляции Plan 9. Другой причиной для использования среды Plan 9 (а не APE) является то, что ее организация заголовков более проста для запоминания и использования.

Существует также некоторые аспекты необходимого поведения POSIX, которые невозможно или очень трудно имитировать в Plan 9. Они описаны ниже. Опыт показывает, что имитирование возможно для большинства программ. Более серьезной проблемой является то, что многие программы используют не предусмотренные в стандарте POSIX функции и заголовки. APE содержит расширения POSIX в этом плане. Для того чтобы среда APE подходила для тестирования программ ANSI/POSIX, расширения должны быть явно описаны в разделе #define.

Pcc

Команда pcc работает как внешняя для компиляторов и загрузчиков Plan 9 C. Она запускает препроцессор ANSI C для исходных файлов, используя заголовки APE для определения директив #include <файл>; затем она запускает компилятор Plan 9 C; и наконец, она загружается с APE библиотеками для создания исполняемой программы. Документ «Как использовать компилятор Plan 9 C» (How to Use the Plan 9 C Compiler, /sys/doc/comp.ps) объясняет как переменные окружения используются при компиляции на различных архитектурах. Переменная окружения $objtype управляет тем, какой Plan 9 компилятор и загрузчик используются pcc, также как и размещение файлов заголовков и библиотек. Например, если переменная $objtype имеет значение mips, тогда pcc указывает cpp искать заголовки в каталоге /mips/include/ape, следующим после /sys/include/ape; затем pcc использует vc для создания объектных файлов с расширением .v; и наконец, vl используется для создания исполняемого кода с использованием библиотек из каталога /mips/lib/ape.

Psh и Cc

Команда pcc предназначена для просмотра исходного кода на наличие ANSI/POSIX, но сами программы постраиваются обычным для Plan 9 способом: посредством mk и созданием объектных файлов с именами, заканчивающимися расширением .v, и т.п. Но иногда бывает полезнее использовать программы POSIX make и cc (который создает объектные файлы с именами, заканчивающимися .o, а также автоматически вызывает загрузчик, если опция -c не указана). В таком случае, выполните следующую команду:

ape/psh

Page 51:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Она запускает POSIX оболочку со средой, включающей POSIX команды: ar89, c89, cc, basename, dirname, expr, false, grep, kill, make, rmdir, sed, sh, stty, true, uname, и yacc. Также есть несколько метка-заполнителей для команд, которые не предусмотрены в Plan 9: chown, ln и umask.

Команда cc обладает опциями POSIX c89, определенными в C-Language Development Utilities Option, приложении стандарта POSIX Shell and Utilities. Также существуют несколько нестандартных опций, описанных ниже:

• -v для эхо контроля команд при каждой передаче на stdout; • -A для включения прототипа предупреждений ANSI; • -S для вывода языка ассемблера в файл.s; • -Wp,арг-ы для передачи аргументов арг-ы в cpp; • -W0,арг-ы для передачи арг-ы в 2c, и т.п.; • и опция -Wl,арг-ы для передачи аргументов арг-ы в 2l, и т.д. и т.п.

Команда sh является оболочкой pdksh, наиболее распространенной и уступчивой POSIX версией Korn Shell. Реализация Plan 9 не содержит режимов редактирования emacs и vi.

Команда stty эффективна лишь в том случае, если команда ape/ptyfs запущена для вставки псевдо-tty интерфейса между /dev/cons и запущенной командой. Ни одна распространяемая команда не делает этого автоматически.

Символы

Стандарты C и POSIX требуют, чтобы определенные символы описывались в заголовках. Описание (или не описание) зависит от типа самих символов и усмотрения реализации. POSIX описывает макросы (макроопределения), которые также являются символами препроцессора, начинающимися с символа подчеркивания и с далее идущими буквами в верхнем регистре; если программа, описанная в разделе #defines, является макросом, то перед включением каких-либо заголовков она посылает запрос на то, чтобы определенные символы были видимыми в заголовках. Наиболее важным макросом является _POSIX_SOURCE: символы, характерные POSIX, становятся видимыми в соответствующих заголовках. Рассмотрим этот факт на примере: ANSI определяет некоторые имена, которые должны быть описаны, но POSIX, в свою очередь, определяет другие имена, такие как sigset_t, которые не допускаются согласно ANSI. Эта проблема решается созданием дополнительных символов видимыми только когда определен макрос _POSIX_SOURCE.

При экспорте программ он помогает установить, входит ли программа в одну из следующих категорий:

1. Строго соответствующая программа ANSI C. Ею используются лишь характеристики языка, библиотек и заголовков, соответствующие стандарту C. Она не зависит от неопределенного, неописанного, или зависимого от реализации поведения, и не превышает любой минимальный предел реализации.

2. Строго соответствующая программа POSIX. Аналогична вышеописанной, только для стандарта POSIX.

3. Усовершенствованный набор POSIX с расширениями. Каждое расширение выбирается макросом, так что ясно какие расширения здесь используются.

Что касается обезьяны, тьфу, то есть APE, если заголовки всегда включают объявления любых используемых библиотечных функций, то набор макросов, описанный в программе, будет указывать к какой из вышеперечисленных категорий относится программа. Чтобы выполнить это, символы, не соответствующие стандарту C или POSIX не должны описываться в заголовке, а те которые принадлежат стандарту POSIX должны защищаться макросом #ifdef _POSIX_SOURCE. К примеру, определения EDOM, ERANGE, и errno

Page 52:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

соответствуют стандарту C. Стандарт C допускает больше имен, начинающихся с буквы E, но наш заголовок описывает все макросы, отличные от _POSIX_SOURCE, в этом случае символы, требующиеся POSIX, также определяются. Это значит, что программа, использующая ENAMETOOLONG, не может замаскироваться под строго соответствующую программу ANSI C.

Pcc и cc не могут определять никакие препроцессоры, отличные от 5 встроенных в стандарт ANSI C: __STDC__, __LINE__, __FILE__, __DATE__, и __TIME__ . Любые другие должны определять себе в программе или, используя опцию -D, в командной строке.

Расширения

Операция, осуществляемая вставкой только необходимых имен в заголовки, полезна при экспорте программ, но она несколько мешает при импорте программ. Компромиссом может быть учитывание дополнительных символов в заголовках, дополнительных заголовках, и дополнительных библиотечных функциях, но только под управлением расширенных макросов. Следующие расширения предусмотрены; если они не указаны явно, то дополнительные библиотечные функции предусмотрены в библиотеке APE по умолчанию.

• _LIBG_EXTENSION. Разрешает использование графической библиотеки Plan 9 (функции описаны в man-странице graphics (2) ) за исключением того, что div должен быть переименован в ptdiv. Заголовок объявления необходимых типов и функций также включаем.

• _LIMITS_EXTENSION. POSIX не требует определения имен типа PATH_MAX и OPEN_MAX, но многие программы принимают так, будто бы они определены там. Если макрос _LIMITS_EXTENSION определен, то все те имена должны включаться с определениями.

• _BSD_EXTENSION. Это расширение включается не только в программы Berkeley Unix, но также и в большинство других смешанных программ, часто находящихся в составе других реализациях Unix. Расширение допускает включение любой из функций: для bcopy(), bcmp(), и др. из Berkeley; для gethostbyname(), и подобных ей связанных структур; для функции Berkeley select и связанных типов и макросов для работы с многочисленными входными источниками; <sys/ioctl.h> для функции ioctl (минимально реализованной); <sys/param.h> для NOFILES_MAX; <sys/pty.h> для поддержки псевдо-tty, посредством функций ptsname(int) и ptmname(int); <sys/resource.h>; <sys/socket.h> для сокетных структур, констант и функций; <sys/time.h> для определения структур timeval и timezone; и <sys/uio.h> для структуры iovec и функций writev и readv, используемых для разброса/сборки ввода-вывода. Определение макроса _BSD_EXTENSION также допускает различные экстра расширения в <ctype.h>, <signal.h>, <stdio.h>, <unistd.h>, <sys/stat.h>, и <sys/times.h>.

• _NET_EXTENSION. Разрешает включения, определяющие сетевые функции. Они описаны в man-странице dial (2) .

• _REGEXP_EXTENSION. Разрешает включения, определяющие функции соответствия регулярных выражений. Они описаны в man-странице regexp (2) .

• _RESEARCH_SOURCE. Расширение позволяет использовать небольшую библиотеку функций из десятой версии Unix (V10). Эти функции и типы необходимо использовать путем определения в заголовке. Предусмотренные функции: srand, rand, nrand, lrand и frand (улучшенные генераторы случайных чисел); getpass, tty_echoon, tty_echooff (для работы с терминальными характеристиками ); min and max; nap; и setfields, getfields, и getmfields (для синтаксического анализа строк в полях). Смотрите руководство программиста десятой версии Unix за детальным описанием всех этих функций.

Page 53:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Общие проблемы

Несколько больших систем, включая X11, были удачно портированы в Plan 9 с использованием APE (порт X11 не включается в основной дистрибутив Plan 9, поскольку для его поддержки нужно слишком много работы). Проблемы можно разделить на три основные категории: (1) используются характеристики не ANSI C/POSIX; (2) неадекватное имитирование POSIX функций; и (3) дефекты компилятора/загрузчика. Наибольшее количество проблем возникает в первой категории.

В данный момент POSIX только становится мишенью для программистов. Большая часть существующего кода написана для работы с одной из систем (или с обоими) BSD или System V Unix. Последняя довольно близка к POSIX, но, все-же, есть и некоторые различия. Также множество System V систем импортировали некоторые характеристики BSD, которые не являются частью POSIX. Хорошей стратегией портирования внешних программ является использование макроса CFLAGS=-D_POSIX_SOURCE; если это не работает, попробуйте добавить _D_BSD_EXTENSION а также включите <bsd.h> в исходные файлы. Вот некоторые решения проблем, которые могли остаться:

• Третий (окружение) аргумент к main. Взамен используйте глобальный environ. • OPEN_MAX, PATH_MAX, и т.п., принятые в <limits.h>. Перепишите для вызова sysconf или определите _LIMITS_EXTENSION.

• <varargs.h>. Перепишите для использования <stdarg.h>.

Неадекватность имитирования POSIX функций в Plan 9. Этот недостаток редко происходит (кроме случаев проблем с link), но, все-же, мы их опишем:

• Функции установки идентификатора пользователя, группы, эффективного идентификатора пользователя, эффективного идентификатора группы — не делают ничего полезного. Эту концепцию трудно имитировать в Plan 9. Chown также бесполезен.

• execlp и связанные с ней функции не просматривают значение переменной окружения PATH. В случае, если путевое имя программы не абсолютное, тогда они делают попытку в текущем каталоге и в каталоге /bin.

• Консультативная блокировка через fcntl не осуществима. • Трудно заставить работать корректно isatty. Использованная аппроксимация только

иногда правильна. • link неработоспособен. • Вместе с open, опция O_NOCTTY не имеет эффекта. Понятие управления tty чуждо

Plan 9. • setsid разделяет пространство имен и группу примечаний, только условно ведет

себя правильно. • Функции работы со стекингом сигналов, sigpending, sigprocmask и sigsuspend — не работают.

• Umask не работает, так как такого понятия нет в Plan 9. • Код, в котором есть вызов getenv("HOME") должен быть изменен на getenv("home") в Plan 9.

Copyright © 2000 Lucent Technologies Inc. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Page 54:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

8½, оконная система Plan 9Роб Пайк[email protected]

АБСТРАКТНО

8½ является оконной системой Plan 9, она обеспечивает текстовый ввод-вывод и сервисы растровой графики, как для локальных, так и для удаленных клиентских программ, обслуживая мультиплексируемый набор файлов этих клиентов. Доступ к мыши и экрану обеспечивают традиционные Unix файлы типа /dev/tty. Операции с растровой графикой в системе выполняются путем обращения к файлу /dev/bitblt, куда клиенты записывают кодированные сообщения для выполнения графических операций. 8½ необходимы те же файлы для ее собственного внедрения (она мультиплексирует свой интерфейс), поэтому она может работать рекурсивно, как клиент самой себя. Такая архитектура имеет много преимуществ и является легко осуществимой.

Введение

В 1989 году мною была создана модельная оконная система всего лишь из нескольких сотен строк кода на языке программирования по-умолчанию и необычная архитектура связывания параллельных процессов [1]. Так как система получилась элементарной, она продемонстрировала, что оконные системы в сущности не являются сложными. В этом же году оконная система была переписана на языке С для новой распределенной операционной системы Plan 9 [12] и получила название 8½. На дисплеях с разными цветовыми возможностями 8½ обеспечивает сервисы, необходимые современной оконной системе, включая программируемость и поддержку удаленной графики. Вся система, включая программу типа xterm [2] с функциями «вырезать и вставить» между окнами, находилась в пределах 90 KB исходного текста для процессора Motorola 68020. Это около половины размера ядра операционной системы, которое поддерживает ее, и десятой части размера X сервера [17] без xterm.

Так что же делает 8½ такой компактной? Большая часть сбережений происходит от общей простоты: 8½ содержит малое число графической фантастики, осмысленный интерфейс программирования, и небольшой, фиксированный пользовательский интерфейс. Часто решения в системе принимаются путем фиата — это трехкнопочная мышь, перекрывающиеся окна, встроенная терминальная программа и оконный менеджер, и т.п., а не путем удовлетворения вкусовых особенностей всех и каждого. Стоит отметить, что компактность 8½ не аскетична. Чтобы сделать использование удобным, она обеспечивает как основы, так и достаточное количество расширенных возможностей. Наиболее важным фактором, повлиявшим на ее небольшой размер, является разработка общей конструкции в виде файлового сервера. Структура такого типа может применятся в оконных системах традиционных Unix-подобных операционных систем.

Небольшой размер не оказывает влияния на функциональность оконной системы: она обеспечивает сервисы практически эквивалентные X Window. Хотя клиенты 8½ могут быть какой угодно сложности, тенденция имитирования конструкции 8½ и ее чистого интерфейса программирования приводят к тому, что они не такие раздутые как приложения Х.

Page 55:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Пользовательская модель

8½ может быть представлена в одном из двух вариантов: как единый экран, мышь и клавиатура терминала (в терминологии Plan 9) или же как массив независимых виртуальных терминалов рабочей станции (в коммерческой терминологии). Терминалы, в свою очередь, также делятся на две категории: текстовые (с поддержкой оболочки и обычного набора инструментальных средств) и графические (использующие всю мощь растрового экрана и мыши). Текст представлен в UTF — кодировке стандарта Unicode [12]. Механизм работы программного интерфейса основан на чтении и записи файлов из каталога /dev.

Исторически сложилось так, что общая модель и внешний вид 8½ подобны системе mux [9]. Как раз на них и остановимся не на долго. Правая кнопка мыши выводит меню управления окнами. Когда создается новое окно, в нем запускается оболочка по-умолчанию (в нашем случае это rc [1]). Стандартные ввод и вывод оболочки ориентированы окну и доступны через файл /dev/cons (console), аналогично /dev/tty в Unix. Смена названия этого файла говорит о разрыве с прошлым: Plan 9 не поддерживает телетайповую модель терминалов.

Графические приложения, как и обычные программы, запускаются путем ввода их имен в окне оболочки. Таким образом, приложение занимает окно, в котором было запущено; чтобы запустить приложение в новом окне, необходимо использовать внешнюю программу под название window, ее описание дается ниже. Для графических приложений модель виртуального терминала расширена отчасти. Она позволяет программам выполнять графические операции, доступ к мыши, и связанные функции путем чтения и записи файлов с именами типа /dev/mouse и /dev/window, мультиплексируемыми в окно подобно /dev/cons. Реализация и семантика этих файлов, как будет описано ниже, является центральной структурой 8½.

Программа по-умолчанию, запускаемая в окне, знакома пользователям терминалов Blit [6]. Она подобна таковой в mux [9], обеспечивающей мыше-основанное редактирование ввода и вывода, возможность прокрутки назад для просмотра недавнего вывода, и т.д. 8½ имеет уникальную особенность, вытекающую из ее строения. Реализуясь как файловый сервер, она обладает возможностью отложенного ответа на запросы чтения для конкретного окна. Эта опция переключается зарезервированной клавишей клавиатуры (ESC). Нажав ее один раз, вы приостановите чтение клиента из окна; повторное нажатие восстанавливает нормальное чтение, которое построчно поглощает любой текст. Таким образом, пользователь может редактировать многострочный входной текст на экране до того, как приложение увидит его; устраняется необходимость включения отдельного редактора для подготовки текста, например, почтовых сообщений. С этим связана и возможность ответа на считывания непосредственно из структуры данных, определяющих текст на дисплее: текст можно редактировать до тех пор, пока его конечная новая строка делает подготовленную строку текста считываемой для клиента.

Plan 9 и 8½

Plan 9 — это распределенная система, обеспечивающая поддержку Unix-подобных приложений в среде, которая построена из различных CPU серверов, файловых серверов и терминалов, соединенных в различные сети [12]. Терминалы сравнимы со скромными рабочими станциями, которые подключены к файловому серверу через сеть среднего масштаба типа Ethernet. Они самодостаточные компьютеры, запускающие полную операционную систему. Тем не менее, в отличие от рабочих станций, их задача заключается в обеспечении доступного мультиплексного пользовательского интерфейса для остальной части системы: они запускают оконную систему и поддерживают простые интерактивные задачи, такие как текстовое редактирование. Таким образом, они лежат примерно между рабочими станциями и X терминалами по конструкции, цене, производительности и

Page 56:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

функциональности. (Терминалы могут использоваться и для общих вычислений, но на практике пользователи Plan 9 выполняют свои вычисления на CPU серверах.) Терминальное программное обеспечение Plan 9, включая 8½, было разработано на 68020-основаной машине под названием Gnot и портировано на NeXTstation, MIPS Magnum 3000, SGI Indigos и Sun SPARC — все малые рабочие станции, которые мы используем в качестве терминалов, также как и PC.

Ресурсоемкие задания типа компиляции, текстовой обработки и научных вычислений выполняются на CPU серверах, которые соединены с файловыми серверами высокоскоростными сетями. При интерактивной работе эти вычисления могут быть доступны терминалам. Терминал и CPU сервер могут использоваться конкретным пользователем, если они подключены к одному файловому серверу, даже через разные типы сетей; Plan 9 обеспечивает независимый от расположения сети вид файлового сервера.

Компоненты Plan 9 соединены посредством общего протокола, основанного на распределении ресурсов. Все ресурсы в сети реализованы как файловые серверы; если программам необходим доступ к ним, то осуществляется соединение через сеть и связь с использованием обычных файловых операций. Необычным аспектом в Plan 9 является пространство имен процесса, т.е. набор файлов, который может быть доступен по имени (например, посредством системного вызова open), он не глобален для всех процессов машины; разные процессы имеют разные пространства имен. Система обеспечивает методы, благодаря которым процессы могут менять свои пространства имен, т.е. способность подмонтировать сервис в существующий каталог, сделав файлы сервиса видимыми в каталоге. (Эта операция сильно отличается от ее Unix тезки.) Многочисленные сервисы могут монтироваться в один каталог, при этом допускается возможность доступа многочисленных сервисов. Опции системного вызова mount управляют порядком поиска файлов в таком союзном каталоге.

Наиболее очевидным примером сетевого ресурса считается файловый сервер, основной задачей которого является постоянное хранение файлов. Также существует большое количество необычных сервисов, чья конструкция в различных средах может отличаться от файловоподобной. Множество таких сервисов описаны в другом документе [12]; некоторые из примеров представлены последовательностью процессов для отладки, они имеют много общего с файлами процессов Киллиана (Tom Killian) для 8-ой версии Unix [5], и реализация пар имя/значение среды Unix exec как файлов. Пользовательские процессы также должны реализовываться как файловые сервисы и быть доступными для клиентов через сеть, они очень похожи на «подмонтированные байт-ориентированные потоки» (mounted streams) в 9-ой версии Unix [15]. Типичный пример — программа, интерпретирующая внешне описанную файловую систему, такую как на CD-ROM дисках или стандартной Unix системе, и делает ее содержимое доступным для программ Plan 9. Такая конструкция использовалась во всех распределенных приложениях Plan 9, включая 8½.

8½ обслуживает набор файлов из стандартного каталога /dev с именами типа cons, mouse и screen. Клиенты 8½ общаются с оконной системой при помощи чтения и записи этих файлов. К примеру, клиентская программа, такая как оболочка, может выводить текст путем записи своего стандартного вывода, который автоматически соединяется с /dev/cons, или же путем явного чтения и записи этого файла. Тем не менее, в отличие от файлов, сохраняемых как традиционные файловые серверы, пример /dev/cons подается в каждом окне 8½ как некий четкий файл; пространства имен процессов Plan 9 позволяют 8½ обеспечивать уникальный /dev/cons каждому клиенту. Хорошей иллюстрацией этого механизма является создание нового клиента 8½.

Когда запускается 8½, она создает дуплексный канал, который представляет собой средство связи для сообщений, реализующих файловый сервис. Один конец распределяется между всеми клиентами, другой же, в свою очередь, организовывает поддержку 8½ для принятия

Page 57:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

запросов ввода-вывода. Когда пользователь, используя мышь, создает новое окно, 8½ распределяет оконные структуры данных и раздваивает порожденный процесс. Порожденное пространство имен, первоначально сохраняемое с порождающим, затем удваивается, таким образом изменения, проводимые в нем, не влияют на порождающее пространство имен. После этого порожденное пространство подключает свой конец соединительного канала, cfd, к каталогу /dev посредством системного вызова монтирования:

mount(cfd, "/dev", MBEFORE, buf)

Этот вызов подключает сервис, ассоциированный с файловым дескриптором cfd (клиентский конец канала), к началу /dev, так что эти файлы в новом сервисе получают больший приоритет, чем существующие в этом каталоге файлы. Эта процедура делает новые файлы cons, mouse и т.п., доступными в /dev, выполняя скрытие файлов с одинаковыми именами. Аргумент buf — это символьная строка (нулевая в нашем случае), описываемая ниже.

Клиентский процесс затем закрывает файловые дескрипторы 0, 1 и 2 и многократно открывает /dev/cons для соединения стандартных файлов ввода, вывода и ошибок с оконным /dev/cons. Для начала выполнения оболочки в окне применяется системный вызов exec. Вся последовательность, вместе с обработкой ошибок, составляет 33 строки кода на С.

Вид этих событий из конца канала 8½ представляет собой последовательность сообщений файлового протокола от нового клиента. Последовательность генерируется операционной системы в ответ на системные вызовы mount и open, которые выполнил клиент. Сообщение, сгенерированное mount, информирует 8½ о том, что новый клиент подключился к файловому сервису, который она представляет; ответ 8½ — это уникальный идентификатор, который охраняется операционной системой и передается со всеми сообщениями, сгенерированными вводом-выводом происходящих от этого mount файлов. Этот идентификатор используется 8½ для различия клиентов, каждый из которых видит уникальный /dev/cons; большинству серверов не требуется делать эти различия.

Процесс, не имеющий отношения к 8½, для создания окон должен использовать именно этот вариант механизма. Когда запускается 8½, она использует сервис Plan 9 чтобы «отправить» клиентский конец соединительного канала в общественное место. Процесс должен открыть этот канал и подмонтировать его к подключению оконной системы, во время этого пути X клиент должен соединиться с Unix доменным сокетом сервера, связанного с файловой системой. Последний аргумент mount посылается операционной системой как не интерпретированный. Он делает возможным обмен информацией между клиентом и сервером во время монтирования. 8½ интерпретирует этот аргумент как размеры окна, которое будет создано для нового клиента. (В описанном выше случае, окно будет создано за время вызова mount, при этом buf не будет нести никакую информацию.) Когда происходит возврат mount, процесс может открывать файлы нового окна и начинать ввод-вывод для его использования.

Так как интерфейс 8½ основан на файлах, для управления им могут использоваться стандартные системные утилиты. К примеру, способ создания окон внешне упакован в 16-строчный сценарий оболочки под названием window, основа которого — простая операция монтирования, которая приписывает каталог 8½ к /dev и запускает команду, введенную в строке аргументов:

mount -b $'8½serv' /dev$* < /dev/cons > /dev/cons >[2] /dev/cons &

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

Page 58:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

возможности.

Другие основные характеристики системы естественно выпадают из файловоподобной модели. Когда пользователь удаляет окно, 8½ отправляет эквивалент Unix сигнала группе процессов (клиентам в окне), удаляет окно с экрана и обрубает входящие соединения к файлу, который управлял им. Если клиент игнорирует сигнал и продолжает запись в окно, он начнет получать ошибки ввода-вывода. Если, с другой стороны, все процессы в окне спонтанно завершат свою работу, они автоматически закроют все соединения с окном. 8½ выполняет счет количества ссылок на файлы окна; когда ссылок нет, она закрывает окно и удаляет его с экрана. Другой пример, когда пользователь нажимает клавишу DEL для генерации прерывания, 8½ записывает сообщение в специальный файл, обеспечиваемый интерфейсом управления процессами Plan 9, который и прерывает выполнение всех процессов в окне. Все эти примеры работают совершенно аналогично через сеть.

Реализация оконной системы посредством мультиплексирования /dev/cons и других подобных файлов дает два ценных эффекта. Первый, автоматически решается проблема подачи значимой интерпретации файлу /dev/cons (/dev/tty) в каждом окне. Обеспечение /dev/cons — это основное задание оконной системы, а не тяжелое бремя; чтобы вести себя предсказуемо в окне другие системы должны часто делать специальные организации для /dev/tty. Второй, любая программа может получить доступ к серверу, включая процесс на удаленной машине, и к файлам, используя стандартные системные вызовы read и write для общения с оконной системой, и стандартные вызовы open и close для подключения к ним. Чтобы сделать возможным использование всех графических особенностей 8½, не требуется никаких специальных организаций для удаленных процессов.

Графический ввод

Безусловно, 8½ представляет клиентам нечто большее, чем просто ASCII ввод-вывод. Состояние мыши можно узнать, прочитав файл /dev/mouse, который возвращает десяти байтовое кодированное сообщение состояния кнопок и позиции курсора. Если с момента последнего чтения /dev/mouse мышь не передвигалась или же, если окно, ассоциированное с примером /dev/mouse, не находится в «фокусе ввода», то проводится чтение блоков.

Формат сообщения таков:

'm'1 байт для состояния кнопки4 байта для x, сначала младший байт4 байта для y, сначала младший байт

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

Для клавиатурного ввода, клиенты могут читать /dev/cons или же, если им нужен символ-за-один-раз ввода, /dev/rcons (raw console). Нет явного механизма помощи клиентам при чтении из многочисленных источников. Взамен, может использоваться небольшая (365 строк) внешняя библиотека поддержки. Она подключает процесс к различным блокирующим источникам ввода — к мыши, клавиатуре, и, возможно, третьему пользовательскому файловому дескриптору — и суммирует их ввод в один канал, из которого могут считываться разные типы событий в традиционном стиле. Этот пакет является побочным. Как обсуждалось в предыдущем документе [10], я предпочитаю освобождать приложения от программирования, основанного на событиях. К сожалению, я не вижу легче путь для достижения этого в одно-потоковых программах на C, и я не склонен требовать от всех программистов овладевать параллельным программированием. (Смотрите программу-

Page 59:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

пример в конце документа.)

Графический вывод

Файл /dev/screen может быть прочитан любым клиентом для получения изображения всего экрана, например для печати (см. Рис. 1). Аналогично, /dev/window хранит содержимое текущего окна. Эти файлы только для чтения.

Рис. 1. Здесь показан экран 8½, запущенной на NeXTstation в Plan 9 (без ПО NeXT). Справа вверху находится программа, анонсирующая поступающую почту. По середине и слева — броузер для астрономических баз данных и созданное им изображение галактики. Снизу слева находится экранный редактор sam [8], в котором выполняется редактирование японского текста в кодировке UTF, и наконец, снизу справа — запущенная рекурсивно 8½, внутри которой просмотрщик вывода troff. Под faces в маленьком окне запущена команда, которая сохраняет изображение экрана путем передачи /dev/screen утилите растрового вывода.

Для выполнения графических операций в окнах, клиентские программы имеют доступ к /dev/bitblt. Он реализует протокол, кодирующий операции с растровой графикой. Большая часть сообщений в протоколе (всего их 23, половина из которых отвечает за управление многоуровневыми шрифтами для эффективной обработки символов Unicode) передается (посредством записи) от клиента к оконной системе для выполнения графической операции типа bitblt [14] или, скажем, прорисовки символа; несколько сообщений

Page 60:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

содержат информацию, возвращаемую клиенту (посредством чтения). Также как и в /dev/mouse, протокол /dev/bitblt имеет определенный порядок байт. Например, вот формат сообщения bitblt:

'b'2 байта для идентификатора назначения2x4 байт для места назначения2 байта для идентификатора источника4x4 байт для исходного прямоугольника2 байта для кода логической функции

Сообщение, тривиально созданное из bitblt подпрограммы в библиотеке, выглядит так:

void bitblt(Bitmap *dst, Point dp, Bitmap *src, Rectangle sr, Fcode c).

Поля «идентификатора» в сообщении указывают на другую особенность 8½: клиенты не хранят локально фактические данные для любых своих растров. Взамен, для распределения растра протокол обеспечивает сообщение, сохраняемое на сервере, и возвращает клиенту идентификатор целого типа (это схоже с файловыми дескрипторами Unix), который будет использоваться в операциях над этим растром. Число растра 0 обычно является клиентским окном, аналогично к стандартному вводу для файла ввода-вывода. Фактически, на клиентской машине не выполняется никаких операций с растровой графикой, все они выполняются на стороне сервера. Опять же, использование стандартных операций над удаленным файлом в Plan 9 позволяет работать без графических возможностей на машинах, таких как CPU сервер. Аналогичные характеристики в оконной системы Andrew [3] и X [17] требуют более сложных механизмов.

8½ не может сама работать непосредственно на растрах. Взамен, чтобы выполнить графические операции, она вызывает другой сервер, используя идентичный протокол. Операционная система для терминалов содержит внутренний сервер, реализующий схожий с 8½ протокол, но лишь для одного клиента. Этот сервер сохраняет фактические байты для растров и реализует основные операции с растровой графикой. Таким образом, среда, в которой запускается 8½, имеет структуру, идентичную обеспечиваемой ею клиентам; 8½ воспроизводит среду для своих клиентов, мультиплексируя интерфейс для поддержки раздельности клиентов.

Безусловно, этот способ мультиплексирования путем имитации может применяться не только в оконных системах, он также имеет некоторые сторонние эффекты. Поскольку 8½ имитирует свою собственную среду для клиентов, она может быть запущена в одном из своих окон (см. Рис. 1). Полезное и общее приложение, построенное по этой технологии, — соединение окна с удаленной машиной, такой как CPU сервер, а затем запуск оконной системы там, чтобы каждое подокно автоматически появлялось на удаленной машине. Это также удобный способ для отладки новой версии оконной системы или создания среды, например, с другим шрифтом по-умолчанию.

Реализация

Для представления графики клиентам 8½, по большей части, лишь мультиплексирует и передает через свой собственный сервер запросы клиентов. Она редко перестраивает сообщения для поддержки вымысла, что у клиентов уникальные экраны (окна). Для управления перекрывающимися окнами она использует модель слоев, которая обрабатывается отдельной библиотекой [7]. Таким образом, 8½ остается совсем мало работы и она достаточно простая программа; ею командуют несколько операторов переключения для интерпретации растра и протоколов файлового сервера. Встроенная оконная программа вместе с ассоциированными с ней меню и поддержкой текстового управления отвечают за

Page 61:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

большую часть кода.

Сервер операционной системы также компактен: версия для процессора 68020 без реализации полдюжины операций над растровой графикой — 2295 строк кода на С (опять, половина из которых отвечает за работу со шрифтами); графические операции — еще 2214 строк.

8½ структурирована как множество связанных сопрограмм, большинство из которых описано в документе 1989 года [10]. Одна сопрограмма управляет мышью, другая — клавиатурой, еще одна отвечает за управление состоянием каждого окна и ассоциированного с ним клиента. Когда не требуется запуск сопрограммы, 8½ читает следующий файловый запрос ввода-вывода, который приходит периодически по полнодуплексному соединительному каналу. Таким образом, 8½ полностью синхронна.

Исходный код программы не велик и компилируется за 10 секунд в нашей среде Plan 9. Все десять исходных файлов и один makefile составляют 5100 строк. Включается исходный код процесса оконного управления, терминальная программа вырезать-и-вставить, сам сервер окно/файл, и небольшая библиотека сопрограмм (proc.c). В программу не входит ни библиотека слоев (еще 1031 строка), ни библиотека управления вырезкой и вставкой текста, отображаемого в окне (960 строк), ни общая библиотека поддержки графики, которая управляет всеми не рисованными аспектами графики — арифметика с точками и прямоугольниками, управление памятью/ошибками, клиппинг, — плюс шрифты, события, и операции не примитивного рисования, такие как окружности и эллипсы (финальные 3051 строка). Сама 8½ не использует все части этих библиотек; в частности, большая часть графической библиотеки используется клиентами. Таким образом, несколько некорректно суммировать все эти числа, включая 4509 строк поддержки в ядре, и прийти к общему размеру реализации 8½ в 14651 строку. Это исходный код для разработки всей оконной системы 8½, от самых нижних уровней — до самых высоких.

Также важна реализация. Производительность 8½ конкурентоспособна системе X Window. По сравнению с использованием закладок gbench Dunwoody и Linton на 68020, распространяемых с «X Test Suite», скорость прорисовки окружностей и арок примерно одинакова с 8½, также как и с 4-й версией X11, скомпилированной при помощи gcc на эквивалентном оборудовании (возможно, потому что они реализованы вызовами примитивов point в пользовательской библиотеке). Скорость прорисовки линий примерно одинакова между двумя системами. Скорость прорисовки текста в кодировке Unicode в 8½ одинакова с текстом ASCII в Х, а тест bitblt в четыре раза быстрее для 8½. Эти результаты показывают, что архитектура 8½ является удачной и ни о каком уменьшении производительности не может быть и речи. И напоследок, загрузка 8½ выполняется за секунду, а создание нового окна почти мгновенное.

Пример

Здесь приведен пример полной программы, запускаемой в 8½. Она выводит строку «hello world» в место нажатия левой кнопки мыши, и завершает свою работу, если нажата правая кнопка мыши. Она также выводит строку в центре окна и управляет ею при изменении размера окна.

#include <u.h>#include <libc.h>#include <libg.h>

voidereshaped(Rectangle r){ Point p;

Page 62:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

screen.r = r; bitblt(&screen, screen.r.min, &screen, r, Zero); /* чисто */ p.x = screen.r.min.x + Dx(screen.r)/2; p.y = screen.r.min.y + Dy(screen.r)/2; p = sub(p, div(strsize(font, "hello world"), 2)); string(&screen, p, font, "hello world", S);}

main(void){ Mouse m;

binit(0, 0, 0); /* инициализация графической библиотеки */ einit(Emouse); /* инициализация библиотеки событий */ ereshaped(screen.r); for(;;){ m = emouse(); if(m.buttons & RIGHTB) break; if(m.buttons & LEFTB){ string(&screen, m.xy, font, "hello world", S); /* ожидание нажатия кнопки */ do; while(emouse().buttons & LEFTB); } }}

Полностью загруженный двоичный файл занимает 26 KB памяти на 68020. Эта программа может быть объединена с ей подобными в великолепном документе Роузенталя (David Rosenthal) [16]. (Текущая программа делает больше: в ней также применяется мышь.) Неуклюжей частью кода является функция ereshaped, которая вызывается из библиотеки событий, если окно изменяет форму или перемещается. (Простые, так называемые, незащищенные события не являются событиями в 8½; за них отвечает библиотека слоев.) Урок этой программы, со ссылкой на Роузенталя, в том, что если оконная система хорошо спроектирована, toolkit необязателен для простых задач.

Статус

1992 год, 8½ ежедневно используется почти всеми 60 членами нашего исследовательского центра. Одни используют ее для доступа к Plan 9, другие как вход для удаленных Unix систем.

Скоро в 8½ произойдут изменения. Неплохой является идея расширения возможностей работы оконной системы с оболочкой. Аналогичный этому документу [11] предлагает один метод решения, но в нем приходится забыть о графической функциональности. Возможно, текстовая версия файла /dev/bitblt могла бы увеличить характеристики системы, к примеру, это дало бы возможность awk программам непосредственно рисовать графы.

Может ли этот стиль оконной системы быть создан на другой операционной системе? Основная часть конструкции 8½ зависит от ее структуры как файлового сервера. В принципе, это можно сделать для любой системы, поддерживающей пользовательские процессы, которые хранятся в файлах. Это могут быть системы, запускающие файловые системы NFS или AFS [18, 4]. Тем не менее, есть одно требование, 8½ нужно отвечать на клиентские запросы по порядку: если один клиент читает /dev/cons в окне без считываемых символов, другие клиенты должны иметь возможность выполнять ввод-вывод в их окнах, или даже в одном окне. Другое ограничение в том, что файлы 8½ схожи с устройствами и должны кешироваться клиентом. NFS не может выполнить эти требования; то же самое с AFS. Конечно, есть и другие механизмы межпроцессовой связи, например, сокеты, они могут

Page 63:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

использоваться как основа для оконной системы.

Выводы

В оконной системе 8½ используется необычная архитектура вместе с файловоподобной межпроцессовой связью Plan 9 для обеспечения сетеоснованной интерактивной графики клиентским программам. Она продемонстрировала, что даже коммерческие оконные системы, в сущности, не являются большими и сложными и могут легко использоваться и программироваться.

Благодарности

Полезными комментариями ранних черновиков этого документа обеспечили: Дуг Блиуэтт (Doug Blewett), Стью Филдман (Stu Feldman), Брайан Керниган (Brian Kernighan), Деннис Ритчи (Dennis Ritchie) и Фил Уинтерботтом (Phil Winterbottom). Поддержка цвета в 8½ была добавлена Говардом Трики (Howard Trickey). Много идей, пришедших в 8½, были сначала проверены в ранних, иногда менее удачных, разработках. Я хочу поблагодарить тех пользователей, которые выстрадали в каких-нибудь моих предыдущих 7½ оконных системах.

Литература

[1] Tom Duff, Rc - A Shell for Plan 9 and UNIX systems, Proc. of the Summer 1990 UKUUG Conf., London, July, 1990, pp. 21-33, reprinted, in a different form, in this volume. [2] Far too many people, XTERM(1), Massachusetts Institute of Technology, 1989. [3] James Gosling and David Rosenthal, A window manager for bitmapped displays and UNIX, in Methodology of Window Management, edited by F.R.A. Hopgood et al., Springer, 1986. [4] Mike Kazar, Synchronization and Caching issues in the Andrew File System, Tech. Rept. CMU-ITC-058, Information Technology Center, Carnegie Mellon University, June, 1987. [5] Tom Killian, Processes as Files, USENIX Summer Conf. Proc., Salt Lake City June, 1984. [6] Rob Pike, The Blit: A Multiplexed Graphics Terminal, Bell Labs Tech. J., V63, #8, part 2, pp. 1607-1631. [7] Rob Pike, Graphics in Overlapping Bitmap Layers, Trans. on Graph., Vol 2, #2, 135-160, reprinted in Proc. SIGGRAPH '83, pp. 331-356. [8] Rob Pike, The Text Editor sam, Softw. - Prac. and Exp., Nov 1987, Vol 17 #11, pp. 813-845, reprinted in this volume. [9] Rob Pike, Window Systems Should Be Transparent, Comp. Sys., Summer 1988, Vol 1 #3, pp. 279-296. [10] Rob Pike, A Concurrent Window System, Comp. Sys., Spring 1989, Vol 2 #2, pp. 133-153. [11] Rob Pike, A Minimalist Global User Interface, USENIX Summer Conf. Proc., Nashville, June, 1991. [12] Rob Pike, Dave Presotto, Ken Thompson, Howard Trickey, and Phil Winterbottom, Operating Systems Review Vol 27, #2, Apr 1993, pp. 72-76 (reprinted from Proceedings of the 5th ACM SIGOPS European Workshop, Mont Saint-Michel, 1992, Paper n? 34, and reprinted in this volume).

[13] Rob Pike and Ken Thompson, Hello World or ?ALPHA??MU??ALPHA ???MUEPSILON or ????? ??, USENIX Winter Conf. Proc., San Diego, Jan, 1993, reprinted in this volume. [14] Rob Pike, Bart Locanthi and John Reiser, Hardware/Software Tradeoffs for Bitmap Graphics on the Blit, Softw. - Prac. and Exp., Feb 1985, Vol 15 #2, pp. 131-152. [15] David L. Presotto and Dennis M. Ritchie, Interprocess Communication in the Ninth Edition Unix System, Softw. - Prac. and Exp., June 1990, Vol 20 #S1, pp. S1/3-S1/17. [16] David Rosenthal, A Simple X11 Client Program -or- How hard can it really be to write Hello, World?, USENIX Winter Conf. Proc., Dallas, Jan, 1988, pp. 229-242. [17] Robert W. Scheifler and Jim Gettys, The X Window System, ACM Trans. on Graph., Vol 5 #2,

Page 64:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

pp. 79-109. [18] Sun Microsystems, NFS: Network file system protocol specification, RFC 1094, Network Information Center, SRI International, March, 1989.

Copyright © 2000 Lucent Technologies Inc. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Page 65:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Rc - оболочка Plan 9Том Дафф[email protected]

АБСТРАКТНО Rc — это командный интерпретатор Plan 9, который обеспечивает средства, подобные к UNIX Bourne shell, но с небольшими дополнениями и менее идиосинкразтичным* синтаксисом. В настоящем документе используются многочисленные примеры для описания характеристик rc, контрасты rc и Bourne shell, модели которых многие пользователи считают подобными.

1 Введение

Rc аналогичен по духу, но различен в деталях с UNIX Bourne shell. В этом документе рассматриваются главные характеристики rc с множеством примеров, которые показывают его схожесть с Bourne shell.

2 Простые команды

В наиболее простом использовании синтаксис rc во многом схож с Bourne shell. Все нижеследующие команды в rc ведут себя весьма предсказуемо:

datecat /lib/news/buildwho >user.nameswho >>user.nameswc <fileecho [a-f]*.cwho | wcwho; datevc *.c &mk && v.out /*/bin/fb/*rm -r junk || echo rm failed!

3 Кавычки

Для работы с файлами, имена которых содержат пробелы и(или) специальные символы, нужно использовать одинарные кавычки ('):

rm 'odd file name'

В случае, если аргумент команды содержит собственную кавычку, она должна быть удвоена:

echo 'How''s your father?'

4 Метасимволы

Метасимволы в именах файлов могут заменять любой символ или группу символов, избавляя пользователя от необходимости набирать длинное имя файла или длинную цепочку команд, они позволяют ему вводить только части имен, а остальное заменять метасимволами. Аргумент без кавычек, содержащий символы * ? [, является метасимволом и используется в оболочке для сокращения имен файлов. Символ * соответствует любым последовательностям символов, ? соответствует одному символу, и [класс] соответствует любому из класса символов, перечисленных в скобках, если первый символ класса не ~, то

Page 66:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

класс дополняется. Класс также может содержать пары символов, разделенные минусом -, представляя этим соответствующий диапазон. Символ / должен явно указываться в метасимволе также как компоненты путевого имени . и ...

5 Переменные

В UNIX Bourne shell используются строковые переменные среды. В rc используются переменные, чьи значения являются списками аргументов, то есть массивами строк. Это является главным различием между rc и традиционными командными интерпретаторами UNIX. Переменным должны присваиваться значения, например:

path=(. /bin)user=tdfont=/lib/font/bit/pelm/ascii.9.font

Круглые скобки указывают на то, что значение переменной среды path является списком из двух строк. Переменным user и font назначены списки, содержащие по одной строке.

Чтобы определить значение какой-либо переменной, воспользуйтесь командой echo, указав в качестве аргумента имя, предваренное символом $ (который указывает интерпретатору rc, что имя переменной нужно заменить ее значением):

echo $path

Если переменная path была установлена, то эта команда эквивалентна следующей:

echo . /bin

Переменные могут быть индексными числами или списками чисел:

echo $path(2)echo $path(2 1 2)

Что эквивалентно:

echo /binecho /bin . /bin

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

Нумерация строк в переменных может заменяться оператором $#. Например,

echo $#path

выведет числовое значение 2.

Следующие два присваивания не одинаковы:

empty=()null=''

Первое присваивает переменной empty пустой список, второе же присваивает переменной null список, содержащий одну без символьную строку. Хотя на первый взгляд может показаться, что они одинаковые (для Bourne shell они неразличимы), но это только на первый взгляд, они ведут себя по-разному почти во всех случаях. Команда

echo $#empty

выводит 0, в свою очередь,

Page 67:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

echo $#null

выводит 1.

Все неустановленные переменные (то есть которым не присвоены значения) имеют по умолчанию значение (). Это свойство полезно при рассмотрении значения переменной как единственной строки. С помощью оператора $" элементы строки конкатенируются в единственную строку, с пробелами, разделяющими элементы. Таким образом, если мы присваиваем:

list=(How now brown cow)string=$"list

то обе команды

echo $list

и

echo $string

будут иметь одинаковый вывод:

How now brown cow

но

echo $#list $#string

выведет

4 1

поскольку переменная $list содержит 4 элемента, а $string — 1.

6 Аргументы

Когда rc читает свой стандартный ввод из файла, то файл, в свою очередь, получает доступ к аргументам командной строки rc. Переменная $* первоначально содержит список аргументов, присвоенных ей. Имена $1, $2, .. , являются синонимами для $*(1), $*(2), .. . Кроме того, $0 — имя файла, из которого читается стандартный ввод rc.

7 Конкатенация

Rc содержит оператор конкатенации строк, символ ^, для составления аргументов из частей.

echo hully^gully

эквивалентна

echo hullygully

Допустим, что некоторая переменная i содержит имя команды, тогда

vc $i^.cvl -o $1 $i^.v

скомпилирует исходный код этой команды, оставив результат выполнения в соответствующем файле.

Операция конкатенации распространяется также и на списки. Нижеследующие строки

Page 68:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

echo (a b c)^(1 2 3)src=(main subr io)cc $src^.c

эквивалентны

echo a1 b2 c3cc main.c subr.c io.c

В деталях, правило звучит так: если оба операнда ^ — списки одного и того же не равного нулю количества строк, то они конкатенируются попарно. Если же один из операндов — единственная строка, то она конкатенируется с каждым членом другого операнда. Любая другая комбинация операндов является ошибочной.

8 Свободные символы

Чтобы сделать синтаксис rc более схожим с Bourne shell, символы должны находится только в строго определенных местах. Например,

cc -$flags $stems.c

эквивалентна

cc -^$flags $stems^.c

В общих чертах, rc вставляет символ ^ между двумя аргументами, которые не разделяются интервалом. (Вдумайтесь в следующее предложение :) — прим. пер.) Всякий раз, когда один из символов $'` следует за словом в кавычках или без них, или слово без кавычек следует за словом в кавычках, без интервальных пробелов или символов табуляции, то подразумевающийся символ ^ вставляется между ними двумя. Если слово без кавычек следует за символом $ и содержит не печатаемые символы, тогда перед первым таким символом вставляется * или ^.

9 Командная подстановка

Часто бывает полезно использовать подстановку результатов выполнения команды как аргумент командной строки. Rc допускает команды, заключенные в скобки и следующие за левой кавычкой `{...} везде, где требуется аргумент. Команда выполняется и ее стандартный вывод захватывается, символы, сохраненные в переменном ifs используются для разделения вывода на аргументы. К примеру,

cat `{ls -tr|sed 10q}

выводит десять имен самых старых файлов из текущего каталога на стандартный вывод.

10 Конвейерная обработка

Нормальная конвейерная обработка является общим средством для решения многих задач. Очень редко используются не линейные конвейеры. Синтаксис rc поддерживает некоторые типы не линейных, но дерево-подобных конвейеров. К примеру, строка

cmp <{old} <{new}

является регрессией-тестом для новой версии команды. Символ < или > следует перед именем команды и заставляет ее запускаться с использованием, соответственно, ввода или вывода аргументов в скобках, указанных в канале.

Page 69:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

11 Код завершения процесса

Когда команда завершается, она может возвратить числовой код своего состояния программе, которая ее вызвала (запустила). По коду состояния вызывающий процесс определяет успешность завершения выполнения команды. В Plan 9 состояние процесса является символьной строкой, описывающей условие ошибки. При нормальном завершении команды эта строка пуста.

Rc сохраняет код завершения команды в переменном $status. Для простой команды, значение $status — такое же, как описано выше. Для конвейера, $status является набором конкатенаций состояний конвейерных компонент с разделяющими их символами |.

Rc имеет несколько типов управления потоками, многие из которых обусловлены состоянием последней завершенной команды. Любая переменная $status, содержащая только нули и символы | имеет логическое (булевое) значение true, любые другие символы — false.

12 Командное группирование

Последовательность команд, заключенная в скобки {}, может использоваться везде, где требуется команде. К примеру, выполнение строки:

{sleep 3600;echo 'Time''s up!'}&

заставляет интерпретатор перейти в состояние ожидания на один час в фоновом режиме, затем выводится сообщение. Без скобок:

sleep 3600;echo 'Time''s up!'&

на один час блокирует терминал, затем в фоновом режиме выводит сообщение.

13 Управляющая конструкция for

Команда может быть выполнена один раз для каждого члена списка, примерно вот так:

for(i in printf scanf putchar) look $i /usr/td/lib/dw.dat

Эта команда просматривает каждое из слов printf, scanf и putchar в данном файле. Общая форма

for(имя in список) команда

или

for(имя) команда

В первом случае команда выполняется один раз для каждого члена из списка вместе с членом, присвоенным переменной имя. Если часть ``in список'' отсутствует, то по умолчанию принимается как ``in $*''.

14 Условная конструкция if

Rc поддерживает общий if-оператор. Например:

for(i in *.c) if(cpp $i >/tmp/$i) vc /tmp/$i

запускает компилятор C для каждой исходной программы, которую программа cpp обработала без ошибок. Оператор `if not' обеспечивается двойным разветвленным условием:

for(i){ if(test -f /tmp/$i) echo $i already in /tmp

Page 70:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

if not cp $i /tmp}

Здесь выполняется цикл над каждым файлом из $*, то есть в каталог /tmp копируются те файлы, которые уже прошли цикл, а сообщение выводится для тех, которые еще в цикле.

15 Управляющая конструкция while

В rc работу оператора while можно рассмотреть на примере:

while(newer subr.v subr.c) sleep 5

Здесь проверяется завершение работы компилятора C, при этом происходит ожидание до тех пор, пока файл subr.v не станет новей, чем subr.c.

Если управляющая конструкция команды — пуста, то работа цикла не завершается. Таким образом,

while() echo y

эмулирует UNIX команду yes.

16 Управляющая конструкция switch

Для сравнения строк в rc предусмотрен оператор switch. Общая форма

switch(выражение){case шаблон ... командыcase шаблон ... команды...}

Оператор switch последовательно сравнивает выражение с шаблонами каждого case оператора очереди. Шаблоны могут содержать имена файлов, так что они не должны содержать явно указанные символы /, . и ...

Если шаблон соответствует выражению, то выполняются команды, следующие за этим оператором до следующего case (или конца оператора switch), после этого происходит завершение работы всего switсh оператора. К примеру,

switch($#*){case 1 cat >>$1case 2 cat >>$2 <$1case * echo 'Usage: append [from] to'}

команда добавления (append). Вызванная с одним аргументом, — именем файла, она добавляет свой стандартный вывод в указанный файл. С двумя аргументами — содержимое первого файла добавляется во второй файл. Любая другая комбинация выводит сообщение об ошибке.

Встроенная команда ~ также соответствует шаблонам и часто она более краткая, чем switch. Ее аргументами являются строка и список шаблонов. Она устанавливает значение true переменной $status если хоть один из шаблонов соответствует строке. Следующий пример

Page 71:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

обрабатывает аргументы выбора для системной команды man(1):

opt=()while(~ $1 -* [1-9] 10){ switch($1){ case [1-9] 10 sec=$1 secn=$1 case -f c=f s=f case -[qwnt] cmd=$1 case -T* T=$1 case -* opt=($opt $1) } shift}

17 Функции

Функции rc описываются в таком виде:

fn название { команды }

Всякий раз, когда встречается имя команды, соответствующее названию функции, остатком аргумента назначается $* и rc выполняет соответствующие команды функции. Значение $* восстанавливается после завершения команд функции. Например,

fn g { grep $1 *.[hcyl]}

определяет некий шаблон и поиск соответствий этого шаблона в исходных файлах текущего каталога.

Функция удаляется посредством выполнения команды

fn название

без тела функции.

18 Выполнение команд

В Plan 9 функция, определенная посредством fn, имеет больший приоритет выполнения, чем простая, не встроенная команда. (О встроенных командах читайте ниже пункт 19.) То есть, если имя команды является названием функции, то выполняется соответствующая функция. Если же имя является встроенной командой, то она выполняется непосредственно в rc. В противном случае, в каталогах, указанных в переменной $path производится поиск этого исполняемого файла. Расширенное использование переменной $path не приветствуется в Plan 9. Взамен, используются каталоги по умолчанию (. /bin).

19 Встроенные команды

Несколько команд, выполняемых непосредственно в rc:

. [-i] файл ... Выполняет команды из файла. Переменная $* устанавливается для длительности напоминания о списке аргументов, следующих за файлом. $path используется для

Page 72:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

поиска файла. Опция -i указывает диалоговый ввод — приглашение (значение переменной $prompt) выводится перед чтением каждой команды.

builtin команда ... Выполняет команду как стандартную, за исключением того, что любая функция, имеющая эквивалентное имя, будет проигнорирована. К примеру, функция

fn cd{ builtin cd $* && pwd}

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

cd [каталог] Производит смену текущего каталога на указанный в аргументе. Аргумент по умолчанию — значение из переменной $home. $cdpath является последним аргументом поиска каталога.

eval [аргументы ...] Все аргументы конкатенируются (разделенные пробелами) в строку, читаются как стандартный ввод для rc, и выполняются. Например,

x='$y'y=Doodyeval echo Howdy, $x

выведет

Howdy, Doody

так как аргументами eval должны быть

echo Howdy, $y

после замены для $x. exec [команда ...]

Rc заменяет себя данной командой. Это схоже с goto, rc не ожидает завершения команды и не возвращается для чтения других команд.

exit [состояние] Rc немедленно производит выход с указанным состоянием. Если состояние не указано, то используется значение переменной $status.

flag f [+-] Эта команда выполняет манипулирование и тестирование флагов командной строки (описанных ниже).

flag f +

устанавливает флаг f.

flag f -

очищает флаг f.

flag f

Page 73:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

тестирует флаг f, устанавливая соответственно переменную $status. Таким образом

if(flag x) flag v +

устанавливает флаг -v, если флаг -x уже установлен. rfork [nNeEsfF]

Использует вход системы rfork Plan 9 для установки rc в новую группу процессов со следующими атрибутами: Флаг Название Функцияn RFNAMEG Создать копию родительского пространства имен

N RFCNAMEG Начать с нового, пустого пространства имен

e RFENVG Создать копию родительской среды

E RFCENVG Начать с новой, пустой среды

s RFNOTEG Создать новую группу примечаний

f RFFDG Создать копию родительского пространства файловых дескрипторов

F RFCFDG Создать новое, пустое пространство файловых дескрипторовСтраница fork (2) руководства программиста (Programmer's Manual) описывает эти атрибуты более детально.

shift [n] Удаляет первые n (по умолчанию 1) элементов из $*.

wait [pid] Ожидает процесс, идентификатор которого указан, для выхода. Если идентификатор процесса pid не указан, то ожидают все процессы.

whatis имя ... Выводит значение каждого имени в пригодной форме для ввода rc. Вывод является назначением переменной, определение функции, вызов builtin для встроенной команды, или путевое имя исполняемой программы. Например, строка

whatis path g cd who

должна вывести

path=(. /bin)fn g {gre -e $1 *.[hycl]}builtin cd/bin/who

~ предмет шаблон ... Предмет соответствует каждому шаблону из очереди. Если есть соответствие, $status устанавливается как true. В противном случае, он устанавливается как 'no match'. Шаблоны могут соответствовать именам файлов. Шаблоны не могут соответствовать именам файлов перед выполнением команды ~, так что они не должны заключаться в кавычки, если же используются специальные символы *, [ или ?, тогда кавычки необходимы. К примеру,

~ $1 ?

соответствует любому единичному символу, в свою очередь

~ $1 '?'

Page 74:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

только буквальному знаку вопроса.

20 Представление переадресации ввода-вывода

Rc допускает переадресацию файловых дескрипторов 0 и 1 (стандартные ввод и вывод), заключая файловый дескриптор в квадратные скобки [ ] после символов < или >. Например,

vc junk.c >[2]junk.diag

сохраняет диагностику компилятора из стандартного потока ошибок в файле junk.diag.

Файловый дескриптор может заменяться копией уже открытого файла, в значении dup(2), например,

vc junk.c >[2=1]

Заменяет файловый дескриптор 2 файловым дескриптором 1. Это более полезно при использовании вместе с переадресациями, вот так:

vc junk.c >junk.out >[2=1]

Переадресации оцениваются слева-направо, так что эта строка переадресует файловый дескриптор 1 на файл junk.out, затем указывает файловому дескриптору этот же файл. Команда

vc junk.c >[2=1] >junk.out

переадресует файловый дескриптор 2 на копию файлового дескриптора 1 (возможно, терминал), а затем адресует файловый дескриптор 1 на файл. В первом случае стандартный и диагностический выводы попадают в junk.out. Во втором, диагностический вывод появляется на терминале, а стандартный вывод направляется в файл.

Файловые дескрипторы могут закрываться с использованием дублированной нотации с пустой правой стороной. Например,

vc junk.c >[2=]

отвергает сообщения диагностики из компиляции.

Произвольные файловые дескрипторы могут посылаться через канал, например,

vc junk.c |[2] grep -v '^$'

Удаляет пустые строки из вывода ошибок компилятора C. Имейте в виду, что вывод grep все еще появляется в файловом дескрипторе 1.

Если вы хотите подключить сторону вывода канала к некоторому файловому дескриптору кроме нуля, команда

cmd1 |[5=19] cmd2

создает конвейер с файловым дескриптором 5 (cmd1), соединенным посредством канала с файловым дескриптором 19 (cmd2).

21 Документ здесь

Оболочка rc поддерживает конструкцию, называемую ``документ здесь'', она удобна если нужно прочесть какие-либо данные со стандартного ввода и поместить их прямо в сценарий,

Page 75:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

но создавать файл для приема нежелательно. Она схожа с версией команды tel.

for(i) grep $i <<!...tor 2T-402 2912kevin 2C-514 2842bill 2C-562 7214...!

Конструкция ``документ здесь'' использует оператор <<, после которого следует маркер EOF (в данном примере это !). Строки, следующие за командой, вплоть до строки, содержащей только маркер EOF, сохраняются во временном файле, который подключается к командному стандартному вводу при запуске.

Rc производит подстановку переменных в документах здесь. Следующая команда:

ed $3 <<EOFg/$1/s//$2/gwEOF

заменяет все случаи $1 на $2 в файле $3. Чтобы вставить символ $ в документ здесь, введите $$. Если имя переменной сопровождается символом ^, он удаляется.

Подстановка переменных может полностью подавляться закрытием маркера EOF (следующего за оператором <<) в кавычки, как здесь <<'EOF'.

Документы здесь могут обеспечиваться в файловых дескрипторах, кроме 0, вот так

cmd <<[4]End...End

Если здесь документ появляется в пределах сложного блока, содержимое документа должно следовать после всего блока:

for(i in $*){ mail $i <<EOF}words to live byEOF

22 Кэширование сообщений

Сценарии rc нормально завершают свою работу, если они получают прерывание от терминала. Функция с именем UNIX сигнала, в верхнем регистре, определяется в обычном виде, но посылается когда rc получает соответствующее сообщение. Страница руководства программиста, посвященная notify(2), описывает сообщения в деталях. Вот некоторые из этих сообщений:

sighup Сообщение имело название `hangup', Plan 9 посылает его, когда терминал отключается от rc.

sigint Сообщение имело название `interrupt', обычно посылается, когда символ прерывания (ASCII DEL) набран в терминале.

sigterm Сообщение имело название `kill', нормально посылается командой kill (1).

Page 76:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

sigexit Искусственное сообщение, когда rc собирается завершить роботу.

Например,

fn sigint{ rm /tmp/junk exit}

перехватывает прерывание с клавиатуры, которое удаляет временный файл перед выходом.

Сообщение будет проигнорировано, если программа сообщения заключена в скобки {}. Сигналы возвращаются в исходное состояние, если их управляющие определения удалены.

23 Среда

Среда — это список пар имя-значение, который делает возможным запуск исполняемых файлов. В Plan 9 среда сохраняется в файловой системе под названием #e, которая монтируется в каталоге /env. Значение каждой переменной сохраняется в отдельном файле с компонентами завершенными нулевыми байтами. (Файловая система полностью поддерживается в ядре ОС, так что ни о каком дисковом или сетевом доступе и речи быть не может.) Содержимое каталога /env разделено между базовыми над-процессовыми группами — когда создается новая группа процессов, она эффективно подключается в /env новой файловой системы, проинициализированную с копией старой группы процессов. Последствием такой организации является то, что команды могут изменять среду данных и просматривать изменения, отраженные в rc.

В среде также появляются функции, к их именам добавляется префикс fn#, как здесь /env/fn#roff.

24 Локальные переменные

Часто бывает необходимо установить длительность одной команды. Следующее за командой назначение делает такой эффект. Например,

a=globala=local echo $aecho $a

выводит

localglobal

Это также работает и в составных командах, подобно

f=/fairly/long/file/name { { wc $f; spell $f; diff $f.old $f } | pr -h 'Facts about '$f | lp -dfn}

25 Примеры cd, pwd

Ниже приводится пара функций, которые обеспечивают расширенные версии стандартных команд cd и pwd. (Спасибо за них Робу Пайку.)

ps1='% ' # приглашение по умолчаниюtab=' ' # символ табуляции

Page 77:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

fn cd{ builtin cd $1 && switch($#*){ case 0 dir=$home prompt=($ps1 $tab) case * switch($1) case /* dir=$1 prompt=(`{basename `{pwd}}^$ps1 $tab) case */* ..* dir=() prompt=(`{basename `{pwd}}^$ps1 $tab) case * dir=() prompt=($1^$ps1 $tab) } }}fn pwd{ if(~ $#dir 0) dir=`{/bin/pwd} echo $dir}

Функция pwd является стандартной версией команды pwd, которая кэширует свое значение в переменную $dir, поскольку истинная pwd может медленно выполняться. (Последние версии Plan 9 содержат очень быстрые реализации pwd, уменьшая преимущества этой pwd функции.)

Функция cd вызывает встроенную команду cd и проверяет успешность ее выполнения. Если выполнение прошло успешно, то устанавливает переменные $dir и $prompt. При этом приглашение будет содержать последнюю часть текущего каталога (кроме домашнего каталога, где она будет равняться нулю), и $dir будет восстановлена или в корректную величину или в (), так что функция pwd будет работать вполне адекватно.

26 Примеры man

Команда man выводит страницы из руководства программиста. Она может быть вызвана таким образом:

man 2 sinhman rcman -t cat

В первом случае, выводится страница руководства из второй секции, посвященная sinh. Во втором случае, страница руководства для rc. Так как руководство разделено на секции, поиск производится во всех секциях, в случае с rc, страница найдена в первой секции. В третьем случае, страница для cat является автонабором (опция -t).

cd /sys/man || { echo $0: No manual! >[1=2] exit 1}NT=n # nroff по умолчаниюs='*' # секция, по умолчанию проверяет всеfor(i) switch($i){case -t NT=t

Page 78:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

case -n NT=ncase -* echo Usage: $0 '[-nt] [section] page ...' >[1=2] exit 1case [1-9] 10 s=$icase * eval 'pages='$s/$i for(page in $pages){ if(test -f $page) $NT^roff -man $page if not echo $0: $i not found >[1=2] }}

Команда eval здесь используется для создания списка возможных man-страниц. Без eval, все соответствия *, сохраненные в переменной $s, не будут соответствовать именам файлов, не заключенных в кавычки. Eval заставляет свои аргументы обрабатываться синтаксическим анализатором и интерпретатором rc, эффективно задерживая оценку *, до назначения переменной $pages.

27 Примеры holmdel

Нижеследующий сценарий rc запускает обманчиво простую игру holmdel, в которой игроки угадывают расположение Bell Labs, победитель первым указывается в Holmdel.

t=/tmp/holmdel$pidfn read{ $1=`{awk '{print;exit}'}}ifs='' # просто новая строкаfn sigexit sigint sigquit sighup{ rm -f $t exit}cat <<'!' >$tAllentown AtlantaCedar CrestChesterColumbusElmhurstFullertonHolmdelIndian HillMerrimack ValleyMorristownNeptunePiscatawayReadingShort HillsSouth PlainfieldSummitWhippanyWest Long Branch!while(){ lab=`{fortune $t}

Page 79:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

echo $lab if(~ $lab Holmdel){ echo You lose. exit } while(read lab; ! grep -i -s $lab $t) echo No such location. if(~ $lab [hH]olmdel){ echo You win. exit }}

Этот сценарий трудно описать в деталях (может быть потому что он такой примитивный).

Переменная $t является аббревиатурой имени временного файла. Включая переменную $pid, проинициализированную rc в свой идентификатор процесса, временные файлы делают так, чтобы их имена не вступали в противоречия, в случаях, когда запущен более чем один пример сценария за раз.

Аргументом функции read является имя переменной, в которую собрана строка из стандартного ввода для чтения. Значение $ifs — новая строка. Поскольку ввод read не разделяется пробелами, завершающая строка удаляется.

Конструктор устанавливается для кэширования сигналов sigint, sigquit, sighup, и искусственного sigexit. Он просто удаляет временные файлы и завершает работу сценария.

Временный файл, содержащий список расположений Bell Labs, инициализируется конструкцией документ здесь и начинает основной цикл.

Сначала программа угадывает расположение (занося его в переменную $lab), используя шуточную программу fortune для выбора произвольной строки из списка расположений. Она выводит расположение, и если это Holmdel, то выводит сообщение о проигрыше и завершает работу.

Затем она использует функцию read, чтобы получить строки из стандартного ввода, проверяет правильность ввода, до тех пор пока не получит правильное расположение. Часть условия while может быть заменена составной командой. Проверке подлежит лишь выходное состояние последней команды из последовательности.

Опять, если получен результат Holmdel — выводится сообщение о проигрыше и программа завершает работу. В противном случае происходит переход на верх цикла.

28 Принципы конструкции

Rc многое перенял от оболочки Steve Bourne /bin/sh. Любой преемник Bourne shell обязан поддаваться сравнениям. Я, как автор оболочки rc, обычно опуская несущественные характеристики предшественницы, пытался устранить наиболее известные ее недостатки и по возможности упростить вещи. Я вводил новые идеи только в крайних случаях. Очевидным является то, что я хорошо повозился с синтаксисом Bourne.

Самым важным принципом конструкции оболочки rc является то, что она не является препроцессором. Ввод никогда не считывается более одного раза кодом лексического и синтаксического анализа (кроме, конечно же, команды eval, чье основное raison d'être нарушать принятые правила).

Сценарии Bourne shell часто пишутся для запуска с аргументами, содержащими пробелы. Они разделяются на многочисленные аргументы с использованием IFS, часто несвоевременно. В rc значения переменных, включая аргументы командной строки, не

Page 80:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Почему же тогда Bourne shell повторно считывает команды после подстановки из переменных? Оболочка нуждается в сохранении списков аргументов в переменных, чьими значениями являются символьные строки. Если же мы устранили повторное считывание, мы должны изменить тип переменных, чтобы они могли принимать списки строк.

Это приводит к некоторым концептуальным осложнениям. Нам требуется нотация для списков слов. Всего существует два вида конкатенации: для строк $a^$b, и для списков ($a $b). Как раз отличия () и '' наиболее запутывают новичков, хотя различия во многом спорны, так нулевой аргумент не эквивалентен отсутствию аргумента.

Bourne также проводит повторное считывание ввода при подстановке команд. Дело в том, что текст, заключенный в обратные кавычки не является строкой. При правильном использовании он должен быть разбит на заключенные в кавычки команды, но это делает трудным оперирование подстановками вложенных команд, подобно этой:

size=`wc -l \`ls -t|sed 1q\``

Использование внутренних обратных кавычек должно быть ограничено во избежание завершения внешней команды. Может возникнуть ситуация значительно хуже вышеуказанного примера. В rc используется унарный оператор обратной кавычки, чей аргумент является командой, подобно этой:

size=`{wc -l `{ls -t|sed 1q}}

При этом не требуются никакие переходы и вся строка обрабатывается за один проход.

По аналогичным причинам rc определяет управляющие сигналы как функции, вместо ассоциаций строки с каждым сигналом, как это делает Bourne shell, с сопровождающейся возможностью получения сообщений о синтаксических ошибках в ответ на ввод символа прерывания. Так как rc анализирует ввод при наборе, то сообщает об ошибках, когда вы их делаете.

Для всей этой проблемы мы увеличиваем надежность семантических упрощений. Нет необходимости в различиях между $* и $@. Нет необходимости ни в четырех типах кавычек, ни чрезвычайно сложных правилах управления ими. Вы используете кавычки в rc когда хотите, чтобы синтаксический символ появлялся в аргументе, или аргумент был пустой строкой, и никаких других вариантов. Больше не используется IFS, кроме случаев, когда она необходима: преобразование вывода команды в список аргументов при командных подстановках.

При этом избегается важная дыра в безопасности UNIX. В UNIX, для выполнения команд, функции system и popen вызывают интерпретатор /bin/sh. Невозможно использовать любую из этих программ с гарантией, что определенная команда будет обязательно выполнена. Это может быть разрешимо, если эти действия происходят в программе с установленным пользовательским идентификатором. Проблема в том, что IFS используется для разделения команды на слова, так что взломщик может установить значение переменной IFS=/ в своей среде и оставить троянского коня под именем usr или bin в текущем каталоге перед запуском привилегированной программы. Rc не допускает этого, потому что ни в каком случае не производит повторного считывания ввода.

Большинство других различий между rc и Bourne shell не так значительны. Я устранил специфические формы переменной подстановки Bourne shell, подобно

echo ${a=b} ${c-d} ${e?error}

Page 81:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

потому что они мало используются, излишни и легко могут быть выражены в более понятных терминах. Мною были удалены функции export, readonly, break, continue, read, return, set, times и unset поскольку они мне кажутся лишними и полезными лишь в очень редких случаях.

Синтаксис Bourne shell происходит от языка программирования Algol 68, в свою очередь синтаксис rc основан на C или Awk. Мне кажется что, к примеру, строка

if(test -f junk) rm junk

имеет лучший синтаксис, чем

if test -f junk; then rm junk; fi

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

Но, все-таки, один кусочек из крупномасштабного синтаксиса Bourne организован бесспорно лучше, чем в rc — это конструкция if с вкладкой else. If в rc не содержит завершающей fi-подобной скобки. В результате синтаксический анализатор не может ни сообщить, ни объяснить вкладку else без просмотра верхней части конструкции своего ввода. Проблема в том, что например, после чтения строки

if(test -f junk) echo junk found

в интерактивном режиме, rc не может решить: выполнить всю строку немедленно и вывести $prompt(1), или же вывести $prompt(2) и ожидать введения else. В Bourne shell эта проблема не наблюдается, поскольку команда if должна заканчиваться словом fi, независимо от того, содержит она else или нет.

По общему признанию, довольно хилым решением проблемы является объявление вкладки else как отдельного утверждения с семантическим условием, оно должно следовать непосредственно за if и вызывать чаще if not чем else как напоминание, что будет происходить что-то странное. Единственно заметное последствие этого, в том, что в конструкции требуется использование скобок

for(i){ if(test -f $i) echo $i found if not echo $i not found}

этим rc решает проблему ``зависаний else'' неоднозначно в оппозиции к многим ожиданиям людей.

В четырех последних изданиях руководства программиста системы UNIX, грамматика оболочки Bourne, описанная в man-странице, не допускает использования команды who|wc. Это несомненно оплошность, но под этим можно понимать и нечто большее: никто точно не может объяснить, что такое грамматика Bourne shell. Даже исследования исходного кода оболочки не дают никаких результатов. Синтаксический анализатор имеет рекурсивное происхождение, но соответствия программ синтаксическим категориям содержат флаговый аргумент, который тонко изменяет их зависимость действий в контексте. Синтаксический анализатор rc осуществлен c использованием yacc, так что я точно могу сказать что такое грамматика.

29 Благодарности

Роб Пайк, Говард Трики и другие пользователи Plan 9 были настойчивыми, непрерывными

Page 82:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

источники хороших идей и критики. Некоторые примеры настоящего документа была заняты из [Bourne], также как и наилучшие характеристики rc.

30 Литература

S. R. Bourne, UNIX Time-Sharing System: The UNIX Shell, Bell System Technical Journal, Volume 57 number 6, July-August 1978

31 Сноски

(*Идиосинкразия — повышенная чувствительность к определенным веществам или взаимодействиям; часто возникает после первого контакта с раздражителем. Проявления — отек кожи, крапивница и т.п. — Прим пер.:)

Copyright © 2000 Lucent Technologies Inc. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Page 83:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Строковый редактор edАндрей С. Кухар[email protected]

АБСТРАКТНО

В этом документе дается описание строкового редактора ed версии операционной системы Plan 9. В наименовании здесь также не обошлось без трэш-кино «Plan 9 From Outer Space», а точнее без его режиссера, Эда Вуда (Ed Wood), как раз в честь него назван почтенный редактор :)

Введение

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

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

История редактора

В 1970 году Bell Labs приобрели машину PDP-11 для проекта по подготовке текста. При этом был получен лишь процессор и основная память, накопители на магнитных дисках отсутствовали. Все ПО хранилось на бумажных лентах, как таковой, операционной системы не было. Элементарная версия Unix была переписана (все еще на ассемблере) для этой машины, теперь включая простой строковый редактор ed, который был написан Кеном Томпсоном (Ken Thompson) как программа рендеринга для форматизаторов текстов runoff и roff. На редактор повлиял популярный в те времена QED. Из ранних свойств редактора можно выделить основную строковую ориентацию, радикально упрощенные регулярные выражения (в нем присутствовал лишь метасимвол *, никаких чередований и круглых скобок) и отсутствие функций для работы с несколькими буферами. Последующие версии ed для Unix (уже написанные на С) усложнялись и были более пригодны для работы; была добавлена возможность обратного обращения в регулярных выражениях, которые теперь совсем не включали ни регулярные языки, ни свободные от контекста языки, но входили в контекстно-зависимые языки.

Редактор обрел заслуженную популярность среди пользователей Unix, «Ученые в области computer science любят ed не потому что он пришел первым, а потому что он стандартный. Все остальные любят ed потому что это ED!», так говаривали они.

Когда в конце 80-х начались работы над проектом Plan 9, одной из первых переписанных программ (т.е. оставленных из мира Unix) был почтенный (venerable) редактор ed. Автором «новой» версии стал некто Том Дафф (Tom Duff) — автор оболочки rc, системы растровой графики, библиотеки панелей, броузера mothra и большого количества других полезных

Page 84:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

вещей. Plan 9 версия ed отличается от ранних Unix версий необходимыми изменениями, вызванными операционной системой, для уведомлений взамен сигналам и т.п., плюс поддержкой UTF-8. Кстати, Том даже портировал Plan 9 версию редактора (которую он считает лучшей из истинных потомков оригинального ed) обратно в Unix, и запускает ее на работе (в Pixar) на машине с IRIX и дома на FreeBSD.

Причины и рекомендации

Если вы хотя бы поверхностно знакомы с редакторами Sam и Acme, то вполне логичным прозвучит вопрос о затрате времени на, казалось бы, устаревшую, примитивную и, наверное, весьма уродливую программу «старой школы». Дело в том, что ed выполняет некоторые операции весьма успешно, несмотря на свой возраст. О стабильной работе в среде Plan 9 не стоит и говорить. Кроме того, ed легко запускать из файлов-сценариев и он незаменим при работе без графического режима, скажем, на файловом сервере.

С вступительной частью закончено, если желание разобраться в ed не оставило вас, тогда читайте дальше. Рекомендуемый путь изучения ed — это чтение документа с одновременным использованием редактора для выполнения примеров и упражнений. (Помощь опытных пользователей также весьма полезна.) В приложении приведен полный список всех команд ed с кратким описанием.

Приступим

Здесь и далее в документе предполагается, что вы успешно вошли в систему и создали окно допустимого размера. Для запуска редактора выполните команду:

ed

У редактора ed НЕТ символа приглашения, точнее есть, но это пустая строка :). Как правило, редактированию подвергается некий временный файл, который вы впоследствии можете скопировать в любой другой файл. Этот временный файл называется буфером редактирования, так как он выполняет функции буфера между вводимым вами текстом и файлом, куда записываются изменения. Например, введите такие строки:

aэто строка 1это строка 2это строка 3это строка 4

Теперь в новой строке введите точку «.». В результате этих действий в буфер будут записаны четыре строки, чтобы просмотреть их, введите:

1,4p

где 1,4 — это диапазон (интервал) номеров строк, а p — команда просмотра строк.

Теперь попробуйте выполнить следующее:

2p

для вывода строки под номером 2. Если же просто ввести:

p

то результатом будет содержимое текущей строки (которой сейчас является строка 2). По умолчанию, большая часть команд ed манипулируют именно текущей строкой.

Page 85:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Если указан аргумент файл, ed применяет к нему команду e (см. ниже); т.е. файл считывается в буфер ed, дабы его можно было редактировать.

Опции редактора:

- подавляет вывод количества байт командами e, r и w, а также выдачу приглашения ! после команды !команда.

-o (для внешнего канала) записывает весь вывод на стандартный файл ошибок в отличие от сохранения командой w. Если файл не задан, то файлом запоминания стает /fd/1.

Основы

Буфер

Каждый раз, когда вы запускаете ed, для выполнения всех ваших команд выделяется специальная область внутренней памяти машины. Эта область называется буфером. При редактировании файла, его содержимое копируется в этот буфер и вы работаете именно с ним. Замена оригинала производится только при сохранении изменений.

Команды

Как и обычные команды Plan 9, команды редактора вводятся с клавиатуры и заканчивается нажатием клавиши Enter. Выполнение команды начинается после того, как вы нажали Enter. Большинство команд состоят из одного символа, перед которым могут указываться номер строки или диапазон номеров строк. Большая часть команд редактора работает с текущей строкой (см. ниже «Номера строк»). Многие команды имеют аргумент имя файла или строка.

Номера строк

После каждой команды, изменяющей количество строк в буфере, ed выполняет перенумерацию строк. Каждой строке буфера всегда присвоен номер. Многие команды редактора используют либо одиночные номера строк, либо диапазон номеров, которые передаются команде в качестве аргументов. Эти аргументы определяют конкретные строки в буфере, над которыми нужно выполнить команду (команды).

Использование редактора

Вход и выход из ed

Как уже описывалось выше, для запуска редактора следует ввести команду:

ed

Также может использоваться команда такого вида:

ed имя файла

где имя файла — это имя нового или уже существующего файла. Для завершения сеанса работы с ed используется команда q (от quit):

q

или комбинация клавиш ctrl-d. В ответ вы получите символ приглашения операционной

Page 86:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

системы Plan 9 (точнее символ приглашения оболочки rc). Если вы еще не записали изменения в файл, ed лаконично (как всегда) предупредит вас, что при выходе произойдет потеря изменений:

?

Если нестерпимое желание выхода из редактора не оставило вас, введите команду q (или ctrl-d) еще раз.

Для «легального» выхода из редактора вам нужно ввести 2 команды:

wq

т.е. завершение работы ed с предшествующим сохранением изменений.

Добавления текста: команда «а»

При вызове ed без аргумента файла, создается новый буфер. Для заполнения буфера нужно набрать текст или скопировать его из файла. На данном этапе изучения работы редактора рассмотрим первый вариант, со вторым разберемся немного позже.

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

Для управления процессом работы с текстовыми файлами ed владеет набором специальных команд.

Изучение команд начнем с команды добавления текста а (от append или add). После ее выполнения, все вводимые вами строки будут добавляться в буфер, к примеру:

aНастало времядля всех нормальных пацановне слабо погудеть..

Чтобы закончить добавление, введите на пустой строке символ точки «.» или нажмите Del (при этом редактор выведет ? и перейдет в командный режим). Точка «.» сообщает ed, что вы закончили ввод.

После завершения добавления текста в буфере будут следующие три строки:

Настало времядля всех нормальных пацановне слабо погудеть.

Символы «а» и «.» отсутствуют, так как они не являются частью текста. Чтобы добавить еще строки к уже имеющемуся тексту, дайте еще раз команду а и продолжайте ввод.

Запись файла: команда «w»

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

w text

Page 87:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

В ответ ed сообщит количество записанных в файл символов (байт). Вы должны увидеть примерно следующее:

61

(Подсчету подлежат также пробелы и символы новой строки.) Команда записи не изменяет содержимое буфера, а лишь копирует его, поэтому вы можете продолжать добавлять в него текст. При вызове ed командой ed имя файла, команда w, заданная без аргумента, записывает буфер в файл с именем имя файла.

Следует также помнить, что ed всегда работает с копией файла, оригинал не редактируется, пока вы не дадите команду w.

Упражнение 1:

Запустите ed и создайте какой-нибудь текст:

a... текст ....

Сохраните его в файл с помощью команды w. Теперь покиньте ed командой q и просмотрите его содержимое, скажем, командой cat:

cat имя файла

или pr:

pr имя файла

Редактирование файла: команда «e»

Для копирования содержимого файла в буфер используется команда e (от edit). Чтобы загрузить в редактор какой-нибудь текст, возьмем, к примеру, три строки с текстом «Настало время» и т.д. из предыдущего примера, выполните команду:

e text

При этом в буфер загружен весь файл text и на экране появится количество его символов.

61

Если в буфере до этого уже была какая-либо информация, она уничтожается.

Если вы использовали команду e для считывания файла в буфер, то в команде w вам необязательно указывать имя файла. Редактор ed помнит имя файла, которое последним использовалось в команде e и команда w по умолчанию будет делать запись в этот файл. Таким образом, сеанс работы с редактором может быть таким:

ede file[процесс редактирования]wq

Изменение имени файла для записи: команда «f»

Чтобы узнать имя файла, в который производилась последняя запись, можно использовать команду f (от file). Для этого выполните f без аргументов. С помощью команды f можно также менять имя файла запоминания редактора. Например, в результате выполнения

Page 88:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

следующих команд:

ed preciousf junk

в буфер будет загружен файл precious и затем команда f сохранит его содержимое в файле junk. Исходный файл precious не подвергнется изменениям.

Считывание файла: команда «r»

Бывают ситуации, когда нужно считать в буфер файл, не стирая имеющейся до этого в нем информации. Для этой цели подходит команда r (от read). К примеру, по команде:

r text

файл text считывается и добавляется в конец имеющейся в буфере информации. Предположим, что вы выполнили команды:

e textr text

После этого в буфере будет находиться две копии файла text (шесть строк):

Также как и команды w и e, после выполнения команды r на экран выводится количество считанных в буфер символов.

Упражнение 2:

Поэкспериментируйте с командой e на различных файлах. Возможно, вы получите сообщение ошибки ?name, где name — это указанное вами имя файла, это означает, что такой файл не существует или вы допустили опечатку в имени или, возможно, у вас нет разрешения для чтения этого файла или записи в него. Убедитесь, что команда

ed имя файла

эквивалентна

ede имя файла

Что делает следующая команда?

f имя файла

Просмотр строк: команда «p»

Для вывода содержимого буфера (или его частей) используется команда печати p (от print). К примеру, чтобы просмотреть первые две строки буфера редактирования (строки с 1 по 2), введите:

1,2p

Ed выведет:

Настало времядля нормальных пацанов

Предположим, что вам нужно просмотреть все строки буфера. Вы, конечно, можете дать команду, скажем, 1,3p, если знаете, что в буфере именно три строки. Но, как правило, вам редко будет известно точное количество строк буфера, и поэтому в ed имеется специальный

Page 89:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

символ (метасимвол), обозначающий «номер последней строки в буфере» — это знак доллара $. Попробуйте такую команду:

1,$p

В результате будут выведены все строки (с первой по последнюю).

Чтобы напечатать последнюю строку буфера, введите:

p,$p

Довольно простая команда, не так ли? Но ed позволяет сократить ее до такого вида:

$p

Вы можете просмотреть любую строку, указав перед p в команде ее номер, к примеру:

1p

выведет на экран только первую строку буфера:

Настало время

Для вывода одной строки вводить символ p необязательно:

$

при этом ed выведет последнюю строку из буфера.

Вы можете также использовать символ $ в комбинациях наподобие этой:

$-1,$p

в результате будет напечатано две последние строки буфера.

Следующей возможностью, предоставляемой редактором, является указание с помощью знаков + (плюс) и - (минус) смещения относительно номеров строк, обозначаемых долларом $ или точкой .. Команда

$-1

выводит предпоследнюю строку из буфера. Для вывода последних шести строк, дайте команду:

$-5,$p

Если в буфере меньше шести строк, то появится сообщение об ошибке.

Команда

.-3,.+3p

печатает текущую строку, включая три строки перед ней и три строки после нее. (В данном случае знак + указывать необязательно, т.е. команда .-3,. 3p выполнит те же действия.)

Вы можете также использовать знаки + и - в качестве номеров строк, например, введя команду:

-

вы переместитесь назад на одну строку в буфере относительно текущей строки. Вы можете указать в командной строке столько знаков -, на сколько строк вам надо переместиться назад.

Page 90:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Например:

- - -

вернет вас на три строки назад также как и команда

-3

Команда

-3,+3p

эквивалентна следующей

?.-3p+3p

Вывод текущей строки: команда «.»

Предположим, что в буфере имеются следующие шесть строк:

Настало времядля всех нормальных пацановне слабо погудеть.Настало времядля всех нормальных пацановне слабо погудеть.

Если вы введете:

1,3p

то ed покажет:

Настало времядля всех нормальных пацановне слабо погудеть.

если же теперь введете

p

на экране появится:

не слабо погудеть.

Эта строка является третьей строкой в буфере и последней строкой, с которой вы работали. Вы можете еще раз ввести p и ed будет продолжать ее печатать. Это происходит потому, что ed помнит номер строки, с которой вы работали последней, и при необходимости использует его в командах. К этой строке можно обратиться с помощью точки .. Точка является таким же номером строки, как и $, она обозначает «текущую строку» или «строку, над который вы только что выполнили какую-нибудь операцию». Точкой можно пользоваться различными способами. Например, команда:

.,$p

печатает все строки, начиная с текущей (и включая ее) и до конца буфера. В нашем примере это строки с 3 по 6.

Некоторые команды изменяют значение номера текущей строки, некоторые нет. Команда p устанавливает значение для точки равным номеру последней напечатанной строки. В данном примере текущей станет строка 6.

Page 91:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Точка часто используется в комбинациях типа:

.+1

что эквивалентно

.+1p

Эта команда выводит следующую строку. Это один из способов последовательного просмотра буфера редактирования. Вы можете также ввести:

.-1

При этом будет выведена строка перед текущей. Еще один полезный пример, печатающий три строки перед текущей:

.-3,.-1p

Помните, что все эти команды изменяют значение номера текущей строки. Вы в любой момент можете узнать ее номер, выполнив команду:

.=

в ответ на которую ed выводит значение номера.

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

Каждое нажатие на клавишу Enter эквивалентно команде:

.+1p

Введите ее, затем попробуйте ввести знак -. Результат будет тот же, что и у команды:

.-1p

Упражнение 3:

Потренируйтесь в работе с командой p над каким-нибудь текстом. Вы, возможно, столкнетесь с тем, что невозможно вывести строку с номером 0 или строку с номером, большим, чем количество строк в буфере, а также с невозможностью вывода строк в обратном порядке, например

3,1p

Удаление строк: команда «d»

Предположим, что вам необходимо удалить три лишние строки из буфера. Для этой цели предназначена команда d (от delete). Ее действие подобно действию команды p за исключением того, что d удаляет строки вместо их вывода. Строки, которые требуется удалить, указываются в команде точно так как в команде p. Например, команда:

4,$d

удаляет строки, начиная с четвертой по последнюю. В нашем примере после выполнения этой команды осталось только три строки и вы можете проверить это, выполнив:

Page 92:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

1,$p

Обратите внимание на то, что текущей является 3-я строка. Указатель . устанавливается на следующую вслед за последней удаленной строку, если только в результате удаления не произошла очистка буфера. В этом случае указатель . устанавливается на текущую строку $.

Упражнение 4:

Поэкспериментируйте с командами a, e, r, w, p и d пока не убедитесь, что вы понимаете, как они работают и как в этих командах можно указывать номера строк.

Попробуйте указать номера строк в командах a, r и w. Вы обнаружите, что команда a добавляет строки после строки с указанным номером; команда r считывает файл в буфер после указанной строки (а не обязательно в конец буфера); команда w записывает в файл только указанные вами строки, а не весь буфер. Все это бывает иногда очень удобно. Например, вы можете вставить файл в начало буфера командой:

0r имя файла

или вставить строки в начале буфера введя:

0a[ . . . текст . . . ].

Помните, что команда

.w

очень сильно отличается от:

.w

так как первая записывает в файл только одну строку, в то время как последняя — весь буфер.

Замена текста: команда «s»

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

Предположим, что в результате опечатки первая строка буфера выглядит так:

Настало врем

В слове время отсутствует последняя буква я. Чтобы исправить ошибку, вы можете использовать команду s следующим образом:

1s/врем/время/

В результате чего в строке 1 символы врем будут заменены на время. Чтобы проверить корректность замены, введите:

p

чтобы просмотреть исправленную строку:

Настало время

Page 93:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Команда замены имеет следующий синтаксис:

начало-строки,конец-строки s/заменить что/чем/

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

Таким образом, можно ввести:

1,$s/ашипка/ошибка/

и исправить первое вхождение последовательности ашипка на ошибка в каждой строке файла.

Если в команде замены не указываются номера строк, замена будет сделана только в текущей строке.

Команда:

s/что-нибудь/что-нибудь другое/p

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

Также можно дать команду:

s/строка//

в результате которой первая найденная в текущей строке последовательность символов строка будет найдена и удалена. Такая команда бывает удобна для удаления лишних слов в строке или букв в слове. Например, если у вас есть строка:

Настало00 время

вы можете ввести:

s/00//p

чтобы получить:

Настало время

Помните, что // (два стоящих рядом слэша) означают «отсутствие символов», а не пробел. Есть разница. (Смотрите ниже другое значение //.)

Упражнение 5:

Потренируйтесь с командой замены. Посмотрите, что происходит, когда вы заменяете в строке слово, встречающееся в ней несколько раз. Например, если вы введете:

aнакладная на товар

Page 94:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

.s/на/не на/p

То строка примет вид:

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

Команда замены меняет только первое вхождение искомого текста в строке. Чтобы выполнить замену всех имеющихся вхождений, добавьте в команде замены символ g (от global):

s/.../.../g

Попробуйте использовать в качестве разделителей вместо слэшев любые другие символы.

Контекстный поиск: команда «/.../»

После того как вы познакомились с командой замены, можно перейти к изучению следующей важной функции редактора — контекстного поиска.

Предположим, у вас в буфере редактирования наличествует такой текст:

Настало времядля всех нормальных пацановне слабо погудеть.

Предположим, вы хотите найти строку, в которой есть словосочетание не слабо, чтобы потом заменить его на плотно. Когда у вас только три строки в буфере, довольно просто их просмотреть и найти нужную строку. Но если буфер содержит сотни строк, такой способ уже не годится. Контекстный поиск является простым методом нахождения требуемой строки независимо от ее номера. Для этого необходимо указать между слэшами искомую последовательность символов:

/шаблон/

Например, команды

/не слабо/

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

/не слабо

Команда поиска делает строку, в которой найдена искомая последовательность текущей и выводит ее на экран.

не слабо погудеть.

Редактор ed осуществляет поиск со строки с номером .+1 до конца буфера, затем переходит в начало буфера и продолжает поиск до строки с номером точка. Ed просматривает все строки в буфере до тех пор, пока не найдет нужный текст или не дойдет до строки с номером точка. Если искомая последовательность не найдена, появляется стандартное лаконичное сообщение об ошибке (?). В противном случае, ed печатает найденную строку. Вы можете также указать обратное направление поиска, заключив искомую последовательность в вопросительные знаки ? вместо /, например:

?не слабо?

Page 95:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

или

?не слабо

Это бывает удобно, когда вы точно знаете, что искомая строка расположена до текущей.

Слэш и знак вопроса являются единственными символами, которые можно использовать для обозначения контекстного поиска. (Если вы получите неожиданные результаты при использовании символов

^ . $ [ * \ &

см. главу «Шаблоны и регулярные выражения».)

Вы можете одновременно выполнять поиск и замену, например:

/не слабо/s/не слабо/плотно/p

После выполнения этой команды вы получите:

плотно погудеть.

Данная команда выполняет сразу три действия: поиск по шаблону, выполнение замены и вывод измененной строки.

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

Предположим, что в буфере есть строки:

Настало времядля всех нормальных пацановне слабо погудеть.

Номера строк, определяемые выражениями:

/Настало/+1/нормальных//погудеть/-1

являются командами контекстного поиска и все они определяют одну и ту же строку (строку 2). Чтобы сделать изменения в строке 2, введите:

/Настало/+1s/нормальных/конкретных/

или

/нормальных/s/нормальных/конкретных//

или

/погудеть/-1s/нормальных/конкретных//

Выбор команды определяется только удобством работы. Чтобы просмотреть все три строки, выполните команду:

/Настало/,/погудеть/p

или

/Настало/,/Настало/+2p

Page 96:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

(или подобную им). Первый способ лучше в случае, если вы не знаете количество строк для вывода.

Помните, что выражение контекстного поиска является обычным номером строки и его можно применять везде, где требуется указание номеров строк.

Предположим, вы выполняете поиск слова штучка:

/штучка/

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

//

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

??

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

/штучка/

Ed выведет на экран строку, содержащую штучка.

s//загогулина/p

В результате слово штучка заменится на загогулина.

Упражнение 6:

Поработайте с командой контекстного поиска. Просмотрите весь буфер в поисках какой-нибудь последовательности символов. Попробуйте использовать команды контекстного поиска в качестве номеров строк в командах замены, вывода и удаления. (Их можно также использовать в командах r, w и а.) Выполните поиск в обратном направлении, указывая вместо / знак вопроса ?.

Изменение и вставка текста: команды «c» и «i»

В этом пункте рассматриваются команда изменения c (от change), применяющаяся для изменения или замены одной или более строк, и команда вставки i (от insert), использующаяся для вставки одной или более строк.

Команда с используется для замены группы строк строками, вводимыми с клавиатуры. Например, чтобы изменить строки с .+1 по $ на какие-либо другие, введите:

.+1,$c[ . . . напечатайте здесь нужные вам строки . . . ].

Строки, которые вы напечатаете после команды с и до команды ., заменят указанную группу строк. Это удобно при замене строки или группы строк с ошибками.

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

Page 97:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Команда i похожа на команду добавления а. Например, чтобы вставить строки перед строкой, содержащей слово штучка, введите:

/string/i[ . . . напечатайте здесь строки, которые необходимо вставить . . . ].

Текст, вводимый после команды i, вставляется перед указанной строкой. Если номер строки не указан, то текст вставляется перед текущей строкой. После выполнения команды текущей становится последняя вставленная строка.

Упражнение 7:

Команда с аналогична последовательному выполнению команды удаления и вставки строк. Проверьте это, выполнив команды:

начало,конец di...текст....

и

начало,конец c...текст....

Они не будут работать в точности одинаково в том случае, если удалению подверглась последняя строка.

Поэкспериментируйте с командами a и i и вы увидите, что они отличаются только тем, что команда:

номер-строки a. . . текст . . ..

вставляет строки после строки с указанным номером, а команда:

номер-строки i. . . текст . . ..

перед этой строкой. Если номер строки не указан, подразумевается текущая строка.

Перемещение строк: команда «m»

Команда перемещения m (move) позволяет переместить группу строк из одного места в буфере в другое. Предположим, вам нужно поместить первые три строки в конец буфера. Это можно сделать следующим способом:

1,3w temp$r temp1,3d

Здесь temp является именем временного файла. Намного проще это сделать одной командой:

1,3m$

Она перемещает строки с 1 по 3 в конец буфера. В общем случае команда перемещения m выглядит так:

Page 98:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

нач.строка,кон.строка m после-какой-строки-вставить

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

Первый параграф. . .конец первого параграфа.Второй параграф. . .конец второго параграфа.

Вы можете поменять параграфы местами командой такого типа:

/Второй/,/конец второго/m/Первый/-1

Обратите внимание на -1, текст помещается после нее. Текущей становится последняя перемещенная строка.

В качестве примера рассмотрим часто употребляемую команду, позволяющую менять порядок следования двух соседних строк. Предположим, вы находитесь на первой строке. Тогда команда:

m+

перемещает текущую первую строку через строку после текущей. Если вы находитесь на второй строке, то команда:

m-

перемещает текущую строку через строку вверх.

Команда m более эффективна чем запись, удаление и повторное считывание. Основная трудность при использовании команды m заключается в том, что в случае применения команд поиска для задания перемещаемой группы строк и адреса, куда их надо переместить, необходимо быть очень внимательными, в противном случае вы можете переместить не те строки. Поэтому если вы будете выполнять действия постепенно, вам легче будет себя проверить на каждом шаге. Также рекомендуется выполнять команду w перед выполнением любой сложной команды, тогда, если вы ошиблись, легко вернуться к предыдущему состоянию.

Дополнительную информацию о том, как перемещать текст, см. в разделе «Создание меток на строки в файле» в этой главе.

Глобализация: команды «g» и «v»

Глобальные команды g и v используются для выполнения одной или более команд редактирования над всеми строками, которые содержат (g) или не содержат (v) указанную последовательность символов. Например, команда:

g/план/p

выводит на экран все строки, содержащие слово план. На текст, заключенный между слэшами, распространяются те же правила и ограничения, что и в командах поиска и замены.

К примеру:

g/^\./p

Page 99:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

показывает все форматирующие команды в файле. По поводу использования символов ^ и \ см. в разделе «Шаблоны и регулярные выражения».

Команда v аналогична g за исключением того, что она работает со строками, не содержащими указанный текст. Например, команда:

v/^\./p

выводит на экран все строки, кроме тех, которые начинаются с точки.

После команд g и v может следовать любая команда. Например, следующая команда удаляет все строки, начинающиеся с «.»:

g/^\./d

Следующая команда удаляет все пустые строки:

g/^$/d

Наверное, наиболее полезной командой, которая может использоваться вместе с глобальными командами, является команда замены. Например, чтобы заменить слово ПЛАН на план сразу во всем файле и проверить, что замена на самом деле произведена, выполните команду:

g/ПЛАН/s//план/gp

Обратите внимание, мы применили // в команде замены для обозначения текста, использовавшегося в последней команде поиска, в нашем случае план. Команда p выполняется для каждой строки, в которой найдено искомое слово.

Глобальные команды просматривают файл дважды. За первый проход они помечают все строки, в которых найден указанный текст. На втором проходе каждая помеченная строка по очереди становится текущей и выполняется вторая команда.

Например, команда:

g/^\.P/+

печатает строки, начинающиеся с команды .P. Помните, что знак + обозначает строку, следующую после текущей.

Команда:

g/тема/?^\.H?p

ищет все строки, содержащие слово тема, затем просматривает файл назад в поиске строки, начинающейся с .H и выводит ее. Другая команда:

g/^\.EQ/+,/^\.EN/-p

печатает все строки, находящиеся между строками, начинающимися с форматирующих команд .EQ и .EN.

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

Под управление глобальной команды можно передать более одной команды. Например, скажем, вам нужно заменить x на y и a на b во всех строках, содержащих слово график. Для этого введите команду:

g/график/s/x/y/\s/a/b/

Page 100:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Бэкслэш \ сообщает команде g, что команда продолжается на следующей строке. В противном случае, команда g заканчивается на строке, не содержащей \.

Обратите внимание на то, что команда замены в команде g не может использоваться для вставки новой строки.

Команда:

g/x/s//y/\s/a/b/

не будет работать так, как вы ожидаете. Дело в том, что запоминаемый шаблон для поиска и замены // в этой команде будет меняться с x на a и наоборот. Поэтому для корректности данную команду следует переписать в таком виде:

g/x/s/x/y/\s/a/b/

Можно выполнять команды a, c и i как часть глобальной команды. Как и для других многострочных команд, добавляйте бэкслэш в конце каждой строки, за исключением последней. Чтобы добавить .nf и .sp перед каждой строкой, содержащей .EQ, введите:

g/^\.EQ/i\.nf\.sp

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

Показ знаков табуляции и управляющих символов: команда «l»

В редакторе ed для вывода содержимого буфера кроме команды p есть еще команда l (от list). l делает видимыми символы, которые обычно (в команде p) не выводятся, например, знаки табуляции, символы забоя и прочие управляющие символы. Если вы выводите командой l строку, содержащую такие символы, то символы табуляции будут отображены как \t, символы забоя как \b, бэкслэши или обратные косые черты (не путайте с чертями :) как \\, непечатаемые символы — слэшем \, буквой x с четырьмя шестнадцатеричными цифрами.

Длинные строки поддаются делению, начиная со второй и последующие под-строки выводятся с отступом на один стоповый символ табуляции. Если последний символ в строке является пробелом, то за ним следует \n.

Функция отмены: команда «u»

Иногда после выполнения замены в строках вы можете обнаружить, что этого не надо было делать, или делать, но совсем по-другому. Команда отмены u (от undo) восстанавливает предыдущее содержимое первой адресуемой строки (sic), которая должна быть последней строкой, в которой была выполнена подстановка (sic вдвойне).

Создание меток на строки в файле: команда «k»

Команда k дает возможность присвоить конкретной строке метку и в последующем обращаться к этой строке, указывая ее метку вместо номера. Это бывает полезно при перемещении строк. Например, команда:

kx

присваивает текущей строке метку x. Если перед символом k в команде указать номер строки,

Page 101:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

то будет помечена эта строка. (В качестве меток можно использовать только одиночные символы.) К помеченной строке можно обратиться командой:

'x

Обратите внимание на использование здесь одинарной кавычки '. Метки очень удобны при перемещении блоков. Пометим сначала начало блока, который нужно переместить:

ka

и затем конец:

kb

Теперь перейдем в место, куда требуется поместить блок, и введем:

'a,'bm.

В каждый конкретный момент времени строка может иметь только одну метку.

Копирование строк: команда «t»

Ранее упоминалась идея сохранения строк, которые часто используются, для сокращения времени, необходимого для их ввода. В редакторе ed для копирования группы строк в любое место предназначена команда t. Ее использование бывает часто легче, чем запись и чтение.

Команда t аналогична команде m, только вместо перемещения строк в указанное место, она их копирует. Например:

1,$t$

дублирует содержимое буфера редактирования.

Обычно команда t используется для создания последовательности строк, которые не сильно отличаются друг от друга. Например, вы можете ввести (за шарпами — комментарии):

aНастало время для всех нормальных пацанов не слабо погудеть..t. # делаем копиюs/пацанов/братков/ # немного изменяемt. # делаем еще одну копиюs/Настало/Вчера было/ # еще изменяем

В результате ваш файл будет выглядеть так:

Настало время для всех нормальных пацанов не слабо погудеть.Настало время для всех нормальных братков не слабо погудеть.Вчера было время для всех нормальных пацанов не слабо погудеть.

Выход в оболочку rc: команда «!»

Иногда бывает удобно временно выйти из редактора для выполнения команды Plan 9. Команда выхода ! позволяет осуществлять это.

Если вы введете:

!команда

ваше текущее состояние редактора будет сохранено и будет выполняться команда операционной системы Plan 9. Когда выполнение команды закончится, ed выведет

Page 102:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

восклицательный знак !. Начиная с этого момента вы можете продолжать редактирование.

Шаблоны и регулярные выражения

Вы могли заметить, что иногда происходят непонятные действия, когда вы используете такие символы как точка ., знак доллара $, звездочка * в контекстном поиске и замене. Дело в том, что ed обрабатывает эти символы как специальные. Например, при контекстном поиске или в команде замены точка . обозначает не символ точки, а шаблон для любого символа, т.е. команда:

/x.y/

будет искать строку, в которой между x и y может стоять любой символ. Вот полный список специальных символов, при использовании которых могут возникнуть проблемы:

^ . $ [ * ] \ / &

В следующих пунктах описывается как использовать эти символы для описания шаблонов текста в командах поиска и замены. Эти шаблоны называются регулярными выражениями и используются также во многих командах и утилитах Plan 9.

Напомним, что символ g, стоящий в конце команды замены, вызывает замену всех вхождений указанного текста. Команды:

s/что/чем

и

s/что/чем/g

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

После любой из форм команд замены можно указывать p или l для вывода содержимого строки. Например:

s/что/чем/ps/что/чем/ls/что/чем/gps/что/чем/gl

Перед любой из команд замены s можно указать один или два номера строк для задания группы строк, в которой требуется произвести замены. Так, команда:

1,$s/очипятка/опечатка/

заменяет первое вхождение слова очипятка на опечатка в файле. А команда:

1,$s/очипятка/опечатка/g

заменяет все вхождения слова очипятка на опечатка в файле.

Если вы добавляете p или l в конце любой из команд замены, то выводиться будут не все измененные строки, а только последняя измененная строка. Позднее мы объясним, как просматривать все измененные строки.

Точка: .

Первый метасимвол, который мы рассмотрим — это точка «.». Если она указывается в левой

Page 103:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

части команды замены s, или в команде поиска, то обозначает любой одиночный символ. Так, команда поиска:

/x.y/

будет искать строку, в которой x и y разделены одним любым символом, например:

x+yx-yx yxzy

и т.п.

Так как точка является метасимволом, обозначающим любой символ, она позволяет работать со специальными символами, показываемыми командой l. Предположим, у вас есть строка, которая показана командой l в таком виде:

э\tто

Допустим, вам нужно удалить символ \t, который соответствует символу табуляции. Наиболее очевидной кажется команда:

s/\t//

но она не сработает. Другой вариант — это перепечатать всю строку. Это довольно разумно, в случае, если строка не слишком длинная. Другим путем решения проблемы является использование метасимвола точки. Так как \t на самом деле представляет собой только один символ, то, если ввести команду:

s/э.то/это/

то задача будет выполнена. В этой команде точка будет обозначать любой символ, стоящий между буквами э и т.

Команда:

s/./,/

заменяет первый символ в строке на запятую. Специальное значение символа точки можно отменить, указав перед ним бэкслэш \.

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

.s/./\./

Первая точка в команде обозначает номер текущей строки. Вторая точка является метасимволом, соответствующим любому символу в этой строке. И только третья точка обозначает обычный символ точки «.». (Помните также, что точка используется для завершения ввода командами a и i.) В правой части команды замены символ точки не имеет никакого специального значения. Если вы выполните указанную команду над строкой:

Настало время.

то в результате получите:

.астало время.

что, скорее всего не совсем то, что вам требуется. Чтобы заменить точку в конце

Page 104:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

предложения на запятую, введите:

s/\./,/

Специальное значение метасимвола отменяется бэкслэшем, стоящей перед ним.

Бэкслэш: \

Так как метасимвол точка . обозначает любой символ, то возникает вопрос, что делать, когда требуется указать именно символ точки. Например, как преобразовать строку:

Настало время.

в

Настало время?

Бэкслэш отменяет все специальные значения у символа, следующего сразу после него, в частности, \ делает из метасимвола точки . обычный символ, и вы можете использовать его в команде замены:

s/\./?/

Пара символов \. рассматривается редактором ed как один обычный символ точки.

Бэкслэш можно также использовать при поиске строк, содержащих специальные символы. Предположим, вы ищете строку, в которой имеется .DE в начале строки. Команда поиска:

/.DE/

не выполнит того, что вам надо, так как она будет искать строки с текстом типа:

JADEFADEMADE

так как точка будет соответствовать любому символу. Но, если вы укажете команду:

/\.DE/

то будет найдена нужная вам строка.

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

/\/

не будет работать, так как в данной команде символ \ не является контекстом для поиска, а обозначает, что следующий за ним символ / больше не служит для обозначения границ контекста. Правильная команда выглядит вот так:

/\\/

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

//exec //sys.fort.go // etc...

введите команду:

Page 105:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

s:/::g

в результате будет:

exec sys.fort.go etc...

Когда вы добавляете текст командами a, i или с, то бэкслэш не имеет специального действия и вы можете вводить ее как обыкновенный символ.

Упражнение 8:

Придумайте две команды замены, каждая из которых преобразует строку:

\x\.\y

в строку:

\x\y

Есть несколько решений, например:

s/\\\.//s/x../x/s/..y/y/

Знак доллара: $

Метасимвол $ обозначает конец строки. Допустим, у вас есть строка:

Настало

и вы хотите добавить слово время в конец строки. Примените знак $ следующим образом:

s/$/ время/

и вы получите:

Настало время

Пробел перед словом время в команде необходим, так как в противном случае вы получите:

Насталовремя

Чтобы заменить в следующем предложении:

Настало время, для всех нормальных пацанов,

вторую запятую на точку, введите команду:

s/,$/./

и вы получите:

Настало время, для всех нормальных пацанов.

В данном контексте знак доллара $ указывает редактору, какую запятую надо заменить. Без знака доллара в команде изменению подверглась бы первая запятая в строке:

Настало время. для всех нормальных пацанов,

Чтобы изменить:

Настало время.

Page 106:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

на

Настало время?

можно дать команду:

s/.$/?/

Также как и метасимвол ., $ имеет несколько значений в зависимости от контекста. В команде:

$s/$/\$/

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

Галочка: ^

Символ ^ обозначает начало строки. Например, вам надо найти строку, начинающуюся с и. Если вы введете:

/и/

то, скорее всего, вы сначала найдете несколько строк с и в середине строк, и потом только нужную вам строку. Но, если вы укажете команду:

/^и/

то существенно сузите рамки поиска.

Используя символ ^ вы можете, например, вставить что-нибудь в начало строки:

s/^/ /

Эта команда вставляет пробел в начале текущей строки.

Метасимволы можно объединять. Чтобы найти строку, которая содержит только символы .P, вы можете дать команду:

/^\.P$/

Звездочка: *

Допустим, у вас есть строка, которая выглядит так:

текст x y текст

где под текст понимается какой-нибудь текст, а между x и y стоит неизвестное количество пробелов. Предположим, вам нужно заменить все пробелы между x и y на один единственный пробел. Строка слишком длинная, чтобы вводить ее заново, и пробелов слишком много, чтобы их пересчитывать. Для решения таких задач имеется специальный метасимвол *. Конструкция, состоящая из символа и следующей за ним звездочки, означает любое количество стоящих подряд таких символов. В нашем случае, чтобы заменить все пробелы между x и y, достаточно ввести команду:

s/x *y/x y/

Звездочка может использоваться с любым символом, а не только с пробелом. Если бы наш пример выглядел так:

Page 107:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

текст x-----------y текст

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

s/x-*y/x y/

Предположим теперь, что наш исходный текст выглядит так:

текст x...................y текст

Если вы дадите команду:

s/x.*y/x y/

то результат ее выполнения может быть весьма непредсказуем. Если в строке нет больше x и y, то замена сработает. Метасимвол . обозначает любой символ, и поэтому конструкция .* соответствует любой последовательности одинаковых символов, и данная команда несмотря на вашу осторожность, может удалить больше символов, чем вы ожидаете.

Например, если строка была такая:

x текст x....y текст y

то, дав команду:

s/x.*y/x y/

вы сотрете весь текст между первым символом x и последним символом y. Чтобы избежать этого, укажите обратную черту перед метасимволом точки, чтобы отменить ее специальное значение:

s/x\.*y/x y/

Но бывают ситуации, когда шаблон .* обозначает именно то, что вам требуется. Например, чтобы изменить строку:

Настало время для всех нормальных пацанов ...

на:

Настало время.

используйте конструкцию .* для удаления всех символов после для:

s/для.*/./

Использование метасимвола * имеет свои особенности, наиболее важной из которых является то, что слова «любое количество» означают ноль или более символов. Например, если строка содержит так:

xy_текст_x__y_текст

здесь символами «_» обозначены пробелы, и вы дадите команду:

s/x_*y/x_y/

то первые символы xy подходят под указанный шаблон, так как между ними нулевое количество пробелов. В результате замена будет выполнена только над первыми символами xy. Чтобы обойти это, достаточно записать шаблон в виде:

/x__*y/

Page 108:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Такая запись означает: x, пробел, затем еще любое количество пробелов и символ y.

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

s/x*/y/g

выполненная над строкой:

abcdef

изменит ее на:

yaybycydyeyfy

Это происходит поскольку данная команда заменяет все последовательности x нулевой длины на y. Если вы не хотите, чтобы это происходило, укажите команду следующим образом:

s/xx*/y/g

Здесь шаблон xx* определяет один или более символ x.

Квадратные скобки: [ и ]

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

1,$s/^1*//1,$s/^2*//1,$s/^3*//

и т.д., но ясно, что это займет много времени, особенно, если числа довольно большие. Редактор ed позволяет выполнить задачи такого типа с помощью одной команды, использующей квадратные скобки.

Конструкция:

[0123456789]

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

1,$s/^[0123456789]*//

Внутри символьного класса можно задавать любые символы. Только символы ^, ] и - сохраняют свое специальное значение. Чтобы найти специальные символы, вы можете, например, дать команду:

/[.\$^[]/

Перечислять в символьном классе все нужные вам цифры или символы довольно утомительно. В ed есть возможность использования сокращений, например: [0-9] — означает все цифры, [a-z] — все строчные буквы, [A-Z] — все прописные буквы.

Внутри квадратных скобок символ [ не является специальным. Чтобы поместить символ ] или - в символьный класс, необходимо указывать их в нем первыми.

Вы можете также задать символьный класс, определяющий все символы, за исключением указанных. Это делается заданием в качестве первого символа символьного класса знака ^.

Page 109:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Например, шаблон:

[^0-9]

означает все символы, за исключением цифр. Таким образом вы можете, например, найти строку, которая не начинается с пробела или символа табуляции:

/^[^(пробел)(символ табуляции)]/

Внутри символьного класса символ ^ имеет специальное значение только, если стоит первым. Проверьте, что команда:

/^[^^]/

находит строку, не начинающуюся с символа ^.

Амперсанд: &

Чтобы сократить время на ввод команд замены, можно использовать амперсанд для обозначения текста, указанного в левой части команды замены. Предположим, у вас есть строка:

Настало время

и вы хотите привести ее в такой вид:

Настало лучшее время

Вы можете ввести команду:

s/Настало/Настало лучшее/

Слово Настало повторять необязательно. Амперсанд & заменяет его. Амперсанд, указанный в правой части команды замены, обозначает текст, который только что был найден. Таким образом, вы можете давать команду в виде:

s/Настало/& лучшее/

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

s/.*/(&)/

В правой части команды замены амперсанд может встречаться более одного раза. Например, команда:

s/Настало/& лучшее время\. & худшее время/

изменит текст на:

Настало лучшее время. Настало худшее время

А команда:

s/.*/&?&!!/

превратит строку в:

Настало время? Настало время!!

Page 110:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Чтобы отменить специальное значение амперсанда, используйте перед ним бэкслэш, например:

s/амперсанд/\&/

заменяет слово амперсанд на символ &. Амперсанд не является специальным символом, когда употребляется в левой части команды замены.

Деление строк

В редакторе ed есть возможность разбиения строки на две или более строк путем вставки новых строк. Предположим, например, что в результате редактирования строка стала слишком длинной. Если она выглядит, скажем, так:

. . . текст xy текст . . .

то вы можете разделить ее между x и y командой:

s/xy/x\y/

Это одна команда, хоть и вводится на двух строках. Поскольку бэкслэш отменяет специальное значение символов, то знак конца строки перестает иметь специальное значение.

При желании вы можете разделить одну строку на несколько строк, используя этот же прием. В качестве примера рассмотрим случай, когда нужно выделить в тексте слово очень наклонным шрифтом, для чего приведем его в отдельной строке и предварим командой форматирования .I. Предположим, первоначальный вид строки следующий:

очень большой текст

Команда:

s/ очень /\.I\очень\/

разбивает строку на четыре меньшего размера, располагает перед словом очень строку .I и убирает лишние пробелы.

Когда в строку подставляется новая строка, то текущей становится последняя созданная строка.

Объединение строк

Строки могут быть объединены с помощью команды j. Предположим, у вас есть строки:

Настало время

и текущей является первая из них. Тогда команда:

j

соединяет их вместе и мы получаем:

Настало время

Page 111:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Указанная без параметров, команда j соединяет текущую и следующую за ней строку. Но можно соединить любую последовательность строк. Для этого достаточно указать начальный и конечный номера строк, которые хотите объединить, например, команда:

1,$jp

соединяет все строки в файле в одну большую строку и выводит затем ее на экран.

Перестановка текста внутри строки: \( и \)

Вспомним, что & является сокращением для текста, подлежащего замене в команде замены. Примерно таким же образом можно помечать найденные части строки. Единственное отличие заключается в том, что вы должны в левой части команды указывать, какие части вас интересуют.

Предположим, у вас есть файл, строки которого состоят из фамилий и инициалов такого типа :)

Плотский-Поцелуев, В.И.Медуза-Горгонер, С.

Это можно сделать с помощью обычных команд редактирования, но это утомительно и возможны ошибки. Альтернативный способ предлагает сначала пометить конкретные части строк (в нашем случае фамилии и инициалы), а затем переставить их. Если в левой части команды замены часть искомого текста находится между \( и \), то он запоминается и затем может быть использован в правой части команды. В правой части команды замены символы \1 относятся тексту, заключенному между первыми знаками \( и \), \2 — к следующему и т.д.

Команда:

1,$s/^\([.*]\),*\(.*\)/\2\1/

хоть и довольно неудобочитаемая, но все же выполняющая требуемые действия. Первые знаки \( и \) находят и запоминают фамилию, которая является текстом до запятой. В правой части команды замены к фамилии обращаются с помощью \1. Вторые знаки \( и \) выделяют инициалы и они обозначены в правой части как \2.

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

Повышение скорости редактирования

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

Например, если вы дадите команду поиска типа:

/штучка/

то окажетесь на следующей строке, содержащей слово штучка. Вам не потребуется указывать номер строки для таких команд как s, p, l, d, a или с, если вы хотите работать именно с этой строкой.

Если не найдено вхождений слова штучка, то значение текущей строки не изменяется.

Page 112:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Текущая строка также не изменяется, если курсор уже показывал на единственное в файле слово штучка. Эти же правила действуют и при использовании ?...?; различие заключается только в направлении поиска.

После выполнения команды удаления d текущей становится строка, следующая после удаляемой. Если же вы удаляете последнюю строку файла (т.е. с номером $), то текущей становится новая последняя строка.

Команды а, с и i, по умолчанию работают с текущей строкой. Если вы в этих командах не указываете номер строки, то команда а добавляет текст после текущей строки, команда с изменяет текущую строку и команда i вставляет текст перед текущей строкой.

Общим у этих команд является то, что после их выполнения текущей становится строка, которая вводилась последней.

Например, вы можете ввести:

a. . . текст . . .botch # в этом месте опечатка.s/botch/bitch/ # исправляем опечаткуa. . . текст . . ..

не указывая никаких номеров строки ни в команде замены, ни в команде добавления. Если вы сделали много ошибок при вводе, то можете исправить их такими командами:

aвводимый текстstubid botch # в этом месте много ошибок.с # заменяем всю строку целикомисправленная строка.

Команда r считывает текст из файла в конец буфера редактируемого вами текста, если вы не указываете номер строки, после которой надо вставить текст файла. В любом случае текущей становится последняя считанная строка. Помните, что вы можете дать команду:

0r

которая поместит содержимое файла в начале вашего текста. Вы также можете использовать 0a или 1i для добавления текста в начало буфера.

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

/^\.AB/,/^\.AE/w абстрактно

Основное правило при работе следующее: текущей всегда становится последняя измененная строка; если строки не изменялись, то и текущая строка остается прежней. Чтобы проиллюстрировать это, предположим, что в буфере имеется три строки и текущей является вторая:

x1x2

Page 113:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

x3

Тогда по команде:

-,+s/x/y/p

будет выведена третья строка, которая является последней строкой, в которую вносились изменения. Но если бы наши строки были другими:

x1y2y3

и вы дали ту же самую команду, то изменена и выведена была бы только первая строка и она же стала бы текущей.

Точка с запятой: ;

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

.

.

.ab...bc...

Если вы находитесь на первой строке и захотите распечатать все строки между ab и bc с помощью команды:

/a/,/b/p

то у вас ничего не получится. Оба поиска (и для a и для b) выполняются одновременно, и, следовательно, оба найдут строку с ab. В результате будет напечатана только одна эта строка. Более того, если перед строкой с ab была бы строка, содержащая b, тогда при выполнении этой команды была бы ошибка, так как второй номер строки оказался бы меньше, чем первый в команде печати. Это происходит из-за того, что запятая, разделяющая номера строк, не меняет номер текущей строки после определения адреса строки в команде, каждый последующий поиск начинается с того же самого места, что и предыдущий. В редакторе ed знаком «точка с запятой» можно пользоваться также, как и обычной запятой. Единственная разница заключается в том, что редактор, дойдя при выполнении командной строки до точки с запятой принудительно делает текущей строку, обработанную последней. Так, в нашем примере команду следовало записать так:

/a/;/b/p

и тогда после того, как будет найдена буква а, строка с ней станет текущей и поиск буквы b начнется уже с этой строки. Это свойство очень полезно в следующих ситуациях:

Предположим, вы хотите найти в тексте место, где второй раз встречается слово штучка. Вы можете, конечно, ввести:

Page 114:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

/штучка///

но при этом будет распечатана и первая строка с штучка, что вам не требовалось. Правильная команда:

/штучка/;//

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

?текст?;??

Помните, что если вы хотите найти место, где в файле впервые встречается какое-нибудь интересующее вас слово, недостаточно ввести команду:

1;/штучка/

так как если слово штучка находится в первой строке, то оно не будет найдено. Команда:

0;/штучка/

выполняет поиск начиная с первой строки. Это один из немногих случаев, когда 0 разрешается использовать в качестве номера строки.

Прерывание команд

Последнее замечание, касающееся установления текущей строки. Если вы нажмете клавишу Del во время выполнения редактором ed команды, ваш файл будет восстановлен до состояния, которое он имел до начала выполнения этой команды (в максимально возможной степени). Естественно, некоторые изменения восстановить нельзя. Например, если вы считываете или записываете файл, делаете подстановки или удаляете строки, то эти команды могут быть остановлены в непредсказуемом месте (именно поэтому не рекомендуется прерывать их). Текущая строка может остаться прежней.

Если вы используете команду печати, то текущая строка не изменяется до тех пор, пока команда не будет завершена. Таким образом, если вы решите выводить текст на экран до тех пор, пока не появится интересующая вас строка и затем нажмете на клавишу Del, чтобы прекратить вывод, то текущая строка не будет переопределена.

Файлы

Вставка одного файла в другой

Предположим, у вас есть файл с именем memo, и вы хотите вставить другой файл с именем table сразу после ссылки в тексте на Табл. 1. Таким образом в файле memo есть где-то строка:

Табл. 1 показывает ...

и данные, хранящиеся в файле table, должны быть помещены после этой строки. Чтобы сделать это, найдите в редактируемом файле memo текст Табл. 1 и добавьте в буфер прямо после этого файл table:

ed memo/Табл\. 1/................ # в этой строке ответ редактора ed.r table

Page 115:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Запись части файла

Другой задачей является запись в файл части редактируемого вами буфера. Например, вы хотите вывести таблицу из предыдущего примера в отдельный файл, чтобы ее можно было проверить и отформатировать отдельно. Предположим, что в редактируемом файле есть такие строки:

.TS[ текст таблицы ].TE

так описывается таблица для программы tbl (препроцессор troff). Чтобы вывести таблицу в отдельный файл, необходимо найти начало таблицы (строка с .TS) и затем записать интересующую часть. Например,

/^\.TS/

На экране появится найденная строка:

.TS

Теперь введите:

.,/^\.TE/w table

и задача будет выполнена. Вы можете все это сделать сразу с помощью команды:

/^\.TS/;/^\.TE/w table

Обратите внимание на то, что здесь команда w записывает группу строк, а не весь файл. При желании вы можете записать всего одну строку; для этого достаточно указать только один номер вместо двух. Если у вас есть какая-либо сложная строка и вы знаете, что она вам впоследствии еще понадобится, то ее проще сохранить, чем вводить вновь. Например, находясь в редакторе, введите:

a[ какой-нибудь текст]сложная строка..w tempa[ еще какой-нибудь текст]..r tempa[ еще какой-нибудь текст].

Макрокоманды редактирования

Если какая-либо сложная последовательность редактирующих команд должна быть выполнена над группой файлов, то самый простой способ — это создать «список команд редактирования» (т.е. файл, содержащий все команды, которые вы хотите выполнить) и затем применять этот список к каждому файлу по очереди.

Page 116:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Например, предположим, вы хотите заменить все «UNIX» на «Unix» и все «США» на «Америка» в большом количестве файлов. Поместите следующие строки в файл es (от ed script):

g/UNIX/s//Unix/gg/США/s//Америка/gwq

Теперь вы можете вводить:

ed -файл1< esed -файл2< es...

Эта команда указывает редактору ed выполнять команды из заранее подготовленного файла с именем es. Помните, что вся работа должна быть заранее спланирована и что, используя оболочку Plan 9, вы можете организовать цикл по нужным файлам. Опция минус - подавляет сообщения от редактора.

При подготовке списка редактирующих команд вам может потребоваться поместить в строке только один единственный символ точки для обозначения конца ввода по командам a и i. Находясь в редакторе ed это сделать довольно трудно, так как точка, которую вы наберете, завершит ваш ввод и не будет помещена в файл. Обратная черта специального значения точки не отменяет. Единственным способом является использование символа @ для обозначения конца ввода. Затем позднее укажите для замены этого символа @ на точку команду:

s/^@$/./

Краткое описание команд

Ниже приводится полный список команд редактора ed. Основной синтаксис команд редактора следующий: один или два необязательных номера строк, имя команды, и в случае команд e, f, r и w еще указывается имя файла. На строке может быть только одна команда, но команда p может указываться после любой команды (кроме e, f, r, w и q).

Команда Описание

a Добавляет строки в буфер (если не указан номер строки, то вставляет их после текущей строки). Добавление прекращается после ввода на новой строке символа точки. Текущей становится последняя добавленная строка.

c

Заменяет указанные строки на вводимый позднее текст. Ввод новых строк прекращается после ввода точки также как в команде а. Если номер строки не указан, то заменяется текущая строка. Текущей становится последняя добавленная строка.

d

Удаляет указанные строки. Если не указан номер строки, то удаляется текущая строка. Текущей после этого становится следующая после удаленной строка. Если была удалена последняя строка, то текущей становится стоявшая перед ней строка.

e Редактирует новый файл. Все предыдущее содержимое буфера уничтожается, поэтому сначала сохраните его командой w.

E Безусловная e; смотрите ниже описание q.

f Выводит на экран имя файла, которое помнит редактор. Если после f указать имя, то редактор запомнит его.

Page 117:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

g Команда g/регулярное выражение/команды выполняет команды над строками, в которых найдено совпадения с запросом регулярных выражений.

i

Вставляет строки в буфер перед указанной строкой (если номер строки не указан, то вставляет их перед текущей строкой) до тех пор пока не будет введен на новой строке символ точки .. Текущей становится последняя добавленная строка.

j Выполняет объединение указанных строк. Промежуточные символы новой строки удаляются. Текущей стает результирующая строка.

k Присваивает адресуемой строке метку. Текущая строка не изменяется.

l Выводит на экран строки, делая видимыми непечатаемые символы и знаки табуляции. В остальном одинакова с командой p.

m Перемещает указанные строки после строки с номером, указанным после символа команды m. Текущей становится последняя перемещенная строка.

n Команда нумерации выдает указанные строки, предваряя каждую номером строки и символом табуляции; текущей становится последняя выданная строка. Команду n можно добавлять к любой команде, кроме e, f, r и w.

p

Выводит указанные строки. Если номера строк не указаны, то печатает текущую строку. Один номер строки без символа p эквивалентен команде. При простом нажатии клавиши Enter печатается следующая после текущей строка.

P Синоним для p.

q Выход из редактора. Ваша работа не будет сохранена, если вы не дадите команду w. Введите команду дважды, если вы в любом случае хотите покинуть редактор.

Q Выход из редактора без проверки, были ли сделаны изменения в буфере с момента выполнения последней команды w.

r Считывает файл в буфер (до конца, если не указано до какого места). Текущей становится последняя считанная строка.

s

Команда s/шаблон/замена/ заменяет последовательность символов замена при совпадении с шаблоном в указанных строках. Если номера строк не указаны, то замена производится только в текущей строке. Текущей остается строка, в которой замена была сделана последней. Если замены не было (т.е. нет совпадения с шаблоном в указанных строках), то текущей остается прежняя строка. Команда s заменяет только первое вхождение текста шаблона в строке; чтобы заменить все имеющиеся в строке вхождения, надо указывать после последней косой черты символ g.

t Копирует указанные строки после строки, номер которой стоит после символа t в команде. Текущей становится последняя скопированная строка.

v Команда v/регулярное выражение/список команд выполняет заданные команды только в тех строках, в которых нет последовательности символов шаблона.

u Восстанавливает предыдущее содержимое первой адресуемой строки, которая должна быть последней строкой в которой была выполнена подстановка.

w Записывает буфер редактирования в файл. Текущая строка не изменяется.

W Эта команда аналогична описанной выше команде записи, за исключением того, что добавляет указанные строки в конец файла, если он существует. Если файл не существует, он создается, как описано выше для команды w.

Page 118:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

= Выводит на экран номер текущей строки.!команда Выполнение команды операционной системы Plan 9.

/шаблон/ Контекстный поиск по шаблону. Текущей становится строка, в которой найден указанный шаблон. Начинается со строки .+1.

?шаблон?

Контекстный поиск в обратном направлении. Начинается со строки .-1.

Примечание

Примечание касается авторства документа. Мне, Андрею Кухару, принадлежит адаптация и компиляция существующих источников, представляющих описание редактора. За основу был взят перевод 3-й главы руководства пользователя по ОС Unix (System V/386) «Строчный текстовый редактор ed» Брайана Кернигана (Brian Kernighan), автор перевода неизвестен.

Copyright © 2003 Андрей С. Кухар.

Page 119:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Прикладная поддержка новой архитектуры в Plan 9

Боб Фландрена[email protected]

Введение

В Plan 9 есть пять классов архитектуро-зависимого ПО: заголовки, ядра, компиляторы и загрузчики, системная библиотека libc, и несколько прикладных программ. В общем, архитектуро-зависимые программы состоят из портабельной части, распространяемой на все архитектуры, и процессоро-специфичной — для каждой поддерживаемой архитектуры. Часто портабельный код компилируется и сохраняется в библиотеке, ассоциированной с архитектурой. Формирование программы осуществляется посредством компиляции архитектуро-специфичной части кода и ее загрузки вместе с библиотекой. Поддержка новой архитектуры обеспечивается построением компилятора, его использованием для компиляции портабельного кода в библиотеки, написанием архитектуро-специфичного кода, и последующей загрузкой этого кода вместе с библиотеками.

В этом документе описана организация архитектуро-зависимого кода и заголовков в Plan 9. Первый раздел кратко обсуждает формат заголовков и исходного кода ядра, компиляторов, загрузчиков и системной библиотеки libc. Во втором разделе детально раскрывается структура libmach — библиотеки, содержащей почти весь архитектуро-зависимый код, который используется прикладными программами. Последний раздел описывает действия, необходимые при добавлении прикладной программной поддержки для новой архитектуры.

Структура каталогов

Архитектуро-зависимая информация для нового процессора находится в каталоге /m, где m (от machine) соответствует имени новой архитектуры (например, как mips). Новый каталог должен быть проинициализирован с несколькими важными подкаталогами, особенно с bin, include и lib. Дерево каталогов существующей архитектуры служит хорошей моделью для нового дерева. Архитектуро-зависимый mkfile должен быть размещен в ново созданном корневом каталоге архитектуры. Легче всего скопировать mkfile уже существующей архитектуры и модифицировать его для новой архитектуры. Если mkfile корректный, то для соответствия новой архитектуре вам следует лишь изменить переменные OS и CPUS в /sys/src/mkfile.proto.

Заголовки

Архитектуро-зависимые заголовки хранятся в каталоге /m/include. Обязательны два заголовочных файла: u.h и ureg.h. В первом описаны фундаментальные типы данных, настройки бит для статуса плавающей запятой и управляющих регистров, и обработка va_list, которая зависит от стековой модели архитектуры. Сформировать этот файл лучше всего, скопировав и модифицировав файл u.h из архитектуры со схожей стековой моделью. Файл ureg.h содержит структуру, описывающую формат набора регистров архитектуры; он определяется ядром.

В заголовочном файле /sys/include/a.out.h находятся определения магических чисел, используемых для идентификации исполняемых файлов для каждой архитектуры. После того как поддержка для новой архитектуры добавлена, в этот файл должно быть добавлено ее

Page 120:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

магическое число.

Формат заголовка загрузочных исполняемых файлов определяется производителем. Заголовочный файл /sys/include/bootexec.h содержит структуру, в которой описаны поддерживаемые заголовки. Если новая архитектура использует общий заголовок, наподобие COFF, то формат заголовка вероятно уже был определен, но если формат заголовка загрузчика не отвечает стандарту, то структура, определяющая формат, должна быть добавлена в этот файл.

Ядро

Хотя ядро критически зависит от свойств используемого оборудования, большая часть высокоуровневых функций ядра, включая управление процессами, подкачку, псевдо-устройства и немного сетевого кода, — независимы от процессорной архитектуры. Портабельный ядерный код разделен на две части: те, что реализуют ядерные функции, и те, что отвечают за процесс загрузки. Код первого класса хранится в каталоге /sys/src/9/port, а портабельный загрузочный код в /sys/src/9/boot. Архитектуро-зависимый код ядра находится в подкаталогах /sys/src/9 каждой архитектуры.

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

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

Компиляторы и загрузчики

Исходный код компилятора соответствует обычной организации: портабельный код компилируется в библиотеку для каждой архитектуры и архитектуро-зависимый код загружается вместе с библиотекой. Общий код компилятора размещен в каталоге /sys/src/cmd/cc. Mkfile в этом каталоге компилирует портабельный исходный код и архивирует объекты в библиотеке для каждой архитектуры. Архитектуро-специфичный код компилятора размещен в подкаталоге /sys/src/cmd с соответствующим именем (как например, /sys/src/cmd/vc).

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

Библиотеки

Большинство модулей библиотеки C являются портабельными; исходный код находится в каталогах /sys/src/libc/port и /sys/src/libc/9sys. Архитектуро-зависимый код библиотеки размещен в подкаталоге /sys/src/libc и имеет схожее с целевым процессором название. Не-портабельные функции выполняют не только архитектуро-зависимые операции, но также обеспечивают реализации функций на языке ассемблера, где скорость критична.

Page 121:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Каталог /sys/src/libc/9syscall — необычен, поскольку он содержит архитектуро-зависимую информацию для всех архитектур. В нем хранятся заголовочный файл с описанием имен и номеров системных вызовов, и mkfile. Mkfile запускает сценарий rc, который выполняет синтаксический анализ заголовочного файла, создает функции языка ассемблера, реализующие системный вызов для каждой архитектуры, формирует код, и архивирует объектные файлы в libc. Синтаксис языка ассемблера и системный интерфейс различаются для каждой архитектуры. Для поддержки новой архитектуры сценарий rc в этом mkfile должен подвергнуться модификации.

Приложения

Прикладные программы обрабатывают две формы архитектуро-зависимой информации: исполняемые образы и промежуточные объектные файлы. Почти вся работа приходится на исполняемые файлы. Системная библиотека libmach обеспечивает функции, которые преобразовывают архитектуро-специфичные данные в портабельный формат, так что прикладные программы могут обрабатывать эти данные независимо от основного представления. Далее, когда новая архитектура реализована, почти все изменения кода ограничиваются библиотекой; наиболее пораженные прикладные программы требуют лишь перезагрузки. Исходный код для библиотеки находится в /sys/src/libmach.

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

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

• Интерпретация заголовка. • Интерпретация символьной таблицы. • Выполнение контекстной интерпретации, наподобие трассировок стека и позиций

стекового фрейма. • Интерпретация команд, включая дизассемблирование и размер команды и

последующие вычисления. • Интерпретация исключений и чисел с плавающей запятой. • Архитектуро-независимый доступ на чтение и запись через карту перемещений.

Заголовочный файл /sys/include/mach.h определяет интерфейсы для прикладной библиотеки. Детали библиотечных функций описаны в man-страницах mach (2) , symbol (2) и object (2) .

Две структуры данных под названиями Mach и Machdata содержат архитектуро-зависимые параметры и функции таблицы переходов. Глобальные переменные mach и machdata указывают на структуры данных Mach и Machdata, связанные с целевой архитектурой. Приложение определяет целевую архитектуру файла или исполняемых образов, устанавливает глобальные указатели на структуры данных, ассоциированные с этой архитектурой, и впоследствии выполняет все действия косвенно через указатели. Как результат, непосредственные указания на таблицы для каждой архитектуры аннулированы и прикладной код внутренне поддерживает все архитектуры (но только поочередно).

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

Page 122:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Разделение архитектуро-зависимой информации между структурами данных Mach и Machdata позволяет приложениям выбирать соответствующий уровень сервиса. Приложение даже не ссылается непосредственно на архитектуро-специфичные структуры данных, оно должно загружать архитектуро-зависимые таблицы и код для всех поддерживаемых архитектур. Размер этих данных может быть постоянным, большинство приложений не требуют полной области архитектуро-зависимой функциональности. К примеру, команда size не требует дизассемблеров для каждой архитектуры; ей лишь необходимо декодировать заголовок. Структура данных Mach содержит несколько архитектуро-специфичных параметров и описание набора регистров процессора. Хотя размер структуры изменяется в зависимости от размера набора регистров, обычно он не велик. Структура данных Machdata содержит таблицу переходов архитектуро-зависимых функций; объем кода и данных, указанных в этой таблице, обычно достаточно большой.

Организация исходного кода libmach

Библиотека libmach представляет четыре класса функциональности:

Декодирование заголовка и символьной таблицы Файлы executable.c и sym.c содержат код для интерпретации заголовочной и символьных таблиц исполняемых файлов или исполняемого образа. Функция crackhdr декодирует заголовок, реформатирует информацию в структуру данных Fhdr, и направляет глобальную переменную mach на структуру данных Mach целевой архитектуры. Для декодирования символьной таблицы используются данные в структуре Fhdr. Ряд функций доступа к символьной таблице затем поддерживает запросы к реформатированной таблице.

Поддержка отладчика Файлы m.c, где m — кодовая буква, присвоенная архитектуре, содержат инициализированную структуру данных Mach и определение набора регистров для каждой архитектуры. Архитектуро-специфичный отладчик, поддерживающий функции и проинициализированную структуру Machdata, собраны в файлах mdb.c. Файлы machdata.c и setmach.c содержат функции поддержки отладчика, совместно используемые многочисленными архитектурами.

Архитектуро-независимый доступ Файлы map.c, access.c и swap.c обеспечивают доступы посредством карты перемещений к данным в исполняемом файле или исполняемом образе. При необходимости выполняется байт-свопинг. Глобальные переменные mach и machdata должны указывать на структуры данных Mach и Machdata целевой архитектуры.

Интерпретация объектных файлов Эти файлы содержат функции идентификации целевой архитектуры промежуточного объектного файла и извлечения указателей на символы. Файл obj.c содержит общий для всех архитектур код; mobj.c содержит архитектуро-специфичный исходный код для машины с кодовым символом m.

Структура данных Machdata первоначально является таблицей переходов архитектуро-зависимых функций поддержки отладчика. Функции выбирают структуру Machdata для целевой архитектуры, основанной на значении типа кода в структуре Fhdr или имени архитектуры. Таблица переходов обеспечивает функции обмена байт, интерпретацию машинных команд, выполняет трассировки стека, поиск стековых фреймов, форматирует числа с плавающей запятой, и декодирует машинные исключения. Некоторые функции, такие

Page 123:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Добавление прикладной поддержки для новой архитектуры

В этом разделе описаны действия, необходимые для добавления поддержки прикладного уровня для новой архитектуры. Предполагается, что ядро, компиляторы и системные библиотеки для новой архитектуры уже на своих местах. При этом подразумевается, что кодовый символ присвоен и архитектуро-специфичные заголовки обновлены. За исключением двух программ, изменения в прикладном уровне ограничены заголовочными файлами и исходным кодом в /sys/src/libmach.

1. Начните с обновления заголовочного файла прикладной библиотеки в /sys/include/mach.h. Добавьте следующие символьные коды в оператор enum ближе к началу файла:

• Код типа процессора, например, MSPARC. • Тип исполняемого файла. Обычно необходимы два кода: один для загрузочного

исполняемого файла (т.е., ядра) и один для прикладного исполняемого файла. • Тип кода дизассемлера. Добавьте по одному элементу для каждого поддерживаемого

дизассемблера для архитектуры. • Символьный код для объектного файла.

2. В имени файла /sys/src/libmach/m.c (где m — идентификационный символ, присвоенный архитектуре), инициализируйте структуры данных Reglist и Mach со значениями, определяющими набор регистров и различные параметры системы. Исходный файл для схожей архитектуры может служить шаблоном. Большая часть полей в структуре данных Mach очевидны, но некоторые все-же требуют дальнейшего объяснения.

kbase Поле содержит адрес ublock. Отладчики принимают первый элемент ublock, указывающего на структуру Proc для нити ядра.

ktmask Битовая маска для вычисления текстового адреса ядра из адреса ublock. Первая страница текстового сегмента ядра вычисляется путем выполнения бинарной операции И над отрицанием этой маски с kbase.

kspoff Содержит смещение байт в структуре данных Proc к сохраненному указателю на стек ядра для приостановленной нити ядра. Это смещение до поля sched.sp элемента таблицы Proc.

kpcoff Содержит смещение байт в структуре данных Proc программного счетчика приостановленной нити ядра. Это смещение до поля sched.pc в этой структуре.

kspdelta и kpcdelta Эти поля содержат коррекции, которые добавляются к указателю стека и программному счетчику, соответственно, к правильному расположению стека и следующей команде нити ядра. Эти значения смещают сохраненные регистры, извлеченные из структуры Label под названием sched в структуре данных Proc. Большинство архитектур не требуют смещения и эти поля содержат нули.

Page 124:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

scalloff Содержит смещение байт поля scallnr в структуре данных ublock, связанной с процессом. Поле scallnr содержит номер последнего системного вызова, выполненного процессом. Расположение поля изменяется в зависимости от размера набора регистров с плавающей запятой, которые следуют за ним в ublock.

3. Добавьте элемент в инициализацию структуры данных ExecTable в начале файла /sys/src/libmach/executable.c. Большинство архитектур требуют два элемента: один для нормального исполняемого файла и один для загрузочного образа. Каждый элемент таблицы содержит:

• Магическое число — магическое число big-endian, присвоенное архитектуре в /sys/include/a.out.h.

• Имя — строка, описывающая исполняемый файл. • Тип кода исполняемого файла — код исполняемого файла, присвоенный в /sys/include/mach.h.

• Указатель Mach — адрес инициализированной структуры данных Mach, созданной во втором действии. Вы должны также добавить название этой таблицы в список определений таблицы Mach немедленно предшествующий инициализации ExecTable.

• Размер заголовка — количество байт в исполняемом файле заголовка. Размером нормального исполняемого заголовка обычно служит sizeof(Exec). Размер загружаемого заголовка определяется размером структуры для архитектуры, описанной в /sys/include/bootexec.h.

• Функция байт-свопинга — адрес beswal или leswal для архитектур big-endian и little-endian, соответственно.

• Функция декодера — адрес функции, декодирующей заголовок. Функция adotout декодирует общий заголовок, совместно используемый всеми нормальными (т.е., не-загрузочными) исполняемыми файлами. Формат заголовка загрузочных исполняемых файлов определяется производителем и для их декодирования почти всегда требуется специальная функция. Заголовочный файл /sys/include/bootexec.h содержит структуры данных, описывающие загрузочные заголовки для всех архитектур. Если новая архитектура использует существующий формат, то подходящая декодирующая функция должна уже быть в executable.c. Если формат заголовка уникален, тогда в этот файл должна быть добавлена новая функция. Обычно декодирующая функция для существующей архитектуры может быть адаптирована с незначительными модификациями.

4. Напишите синтаксический анализатор объектных файлов и сохраните его в файле /sys/src/libmach/mobj.c, где m является символом-идентификатором, который присвоен архитектуре. Необходимы две функции: предикат для идентификации объектного файла для архитектуры и функция извлечения символьных указателей из объектного кода. Формат объектного кода затемнен, но часто есть возможность адаптации кода существующей архитектуры с незначительными модификациями. Когда эти функции под рукой, вставьте их адреса в таблицу переходов в начале файла /sys/src/libmach/obj.c.

5. Реализуйте требуемые функции поддержки отладчика и инициализируйте параметры и таблицу переходов структуры данных Machdata. Этот код обычно размещается в файле /sys/src/libmach/mdb.c. Поля архитектуры таковы:

bpinst и bpsize Содержат команду точечного разрыва (breakpoint) и размер команды, соответственно.

swab Содержит адрес функции для обмена байт 16-битным значением. Выберите leswab

Page 125:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

или beswab для архитектуры little-endian или big-endian, соответственно. swal

Содержит адрес функции обмена байт 32-битным значением. Выберите leswab или beswab для архитектуры little-endian или big-endian, соответственно

ctrace Содержит адрес функции трассировки стека (язык C). Две общих функции трассировки, risctrace и cisctrace, просмотр фиксированно-фреймового и относительно-фреймовых стеков, соответственно. Если компилятор для новой архитектуры подходит для одной из этих моделей, тогда выберите необходимую. Если модель стека уникальна, то придется обеспечить специальную функцию трассировки стека.

findframe Содержит адрес функции расположения стекового фрейма, ассоциированного с текстовым адресом. Общие функции riscframe и ciscframe обрабатывают модели фиксированно-фреймового и относительно-фреймового стеков.

ufixup Содержит адрес функции регулировки базового адреса регистровой области сохранения. К настоящему времени, лишь 68020 требует это смещение выше фрейма активного исключения.

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

bpfix Содержит функцию регулировки адреса до формулирования точечного разрыва.

sftos Содержит адрес функции преобразования значения с плавающей запятой одинарной точности в строку. Выберите leieeesftos для little-endian или beieeesftos для big-endian.

dftos Содержит адрес функции преобразования значения с плавающей запятой двойной точности в строку. Выберите leieeedftos для little-endian или beieeedftos для big-endian.

foll, das, hexinst и instsize Эти поля указывают на функции интерпретации машинных команд. Они полагаются на дизассемблирование команды и уникальны для каждой архитектуры. Foll вычисляет следующий набор команд. Das дизассемблирует машинную команду в язык ассемблера. Hexinst форматирует машинную команду как текстовую строку шестнадцатеричных цифр. Instsize вычисляет размер команды в байтах. Как только дизассемблер написан, другие функции могут быть реализованы как его тривиальные расширения.

Есть возможность предоставления поддержки для новой архитектуры пошагово путем заполнения элементов таблицы переходов структуры Machdata как написанного кода. В общем, если элемент таблицы переходов содержит нуль, то прикладная программа, требующая эту функцию, будет производить сообщение об ошибке взамен попытки вызова функции. К примеру, слоты таблицы переходов: foll, das, hexinst и instsize могут быть обнулены, пока не написан дизассемблер. Другие возможности, такие как трассировка стека или проверка переменных, могут быть обеспечены и будут доступны отладчикам, но попытка использовать дизассемблер будет результировать с сообщением об ошибке.

6. Обновите таблицу machines ближе к началу /sys/src/libmach/setmach.c. Эта таблица связывает код типа файла и имя машины в структурах Mach и Machdata архитектуры. Имена инициализированных структур Mach и Machdata, сформированных в

Page 126:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

действиях 2 и 5, должны быть добавлены к списку структурных определений непосредственно следующие за таблицей инициализации. Если оба Plan 9 и исконное дизассемблирование поддерживаются, тогда добавьте в таблицу элемент для каждого дизассемблера. Элемент для дизассемблера по-умолчанию (обычно Plan 9) указывается первым.

7. Добавьте элемент, описывающий архитектуру в таблицу trans ближе к концу /sys/src/cmd/prof.c.

8. Добавьте элемент, описывающий архитектуру в таблицу objtype ближе к началу /sys/src/cmd/pcc.c.

9. Перекомпилируйте и установите все прикладные программы, которые включают заголовочный файл mach.h, и загрузите вместе с libmach.a.

Copyright © 2002 Lucent Technologies Inc. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Page 127:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Файловый сервер Plan 9Кен Томпсон[email protected]

АБСТРАКТНО

В этом документе описана структуру и работа файловых серверов Plan 9. Хотя речь идет о нашем главном файловом сервере Emelie, код также является основой пользовательского уровня файлового сервера kfs.

Введение

Файловый сервер Emelie — это одна из старейших частей системного программного обеспечения, которое все еще используется в Plan 9. Он развился из пользовательской программы, которая обслуживала последовательные линии на многопроцессорной машине Sequent. Хоть текущая реализация не является ни чистой, ни портабильной, она подходит к требованиям конкретного набора компьютеров и их устройств.

Структура процессов

Сервер файловой системы Plan 9 происходит от древней версии ядра Plan 9. Ядро поддерживает: управление процессами, синхронизацию, блокировку и распределение памяти. Отсутствует реализация пользовательских процессов и виртуальной памяти.

Структура файловой системы сервера представляет собой набор процессов ядра, синхронизирующий большую часть передач сообщений. Emelie содержит 26 процессов 10-ти типов.

Количество Название Функция15 srv Главные процессы файловой системы сервера

1 rah Блочные read-ahead процессы

1 scp Процесс sync

1 wcp Копия WORM процесса

1 con Консольный процесс

1 ilo Процесс протокола IL

1 ilt Процесс таймера IL

2 ethi Процесс ввода Ethernet

2 etho Процесс вывода Ethernet

1 flo Процесс флоппи диска

Серверные процессы

Главный алгоритм файловой системы является набором идентичных процессов под общим названием srv, управляемых протоколом 9P. Каждый процесс файловой системы ожидает поступающий запрос в очереди сообщений. Запрос содержит сообщение 9P и адрес очереди ответа. Процесс srv выполняет синтаксический анализ и разбор сообщения, перемещает псевдо-дисковый ввод-вывод в соответствующее блочное устройство файловой системы, формулирует ответ и посылает его обратно в очередь.

Блок данных в устройстве является единицей хранения:

Page 128:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

enum{ RBUFSIZE = 16*1024};

typedefstruct{ short pad; short tag; long path;} Tag;

enum{ BUFSIZE = RBUFSIZE - sizeof(Tag)};

typedefstruct{ uchar data[BUFSIZE]; Tag tag;} Block;

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

Основная структура данных процесса srv является каталоговой записью. Это эквивалент индексного дескриптора Unix, она определяет набор блочных адресов, который указывает файл это, или каталог. В отличие от индексного дескриптора, каталоговая запись также содержит имя файла или каталога:

enum{ NAMELEN = 28, NDBLOCK = 6};

typedefstruct{ char name[NAMELEN]; short uid; short gid; ushort mode; short wuid; Qid qid; long size; long dblock[NDBLOCK]; long iblock; long diblock; long atime; long mtime;} Dentry;

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

Page 129:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Запись wuid указывает идентификатор пользователя, совершившего последнюю запись, а size — размер файла в байтах. Первые 6 блоков файла занимает массив dblock. Если файл имеет больший размер, то косвенный блок распределяется таким образом, что содержит следующие BUFSIZE/sizeof(long) блоков файла. Адрес косвенного блока хранится в элементе структуры под названием iblock. Если файл еще больше, то он содержит двойной косвенный блок, указывающий на составляющие косвенные блоки. Адрес двойного косвенного блока хранится в diblock и может указывать на другие (BUFSIZE/sizeof(long))2 блоки данных. Максимальный адресуемый размер файла около 275 GB. Есть и наименьшее ограничение — 232 B, поскольку длина файла поддерживается типом long. Таким образом, даже неаккуратное использование длинных арифметик ограничивается 231 B. Эти цифры основаны на сервере Emelie, который имеет размер блока 16 KB и sizeof(long) равняется 4. Если изменить размер блока, эти цифры будут отличаться.

Описания косвенного и двойного косвенного блоков:

enum{ INDPERBUF = BUFSIZE/sizeof(long),};

typedef{ long dblock[INDPERBUF]; Tag ibtag;} Iblock;

typedef{ long iblock[INDPERBUF]; Tag dibtag;} Diblock;

Корневой каталог файловой системы — это одна каталоговая запись с известным блочным адресом. Каталог — это не что иное как файл, содержащий список содержимого каталога. Чтобы упростить доступ, блоки не могут пересекаться в каталоговой записи.

Устройство, на котором находятся блоки, является подразумеваемым и происходит от сообщения attach протокола 9P. Это сообщение определяет имя устройства, содержащего корневой каталог.

Буферный кеш

Когда загружен файловый сервер, вся не используемая память распределяется в пуле буферного кеша. В буферном пуле существует две главных операции. Getbuf выполняет поиск буфера, ассоциированного с конкретным блоком на конкретном устройстве. Возвращаемый буфер блокирован, так что вызывающий имеет исключительное использование. Если запрошенный буфер отсутствует в пуле, другой буфер подвергается переразметке и данные считываются из него. Putbuf выполняет разблокировку, если содержимое буфера обозначено как модифицированное, записывается на устройство и после этого подвергается переразметке. Если необходимо специальное распределение или сброс кеша процессора, которые должны быть выполнены посредством физического устройства ввода-вывода для доступа к буферу, то это выполняется между getbuf и putbuf. Содержимое буфера никогда не трогается, за исключением ситуации, когда он заблокирован между вызовами getbuf и putbuf.

Сервер файловой системы обходит этот тупик в буферах путем постоянной блокировки

Page 130:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Блочные устройства

Блочное устройство системы ввода-вывода является не чем иным как протокольным стеком фильтров. Существует набор псевдо-устройств, рекурсивно связанных с другими псевдо-устройствами и настоящими устройствами. Протокольный стек компилируется из конфигурационной строки, которая определяет псевдо-устройства и просто устройства. Каждое псевдо-устройство и устройство имеет набор записей, указывающих соответствия операций, которые файловая система требует от устройств. Наиболее важными операциями являются read, write и size.

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

D = (DD...) Это набор устройств, соединенных для формирования одного устройства. Размер соединенного устройства равен сумме размеров всех под-устройств.

D = [DD...] Это чередование индивидуальных устройств. Если в списке есть N устройств, тогда псевдо-устройство является N-путевым блочным чередованием под-устройств. Размер чередуемого устройства равен сумме минимального под-устройства N раз.

D = pDN1.N2 Это раздел под-устройства. Под-устройство разделено на 100 одинаковых частей. Если размер под-устройства не делим на 100, тогда на верхушку будет выброшен какой-то мусор. Псевдо-устройство начинается с N1-й части и продолжается до N2 частей. Так, pD67.33 будет последним третьим устройством D.

D = fD Это фальшивое WORM (write-once-read-many, т.е. «однократная-запись-многократное-чтение») устройство, сымитированное вторым устройством чтения-записи. Второе устройство разделено на набор блочных флагов и блоков. Флаги используются для генерации ошибок, если блок записан дважды или производится чтение без предыдущей записи.

D = cDD Это не что иное как кеш/WORM устройство, созданное кешем устройства чтения-записи и WORM устройством. Подробнее об этом чуть позже.

D = o Это файловая система dump — двухуровневая иерархия всех дампов, отправленных на кеш/WORM. Корневой каталог файловой системы кеш/WORM имеет атрибут «только для чтения» и название от даты создания, например, дамп, полученный 18 февраля 1995 года будет назван /1995/0218 в псевдо-устройстве. /1995/02181 будет вторым дампом, полученным в этот же день.

D = wN1.N2 Это SCSI диск на контроллере N1 и объект N2.

D = lN1.N2 То же, что и w, но один блок из SCSI диска перемещен для переименования.

Page 131:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

D = j(D1D2*)D3

D1 — это накопитель со сменой дисков интерфейса SCSI. D2 — это SCSI устройства в

накопителе и D3 — это демонтированные участки в накопителе. D1 и D2 должны быть

w. D3 должны быть псевдо-устройствами w или l устройств.

Для обоих устройств w и r любые номера конфигурации могут быть заменены итератором формы <N1-N2>. Так,

[w0.<2-6>]

это чередующиеся SCSI диски в SCSI объекте от 2 до 6, SCSI контроллер 0. Основная файловая система в Emelie описана следующей конфигурационной строкой:

c[w1.<0-5>.0]j(w6w5w4w3w2)l(<0-236>l<238-474>)

Это драйвер кеш/WORM. Кеш — это три чередующихся диска на SCSI контроллере 1, объекты 0, 1, 2, 3, 4 и 5. WORM-половина кеш/WORM — 474 накопителей со сменой дисков.

Процессы read-ahead

Существует набор процессов файловой системы под названием rah, он ожидает сообщения, содержащие устройство и блочный адрес. Когда поступает сообщение, процесс считывает определенный блок из устройства. Эта операция выполняется посредством вызовов getbuf и putbuf, что дает возможность использования блоков после некоторого времени их нахождения в буферном кеше. В противном случае есть вероятность, что блоки могут быть отвергнуты перед использованием.

Сообщения для процессов read-ahead генерируются специальным сервером процессов. Сервер процессов сохраняет относительную отметку блока в каждом открытом файле. Каждый раз, когда открытый файл считывает относительный блок, следующие 110 блочных адресов файла отправляются процессам read-ahead, при этом относительный блок получает метку 100. Начальный относительный блок установлен как 1. Если открыт файл и считано всего лишь несколько байтов, то дальше никаких считываний не предвидится (и не проводится), пока относительный блок установлен как 1 и считывается лишь блочное смещение 0. Это функция должна предохранять некоторые довольно общие действия, как например:

file *

захламляющие файловую систему процессами read-ahead, которые никогда не будут использованы.

Драйвер кеш/WORM

Драйвер кеш/WORM (cache/WORM — cw) является одним из самых больших и сложных драйверов устройств в файловом сервере. В него входят четыре устройства. Драйвер осуществляет чтение/запись псевдо-устройства (cw-устройства) и только чтение псевдо-устройства (dump) путем выполнения операций над своими двумя составляющими устройствами: чтение-запись c-устройство и однократная-запись-многократное-чтение w-устройство. Номера блоков на четырех устройствах достаточно точные, хотя cw адреса и w адреса — высоко согласованные.

Драйвер cw использует w-устройство как стабильное хранилище файловой системы на момент последнего дампа. Все вновь записанные и большое количество недавно использовавшихся точных копий блоков w-устройства хранятся на c-устройстве. С-

Page 132:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

устройство намного меньше по размеру чем w-устройство, таким образом подмножество w-блоков, хранящихся на c-устройстве, отображаются через хэш таблицу, которая находится на разделе c-устройства.

Часть карты c-устройства состоит из блоков групп записей. Описания приведены ниже.

enum{ BKPERBLK = 10, CEPERBK = (BUFSIZE - BKPERBLK*sizeof(long)) / (sizeof(Centry)*BKPERBLK),};

typedefstruct{ ushort age; short state; long waddr;} Centry;

typedefstruct{ long agegen; Centry entry[CEPERBK];} Bucket;

Bucket bucket[BKPERBLK];

Для каждого блока в разделе данных c-устройства есть лишь одна структура записи. Группа содержит все w-адреса, у которых одинаковый хэш код. Существует большое количество групп, которые устанавливаются в блоке. Чтобы иметь необходимое количество записей, существует достаточно блоков. Записи в группе поддерживаются в FIFO порядке с age переменной и увеличивающим age генератором. Когда age генератор доходит до переполнения, все age записи в группе масштабируются до нуля.

Следующие шаги конвертируют w-адрес в c-адрес. Группа обнаруживается при помощи:

bucket_number = w-address % total_bucketsgetbuf(c-device, bucket_offset + bucket_number/BKPERBLK);

После того как нужная группа найдена, выполняется линейный поиск записи с группой и waddr.

Штатной переменной в записи является одна из следующих:

enum{ Cnone = 0, Cdirty, Cdump, Cread, Cwrite, Cdump1,};

Каждый w-адрес имеет состояние. Блоки, которые находятся не на c-устройстве, имеют неявное состояние Cnone. Состояние Cread предназначено для блоков, которые имеют одинаковые с соответствующим блоком w-устройства данные. Так как c-устройство намного быстрее чем w-устройство, Cread блоки хранятся так долго, сколько это возможно и их

Page 133:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

использование предпочтительнее чем чтение w-устройства. Когда нужно пространство для новых данных, Cread блоки должны сбрасываться из c-устройства. Состояние Cwrite — когда c-устройство содержит данные, новей чем соответствующий блок w-устройства. Это происходит когда записано одно из состояний: Cnone, Cread или Cwrite. Состояние Cdirty — когда c-устройство содержит данные, новей чем соответствующий блок w-устройства, который никогда не был записан. Это происходит когда новый блок размещается в свободном пространстве w-устройства.

Блоки Cwrite и Cdirty создаются и никогда не удаляются. Если же выполняется операция преобразования этих блоков, c-устройство будет постепенно заполнятся и перестанет функционировать. Один раз в день, и посредством выполнения команды, берется дамп cw-устройства. Назначение дампа — поставить в очередь записи, которые были отведены c-устройством для записи на w-устройство. Так как w-устройство — это WORM, блоки не могут быть переписаны. Блоки, которые уже записаны на WORM, должны быть перемещены в неиспользуемую часть w-устройства. Это блоки с состоянием Cwrite.

Алгоритм дампа таков: а) Длина дерева на cw-устройстве зависит от того, какие посещенные блоки были модифицированы со времени последнего дампа. Это блоки с состояниями Cwrite и Cdirty. Есть возможность ограничения поиска блоков: так как в каталог, содержащий модифицируемый файл, должен произойти доступ, после модификации файла происходит установка времени модификации каталога, таким образом блок, содержащий его, — будет записан. Каталог, содержащий этот каталог, должен быть модифицирован таким же образом. Прохождение по дереву каталогов не занимает много времени. б) Все Cwrite блоки, найденные при древовидном поиске перемещаются в новые чистые блоки на w-устройстве и конвертируются в состояние Cdump. Все Cdirty блоки конвертируются в состояние Cdump без перемещения. Таким образом, все модифицированные блоки в cw-устройстве имеют w-адреса, указывающие на не записанные WORM блоки. Эти блоки отмечаются для последующей записи на w-устройство с состоянием Cdump. в) Все открытые файлы, указывающие на модифицированные блоки, открываются вновь для указания соответствующих перемещаемых блоков. Это вызывает модификации каталогов, идущих за открытыми файлами. Таким образом инвариант, обсужденный в а) обслуживается. д) Фоновый процесс дампинга медленно проходит по карте c-устройства и записывает все блоки с состоянием Cdump.

Дампу требуются считанные минуты для прохождения дерева и отметки блоков. Он может занимать часы при записи отмеченных блоков на WORM. Если отмеченный блок был перезаписан перед тем как старая копия записана на WORM, то он должен быть принудительно записан на WORM перед перезаписью. Проблемы нет, если другой дамп был взят перед тем как первый закончен. Ново отмеченные блоки добавляются к отмеченным слева от первого дампа.

Если при записи отмеченного блока на WORM происходит ошибка, то состояние дампа конвертируется в Cdump1, в такой ситуации необходимо ручное вмешательство. (Смотрите описание команды cwcmd mvstate в fs (8) ). Эти блоки могут вновь записываться, если их состояние конвертировать обратно в Cdump. Также они могут быть конвертированы в Cwrite, так что они будут занимать новые адреса в следующем дампе. В большинстве других случаев, Cdump1 блок ведет себя подобно Cwrite.

Процессы Sync Copy и WORM Copy

Процесс scp запускается каждые 10 секунд, при этом данные записываются в блоки буферного кеша, которые должны быть модифицированы. Это происходит автоматически в важных консольных командах типа halt и dump.

Процесс wcp также запускается каждые 10 секунд и пробует копировать dump блок из кеша

Page 134:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

в WORM. Копирование происходит на высокой скорости так как копируются dump блоки и нет конкуренции за WORM устройство. Если же есть конкуренция за WORM устройство или больше нет блоков для копирования, процесс переходит в режим ожидания на 10 секунд перед следующим просмотром.

Устройство с автоматической сменой дисков HP WORM состоит из 238 дисков, разделенных на 476 сторон или участков. Участок 0 — это сторона А диска 0. Участок 1 — это сторона А диска 1. Участок 238 — это сторона В диска 0. В Emelie главная файловая система сконфигурирована на обоих сторонах первых 237 дисков, участков 0-236 и 238-474.

Драйверы протокола 9P

Чтобы появиться в своей очереди ввода, описанный файловый сервер находится в ожидании сообщений протокола 9P. Он обрабатывает каждое сообщение и отправляет ответ создателю. Существуют группы процессов, выполняющие ввод-вывод в некоторых сетях или устройствах, при этом результирующие сообщения отправляются в очередь файловой системы.

Для выполнения ввода и вывода Ethernet используются два набора процессов: ethi и etho. Эти процессы отправляют Ethernet сообщения процессам ilo и ilt, которые делают надежную дейтаграмму протокола IL над пакетами IP.

И наконец, последний процесс Emelie — con, считывает консоль и вызывает внутренние подпрограммы для выполнения введенных команд. Так как это лишь один процесс, в данный момент времени может выполняться только одна команда. За описанием команд, доступных в консоли, обращайтесь к man-странице fs (8) .

Copyright © 2000 Lucent Technologies Inc. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Page 135:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Протокол ILДейв ПресоттоФил Уинтерботтом

presotto,[email protected]

АБСТРАКТНО

IL — это новый сетевой протокол, предназначенный для доставки сообщений удаленных процедурных вызовов. Легкий транспортный протокол, который переносит дейтаграммы, изолированные от IP. IL обеспечивает повторную передачу потерянных сообщений и доставку с соблюдением порядка, но в нем недоступны операции управления потоками (flow control) и слепые повторные передачи.

Введение

В Plan 9 используется протокол файловой системы под названием 9P [1], который принимает упорядоченную гарантированную доставку раздельных сообщений, содержащих запросы и ответы удаленных процедурных вызовов (RPC). Ни один из стандартных протоколов IP [2] не пригоден для передачи сообщений 9P через сети Ethernet или Internet. У TCP [3] слишком большие потери данных и он не сохраняет разделители сообщений. UDP [4], при низкой стоимости и сохранении разделителей сообщений, отличается ненадежной доставкой дейтаграмм. Во время реализации IP, TCP и UDP в нашей системе мы пробовали выбрать протокол, пригодный для переноса сообщений 9P. Необходимыми были такие свойства:

• Надежный сервис дейтаграмм • Доставка с соблюдением порядка • Межсетевое взаимодействие с использованием IP • Низкая сложность, высокая производительность • Адаптивные тайм-ауты

Так как протокол, удовлетворяющий таким требованиям, не был найден, то мы разработали новый.

IL — это легкий, изолированный от IP, протокол. Он основан на соединениях и обеспечивает надежную передачу упорядоченных сообщений. Поскольку протокол предназначен для передачи сообщений RPC между клиентом и сервером, то отпадает необходимость в средствах управления потоками. Нас вполне устраивает структура с присущими потоковыми ограничениями. Уменьшенное окно для нераспределенных сообщений предотвращает от буферизации слишком большого количества входящих сообщений; сообщения за пределами окна отвергаются и должны быть переданы повторно. Установка соединения использует дуплексное квитирование связи для генерации начальных последовательных номеров в каждом конце соединения; чтобы получатель мог изменять порядок сообщений, последующие сообщения данных увеличивают последовательные номера. В отличие от других протоколов, IL избегает слепые повторные передачи, таким образом не происходит продублирование сообщений. Это свойство повышает производительность протокола в перегруженных сетях, где слепые повторные передачи могут вызывать дальнейшие перегрузки. Подобно TCP, IL имеет адаптивные тайм-ауты, в результате чего протокол работает одинаково хорошо как в Internet, так и в Ethernet. Таймер задержек используется для вычисления времени подтверждения и повторной передачи сообщения, которые характеризуют скорость работы сети.

Page 136:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Соединения

Соединение IL переносит поток данных между двумя конечными точками. Пока соединение устойчиво, данные, входящие с одной стороны, отправляются в другую сторону той же последовательности. Функционирование соединения описано машиной состояний (см. Рис. 1). Состояния изображены кругами, переходы между ними — дугами. Каждый переход помечен списком событий, которыми он вызван, разделенным горизонтальной линией с сообщениями, которые отправляются или получаются при переходе. В остальной части документа обсуждается эта машина состояний.

ackok любой последовательный номер между id0 и следующим включающим!x любое значение кроме x - любое значение

Рис. 1 — Переходы состояний IL

IL имеет пять состояний переходов: Closed, Syncer, Syncee, Established и Closing. Соединение идентифицируется IP адресом и номером порта, которые используются на каждом конце. Адреса размещаются в заголовке протокола IP, в то время как порты являются частью 18-байтового заголовка IL. Локальные переменные определяют состояние соединения:

state одно из состояний

Page 137:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

laddr 32-битный локальный IP адресlport 16-битный локальный IL портraddr 32-битный удаленный IP адресrport 16-битный удаленный IL портid0 32-битный начальный последовательный номер локальной стороныrid0 32-битный начальный последовательный номер удаленной стороныnext последовательный номер следующего отправляемого сообщения с локальной стороныrcvd последнее сообщение из последовательности, полученное из удаленной стороныunacked последовательный номер первого неподтвержденного сообщенияНеиспользуемые соединения находятся в состоянии Closed с не назначенными адресами и портами. Существует два события, которые могут открыть соединение: (1) получение сообщения, в котором адреса и порты не соответствуют ни одному открытому соединению; (2) явное открытие соединения пользователем. В первом случае, исходные адрес и порт сообщения стают удаленными адресом и портом соединения, и адрес и порт назначения сообщения стают локальными адресом и портом. Соединение переходит в состояние Syncee и сообщение считается обработанным. Во втором случае, пользователь указывает оба локальных и удаленных адреса и порта. Соединение переходит в состояние Syncer и сообщение sync отправляется в удаленную сторону. Официальные значения для локального адреса ограничены реализацией IP.

Последовательные номера

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

Передача/Повторная передача

Каждое сообщение содержит два последовательных номера: идентификатор (ID) и подтверждение. Подтверждение является последним упорядоченным сообщением данных, полученным передатчиком. Для сообщений data и dataquery, ID считается их последовательный номером. Для управляющих сообщений sync, ack, query, state и close, ID больше чем последовательный номер самого верхнего отправленного сообщения данных.

Отправитель передает сообщения данных с типом data. Любые сообщения путешествуют в противоположном направлении по отношению к подтверждениям. Если возвращаемое сообщение имеет нестандартное подтверждение отправителю, то в течение 200 мили секунд будет отправлено сообщение ack.

В IP, сообщения могут приходить поврежденными или вообще быть потеряны в результате перегрузки или дефектов. Для преодоления этого, IL использует модифицированный протокол «go back n», который также пытается избегать усугубления сетевых перегрузок. Среднее время подтверждения определяется измерением задержки между передачей сообщения и получением его подтверждения. До того как первое подтверждение будет получено, среднее время подтверждения принимается за 100 мс. Если подтверждение не пришло за четыре периода подтверждения первого неподтвержденного сообщения (тайм-аут rexmit на Рис. 1), IL решает что сообщение или подтверждение потеряно. Затем отправитель пересылает лишь первое неподтвержденное сообщение с установленным типом dataquery. Когда получателю приходит dataquery, то он отвечает сообщением state, подтверждающим самое верхнее полученное упорядоченное сообщение данных. Это может

Page 138:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

быть повторно переданное сообщение или же, если получателем были сохранены неупорядоченные сообщения, какое-нибудь из выше перечисленных сообщений. Реализация получателя свободна для выбора сохранения неупорядоченных сообщений. Наша реализация сохраняет по 10 пакетов за раз. Когда отправитель получает сообщение state, то он немедленно пересылает следующее неподтвержденное сообщение с типом dataquery. Это продолжается до тех пор, пока все сообщения не будут подтверждены.

Если после первого dataquery ни одного подтверждения не было получено, то передатчик продолжает находится в тайм-ауте и пересылать сообщение dataquery. Интервалы между повторными передачами увеличиваются экспоненциально. После прохождения 300 периодов времени подтверждения (тайм-аут death на Рис. 1) отправитель прекращает отправку и решает, что соединение мертвое.

Повторная передача также происходит в состояниях Syncer, Syncee и Close. Интервалы повторной передачи такие же как для сообщений данных.

Сохранение работоспособности

Соединения с мертвыми системами должны обнаруживаться и отвергаться, если они поглощают ресурсы. Если выживающей системе не требуется отправление каких-либо данных и все отправленные ею данные подтвердились, то описанный выше протокол не будет обнаруживать эти соединения. Следовательно, в состоянии Established, если никакие другие сообщения не отправляются за 6-ти секундный период, отправляется query. Получатель всегда отвечает на сообщения query и state. Если за 30 секунд никакое сообщение не приходит, соединение отклоняется. Это не показано на Рис. 1.

Порядок байт

Все 32- и 16-битные количества передаются с первым старшим байтом, что обычно для IP.

Форматы

Ниже представлено описание заголовка IP+IL на языке C, предполагается, что опции IP не заданы:

typedef unsigned char byte;struct IPIL{ byte vihl; /* Версия протокола и длина заголовка */ byte tos; /* Тип сервиса */ byte length[2]; /* Длина пакета */ byte id[2]; /* Идентификация */ byte frag[2]; /* Информация фрагмента */ byte ttl; /* Время жизни */ byte proto; /* Протокол */ byte cksum[2]; /* Контрольная сумма заголовка */ byte src[4]; /* Исходный Ip */ byte dst[4]; /* Ip назначения */ byte ilsum[2]; /* Контрольная сумма, включая заголовок */ byte illen[2]; /* Длина пакета */ byte iltype; /* Тип пакета */ byte ilspec; /* Резерв */ byte ilsrc[2]; /* Исходный порт */ byte ildst[2]; /* Порт назначения */ byte ilid[4]; /* Идентификатор последовательности */ byte ilack[4]; /* Подтвержденная последовательность */};

Page 139:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Предполагается, что в сообщении данные следуют немедленно за заголовком. Ilspec — это расширение, зарезервированное для изменений в протоколе на будущее.

Контрольная сумма вычисляется вместе с ilsum и ilspec, установленными в нуль. Это стандартная контрольная сумма IP — 16-битное дополнение суммы дополнения всех 16-битных слов в заголовке и тексте. Если сообщение содержит странный номер заголовка и текстовые байты, контрольная сумма которых должна быть вычислена, последний байт заполняется справа нулями для формирования 16-битных слов для контрольной суммы. Контрольная сумма защищена от cksum до конца данных.

Возможные значения iltype:

enum { sync= 0, data= 1, dataquery= 2, ack= 3, query= 4, state= 5, close= 6,};

Поле illen является размером заголовка IL в байтах (18 байт) плюс размер данных.

Номера

Номер протокола IP для IL равен 40.

Назначенные номера портов IL: 7 эхо всего ввода на вывод9 исключение ввода19 отправление стандартного образца на вывод565 отправление IP адреса caller и callee на вывод566 протокол аутентификации Plan 917005 сервис Plan 9 CPU, данные17006 сервис Plan 9 CPU, примечания17007 экспортированные файловые системы Plan 917008 файловый сервис Plan 917009 удаленное выполнение Plan 917030 сервер имен Alef

Литература

[1] Rob Pike, Dave Presotto, Ken Thompson, Howard Trickey, and Phil Winterbottom, The Use of Name Spaces in Plan 9, Op. Sys. Rev., Vol. 27, No. 2, April 1993, pp. 72-76, reprinted in this volume.[2] RFC791, Internet Protocol, DARPA Internet Program Protocol Specification, September 1981.[3] RFC793, Transmission Control Protocol, DARPA Internet Program Protocol Specification, September 1981.[4] J. Postel, RFC768, User Datagram Protocol, DARPA Internet Program Protocol Specification, August 1980.

Copyright © 2000 Lucent Technologies Inc. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Page 140:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Процессы sleep и wakeup на мультипроцессоре с памятью совместного использования

Роб ПайкДейв ПресоттоКен ТомпсонДжерард Хольцманн

rob,presotto,ken,[email protected]

АБСТРАКТНО

Проблема временного приостановления выполнения процесса («перехода ко сну») на мультипроцессоре с совместным использованием памяти (Shared-memory Multiprocessor) считается одной из самый труднорешимых, особенно если процесс должен перейти в состояние готовности к выполнению (так называемое «пробуждение») вследствие определенного события. Здесь нами представлен код для примитивов «перехода ко сну» и «пробуждения», которые мы используем в нашей многопроцессорной системе. Код испытан годами активного использования, а также верификационной системой.

Наша проблема заключается в синхронизации процессов на симметричном мультипроцессоре (Symmetric MultiProcessor — SMP) с памятью совместного использования. Процессы временно приостанавливают выполнение, или переходят ко сну, до наступления события наподобие прерывания ввода-вывода. Когда происходит прерывание, процесс пробуждается и переходит в состояние «готовности к выполнению». В это время могут запускаться другие процессы, при чем на процессоры будут влиять другие прерывания.

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

Мы предполагаем, что процессоры владеют элементарной test-and-set или эквивалентной операцией, но никаким другим методом синхронизации. Также предполагается, что прерывания могут происходить на любой процессоре в любое время, кроме процессора, который локально тормозит их.

Данная проблема состоит в обобщении понятия мультипроцессора к схожей и хорошо-понятной унипроцессорной конструкции. Она может быть уменьшена до унипроцессорной проблемы с использованием глобальной test-and-set операции для серийных снов и пробуждений, которые эквивалентны синхронизации посредством проверки. Для эффективности и чистоты, тем не менее, мы предпочитаем допускать мультипроцессорные обработку прерываний и управление процессами.

В этом документе описаны наши попытки решения проблемы перехода ко сну/пробуждения в Plan 9 [4]. У нас появлялись разные реализации решений в течение нескольких месяцев и каждый раз мы ошибочно убеждали себя в их корректности. Для доказательства корректности верификацией, алгоритмы, предназначенные для мультипроцессоров, могут

Page 141:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

быть основательно трудными, формальная аргументация для них непрактична. Наконец, мы разработали алгоритм, проверенный инструментальным средством эмпирического тестирования. Этот код приведен здесь вместе с несколькими комментариями о процессе, для которого он был создан.

История

Поскольку процессы в системах Plan 9 и Unix имеют схожую структуру и особенности, возникает резонный вопрос, а нельзя ли Unix sleep и wakeup [1] адаптировать из их стандартной унипроцессорной реализации для наших мультипроцессорных нужд? Оказывается, что нет.

Программы Unix как аргумент принимают единственный глобальный адрес, который служит уникальным идентификатором для связи пробуждения с соответствующим процессом или процессами. Этому методу присущие существенные недостатки. С точки зрения sleep и wakeup, трудность состоит в ассоциации структуры данных с произвольным адресом; программы неспособны поддерживать запись переменной состояния значением состояний события и процессов. (Обратная операция, конечно, легка — мы можем требовать адрес для указания на специальные структуры данных. Но, исследовав Unix sleep и wakeup, мы узнали, что код, вызывающий их, нам не подходит.) Также, многочисленные процессы переходят ко сну «по» данному адресу, вследствие чего wakeup должен допускать их всех, и позволять планировщику процессов определять, какой процесс действительно имеет преимущество для события. Это неэффективно; хотя механизм организаций очереди (queueing) может быть предпочтительным, но, вновь, наличествует трудность в ассоциации очереди с общим адресом. Кроме того, отсутствие состояния означает, что sleep и wakeup не могут знать какой точно процесс (или прерывание) выполняется; sleep и wakeup должны запускаться автоматически. На унипроцессоре для этого достаточно отключить прерывания в течение их выполнения. На том же унипроцессоре, тем не менее, большинство процессоров могут тормозить прерывания только на текущем процессоре, так что пока процесс выполняется, требуемое прерывание для sleep может прийти и отправиться на другой процессор. Если пробуждение инициировано другим процессом, то проблема становится намного сложнее. В этом случае должен использоваться какой-нибудь механизм межпроцессового взаимного выполнения, который, еще раз, трудно осуществить без средств передачи состояний.

В итоге, полезные на унипроцессоре Unix sleep и wakeup должны либо запускаться автоматически на одном процессоре (как с использованием проверок), либо же есть потребность в более богатой модели для своей связи.

Конструкция

Рассмотрим вариант пробуждений от прерываний пребывающих во сне процессов. (Другой вариант, процесс, который будит другой процесс, легче в реализации, поскольку атомарность здесь может быть достигнута с использованием взаимоблокировки.) Когда происходит событие, все приостановленные процессы пробуждаются, поскольку значение условия, связанного с событием, больше не является истинным. Условие может быть просто происходящим событием, или чем-то другим. Мы представляем условие как функцию с одним аргументом типа void*; поддерживаемый устройством код генерирует прерывания, тем самым представляя функцию, которая используется sleep и wakeup, для синхронизации. Функция возвращает false если событие не произошло, и true — в противном случае. Программы sleep и wakeup должны, конечно, работать корректно если событие происходит пока процесс выполняет sleep.

Мы принимаем, что конкретный вызов к sleep соответствует конкретному вызову к

Page 142:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

wakeup, так, от силы один спящий процесс ожидает конкретное прерывание. Это может быть гарантировано в коде, который вызывает sleep и wakeup подходящими взамоблокировками. Мы также полагаем, что в данный момент времени может присутствовать лишь одно прерывание и что оно должно происходить в любое время, даже перед запуском sleep.

Для эффективности, мы хотим чтобы на нашем мультипроцессоре многочисленные примеры sleep и wakeup могли запускаться одновременно. Например, процессу, вызывающему sleep для ожидания получения символа из входящего канала, необязательно ожидать другой процесс для завершения sleep — для ожидания дискового блока. На высшем уровне, мы хотим чтобы у процесса, считывающего данные из входного канала, была возможность выполнить sleep параллельно с процессом, получающим данные из другого входного канала. Стандартный метод синхронизации заключается во взаимоблокировке канального «драйвера», как результат, за раз только один процесс будет выполняться в канальном коде. Этот способ несомненно неадекватен для наших нужд; нам требуется «мелкозернистая» синхронизация, и что конкретнее, применение взаимоблокировок на уровне индивидуальных каналов вместо уровня канального драйвера.

Наш метод заключается в использовании объекта под названием rendezvous, который представляет собой структуру данных, посредством которой sleep и wakeup синхронизируются. (Подобно названная конструкция в языке Ada является управляющей структурой; наша же структура данных не имеет к ней никакого отношения.) Rendezvous распределена для каждого активного источника событий: по одной для каждого канала ввода-вывода, для каждого конца pipe, и т.д. Rendezvous хранится как взаимоблокирующая структура, в которой производится запись состояния спящего процесса, таким образом, sleep и wakeup могут общаться если событие происходит перед или после выполнения sleep.

Как следствие, наша конструкция sleep — функция

void sleep(Rendezvous *r, int (*condition)(void*), void *arg)

вызываемая спящим процессом. Аргумент r соединяет вызов к sleep с вызовом к wakeup, и является частью структуры данных для (скажем) устройства. Описание функции condition дано выше; вызываемая с аргументом arg, она используется sleep для установления чем было вызвано событие. У wakeup более простая спецификация:

void wakeup(Rendezvous *r).

Wakeup должен вызываться после того как условие получило значение истина.

Реализация

Тип данных Rendezvous описывается следующим образом

typedef struct{ Lock l; Proc *p;}Rendezvous;

Наши Locks — test-and-set spin блокировки. Программа lock(Lock *l) возвращается когда текущий процесс имеет эту блокировку; unlock(Lock *l) осуществляет блокировку.

Вот наша реализация процесса sleep. Ее детали описаны ниже. Thisp — это указатель на текущий процесс на текущем процессоре. (Его значение варьируется на каждом процессоре.)

void

Page 143:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

sleep(Rendezvous *r, int (*condition)(void*), void *arg){ int s;

s = inhibit(); /* прерывания */ lock(&r->l);

/* * неважно, выполняется ли условие */ if((*condition)(arg)){ unlock(&r->l); allow(); /* прерывания */ return; }

/* * теперь мы осуществляем * изменение состояния и вызываем планировщик */ if(r->p) error("double sleep %d %d", r->p->pid, thisp->pid); thisp->state = Wakeme; r->p = thisp; unlock(&r->l); allow(s); /* прерывания */ sched(); /* освобождение процессора */}

Теперь wakeup.

voidwakeup(Rendezvous *r){ Proc *p; int s;

s = inhibit(); /* прерывания; возвращение старого состояния */ lock(&r->l); p = r->p; if(p){ r->p = 0; if(p->state != Wakeme) panic("wakeup: not Wakeme"); ready(p); } unlock(&r->l); if(s) allow();}

Sleep и wakeup оба начинаются с отключения прерываний и блокировки структуры rendezvous. Из-за того что wakeup может быть вызван программой прерывания, блокировка должна быть установлена только с прерываниями, отключенными на данном процессоре, так что если прерывание происходит в течение sleep, оно будет действовать лишь на другой процессор; если оно получено во время выполнения процессором sleep, то spin блокировка в wakeup зависнет навсегда. В конце каждой программы блокировка опускается и приоритет процессора приобретает предыдущее значение. (Wakeup требует торможения прерываний в случае если он вызван процессом; это no-op, если вызван прерыванием.)

Sleep проверяет выполнение условия, если результат позитивен, то он возвращается. В

Page 144:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

противном случае процесс посылает свое имя в структуру rendezvous, где его должен найти wakeup, отмечает его состояние как «ожидающий пробуждения» (используется для проверки на ошибки) и посредством вызова sched() переходит в сон. Обработка структуры rendezvous осуществляется во время блокировки, и wakeup только проверяет его, так что атомарность и исключение гарантированы.

У wakeup более простая задача. Когда он вызван, условие принимает истинное значение, при этом блокируется rendezvous, далее выполняется проверка, находится ли процесс в ожидании, и подготовка для запуска.

Обсуждение

Техника синхронизации использовалась здесь подобно известным методам, даже значительно поодаль от тезиса Saltzer [5]. Код выглядит тривиально корректным в ретроспективе: весь доступ к структурам данных осуществляется во время блокировки, и здесь нет места тому, что вещи могут выходить вне порядка. Тем не менее, нам потребовалось несколько итераций для достижения такой реализации, поскольку действия, которые могут произойти не правильно, часто трудно усмотреть. У нас было четыре ранних реализации, которые были проверены за большой отрезок времени, но неисправность была обнаружена лишь тогда, когда устройство отличного стиля или активности было добавлено в систему.

Вот, к примеру, некорректная реализация wakeup, имеет тесное отношение к одной из наших версий.

voidwakeup(Rendezvous *r){ Proc *p; int s;

p = r->p; if(p){ s = inhibit(); lock(&r->l); r->p = 0; if(p->state != Wakeme) panic("wakeup: not Wakeme"); ready(p); unlock(&r->l); if(s) allow(); }}

Ошибка кроется в том, что чтение r->p должно происходить в то время, когда другой процесс вызывает sleep, так что когда прерывание проверяет структуру, то не обнаруживается ни один процесс, нуждающийся в пробуждении, и спящий процесс избегает этого выхода из сна. Мы написали этот код, потому что осознали, что выборка p = r->p была в сущности элементарная и необходимости во взаимоблокировке нет. Баг был обнаружен путем проверки когда новое, очень быстрое устройство было добавлено в систему и прерывания были тесно перекрыты. Тем не менее, он присутствовал в системе в течение нескольких месяцев без причинения неудобств.

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

Page 145:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

sleep и wakeup. Код был транслирован в язык для системы (к сожалению, без возможности доказательства корректности самой трансляции) и проверен в условиях полной эмуляции.

Программой проверки был найден баг. При нашем предположении, что есть лишь одно прерывание, баг не выявлял себя, но в более общем случае многочисленных прерываний, синхронизирующихся через одну и ту же условную функцию и rendezvous, процесс и прерывание могут входить в специфическое состояние. Процесс должен возвращаться из sleep с условной функцией значения false, если была задержка между условием, стающим истинным и вызовом wakeup, с задержкой, происходящей просто как будто бы получающий процесс вызывает sleep. Теперь условие имеет истинное значение, так что процесс возвращается немедленно, выполняет все что от него требуется, и затем (скажем) решает вызвать sleep вновь. Если условие неверное — переход в сон. Далее wakeup осуществляет поиск спящего процесса, и будит его, но условие теперь — false.

Наличествует легкое (и проверенное) решение: в конце sleep или после возвращения из sleep, если условие неверное, — вновь вызов sleep. Предполагается, что это повторное выполнение не может повториться; вторая синхронизация гарантировано будет действовать на внешних условиях.

Несмотря на то, что оригинальный код полностью защищен взаимоблокировками и был проверен всеми нами на корректность, с ним все еще возникают проблемы. Мы считаем, что для гарантии безопасности мультипроцессорных алгоритмов требуется полный специальный автоматизированный анализ. Наш опыт подтверждает, что правильность мультипроцессорного алгоритма почти невозможно гарантировать путем верификации или простого тестирования. Тестирование может показать наличие ошибок, но никак не их отсутствие [2].

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

Литература

[1] Maurice J. Bach, The Design of the UNIX Operating System, Prentice-Hall, Englewood Cliffs, 1986.[2] Edsger W. Dijkstra, The Humble Programmer - 1972 Turing Award Lecture, Comm. ACM, 15(10), pp. 859-866, October 1972.[3] Gerard J. Holzmann, Design and Validation of Computer Protocols, Prentice-Hall, Englewood Cliffs, 1991.[4] Rob Pike, Dave Presotto, Ken Thompson, Howard Trickey, Plan 9 from Bell Labs, Proceedings of the Summer 1990 UKUUG Conference, pp. 1-9, London, July, 1990.[5] Jerome H. Saltzer, Traffic Control in a Multiplexed Computer System MIT, Cambridge, Mass., 1966.

Copyright © 2000 Lucent Technologies Inc. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Руководство по спулеру печати LpПол Глик[email protected]

Page 146:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

АБСТРАКТНО

Lp — это набор программ, который используется для представления удобного интерфейса для печати различных типов документов на разных принтерах. Lp является прослойкой, соединяющей вместе различные трансляторы с языков форматирования документов и программ связи принтера, в результате пользователь получает последовательный вид принтеров. Большую часть этой прослойки занимает легко модифицируемый сценарий оболочки. В большинстве случаев пользователю не требуется определять никаких опций, чтобы получить какой-нибудь значительный вывод. После прочтения этого документа вы можете смело приступать к созданию надстроек, дополнений и, возможно, даже исправлений.

1. Введение

Lp используется для форматирования и печати данных на разных устройствах вывода. Необходимость в lp появилась в результате невозможности других спулеров печати выполнять простые задания без указания пользователем специальных опций. На момент создания lp существовало всего лишь несколько языков печати, а точнее ImPress и PostScript, и непосредственно разработанный принтер для работы с выводом troff. Сейчас все наши принтеры работают с форматом PostScript, но принтеры, использующие HPCL и HPGL, изобилуют и их поддержка может быть легко добавлена. В основе lp лежат спулеры BSD lpr и System V lp. Важная характеристика системы заключается в том, что большинство программ являются легко модифицируемыми сценариями оболочки и пользователю не обязательно изучать огромный багаж программного обеспечения, лежащего в основе системы. Lp работает как в Plan 9, так в и нескольких Unix-подобных системах. В данном документе описывается lp, имеющий отношение сугубо к Plan 9. Исконно для передачи данных между машинами использовались сети Datakit и Ethernet, сейчас же остался лишь один транспортный механизм Ethernet.

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

Все сценарии оболочки (см. rc (1) ), ассоциированные с lp, находятся в каталоге спулинга /sys/lib/lp, но кроме самой команды lp, — она находится в /rc/bin. Команды, связанные с lp, которые не являются сценариями оболочки, могут быть найдены в /$cputype/bin/aux. Каталог, содержащий все сценарии lp, определен в переменной окружения LPLIB. В остальной части этого документа имена файлов будут определяться с использованием именно этой переменной оболочки.

2. Использование

Перед обработкой ввода lp требует обязательного указания устройства вывода. Это можно сделать одним из трех способов:

1. Файл $LPLIB/defdevice должен содержать имя устройства вывода по-умолчанию. Этот вариант не практичен в системах с несколькими принтерами.

2. Имя устройства можно явно указать в переменной окружения LPDEST. Этот вариант является более практичным решением в системах с несколькими принтерами. При выборе этого способа происходит автоматическое аннулирование спецификации defdevice.

3. Опция -d принтер команды lp определяет принтер как устройство, на которое будет направляться весь вывод. В этом случае происходит аннулирование предыдущих двух

Page 147:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

спецификаций.

Если принтер имеет значение ?, то будет выведен список принтеров и другая информация из файла devices, как это показано на Рис. 1. Заключение в кавычки знака вопроса отключает его интерпретацию оболочкой как метасимвола.

% lp -d'?'device location host classfn 2C-501 helix post/2+600dpi+duplexpcclone - - post+noheadpeacock 2C-501 cetus post/2+300dpi+nohead+colorps83 st8_fl3 rice post+300dpi+reversepsu 2C-501 cetus post/2+1200dpi . . .%

Рис. 1. Простой листинг установленных принтеров.

Обычно, lp использует команду file для определения типа ввода, который он получает. При этом используется процесс generic, который описан ниже в документе в разделе «Каталог процессов». Для выбора специфического процессора ввода используется опция -p процесс, где процесс — это один из сценариев оболочки из каталога process.

К примеру, вывод troff может быть распечатан на принтере fn командой:

% troff -ms lp.ms | lp -dfn

Псевдо-принтер stdout используется для преобразования файла в формат PostScript:

% troff -ms lp.ms | lp -dstdout > lp.ps

Документы LaTeX (и аналогично TeX) можно вывести на печать двумя командами:

% latex lp.tex . .% lp lp.dvi . .%

LaTeX создает файл «.dvi» и не разрешает использовать конвейер со стандартным вводом lp. Чтобы просмотреть статус и очередь устройства, используйте опцию -q:

% lp -dpsu -qdaemon status:: 67.17% sentprinter status:%%[ status: busy; source: lpd ]%%

queue on cetus:job user try sizerice29436.1 pg 0 17454slocum17565.1 ches 1 49995%

Эта команда может выводить информацию о статусе принтера и очереди печати как локальных, так и удаленных хостов. Администраторам рекомендуется работать в среде, где каталог спулинга lp распределен среди локальных и удаленных хостов. На локальных хостах

Page 148:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

ни о каком спулинге не может быть речи. Задание, запущенное выше, может быть прервано при помощи опции -k:

$ lp -dpsu -k rice29436.1rice29436.1 removed from psu queue on cetus

3. Опции

В системе есть много опций по управлению заданиями. Работу по настройке опций проводят программы lp, таким образом, каждая из них может использоваться различными программами преобразования и интерфейса. Не все опции применимы ко всем средам печати. Таблица 1 содержит стандартные опции lp, их описание и настройки переменных оболочки.

Опция Переменная оболочки

Действие имя по-умолчанию установка

-D DEBUG N 1 Включает режим отладки.

-H NOHEADER N 1 Пропускает заголовки страниц.

-L LAND N 1 Растягивает страницу (горизонтально) по всей длине.

-M машина LPMACHID N машина Устанавливает имя машины-источника.

-Q QONLY N 1 Не запускает демон, используется для отладки.

-c n COPIES N n Количество копий печати.

-d принтер LPDEST U принтер Устанавливает устройство вывода, при этом другие опции опускаются.

-f шрифт, размер

FONTPOINT

NN

шрифтразмер

Выбор стиля и размера шрифта

-i n IBIN N n

Выбор опций поддона вводного листа. Аргумент зависит от типа принтера. Данное число выбирает конкретный поддон и/или может использоваться для получения одно/двустороннего вывода. Если опций несколько, то они должны разделяться запятыми.

-k KILLFLAG O 1 Прерывает (удаляет) задания из очереди.

-l n LINES N n Устанавливает количество строк на логическую страницу.

-m f MAG N f Увеличивает изображения на значение f. Значение должно быть позитивным.

-n n NPAG N n Устанавливает n логических страниц на одну физическую. Для сжатия страниц используется простой алгоритм.

-o список OLIST N список

Печатает только указанные номера страниц. Список может быть последовательностью номеров, разделенных запятыми, или диапазоном. Диапазон — это пара чисел, разделенных дефисом.

-p процесс LPPROC L процесс Использование препроцессора процесс взамен препроцессора, указанного в файле данного принтера.

Page 149:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

-q LPQ N 1 Выводит информацию о статусе принтера и очереди печати.

-r REVERSE L 1 Переключает флаг, переворачивая страницу. Если документ уже имеет этот флаг, то этот не будет иметь никакого эффекта.

-u п-ль LPUSERID U п-ль Изменяет идентификатор пользователя, который появляется на обложке.

-x смещение

XOFF N смещение

Перемещает изображение на смещение дюймов в право. Отрицательное значение смещения переместит изображение влево. Смещение может быть любым действительным числом.

-y смещение

YOFF N смещение То же самое, что и выше, только теперь позитивное значение перемещает изображение вниз по вертикали.

по-умолчанию описание установки N первоначально установлен в нулевую строку (`') в lp L установлен из элемента принтера файла devices U установлен из пользовательского окружения

Таблица 1. Список опций lp

4. Файл devices

Файл devices находится в каталоге спулинга. Каждая строка файла состоит из 12 полей, разделенных пробелами и/или символами табуляции. Поля описывают атрибуты принтера и его обслуживание. В команде lp переменная оболочки установлена для каждого атрибута; все они описаны в следующем списке:

LPDEST

Название устройства, которое передается lp при помощи опции -d или определяется в переменной окружения оболочки LPDEST или же посредством файла $LPLIB/defdevice. Это название используется при создании каталогов и журнальных файлов, которые ассоциированы с операциями печати.

LOC Описывает место физического подключения принтера.

DEST_HOST

Хост, как источник файлов для печати. Файлы могут распределяться на другие машины перед их передачей хосту-приемнику.

OUT_DEVФизическое название устройства или сетевой адрес, необходимые демону печати для соединения с принтером. Это поле зависит от требований демона и, если нужно, может содержать «-».

SPEED Скорость, установленная для порта. Это поле зависит от требований демона и, если нужно, может содержать «-».

LPCLASS

Используется для кодирования незначительных различий между принтерами. Ключевое слово reverse используется некоторыми препроцессорами для инвертирования порядка страниц. Ключевое слово nohead используется для подавления страницы заголовков. Ключевое слово duplex используется для получения двустороннего вывода из дуплексных принтеров.

LPPROC Команда из каталога LPLIB/process используется для преобразования ввода в формат, допустимый устройством. Препроцессор вызывается спулером.

SPOOLER Команда из каталога LPLIB/spooler выполняет выборку файлов посредством команды SCHED и вызов посредством LPPROC, отправляя свой вывод в удаленный каталог спулинга. Во избежание конфликтов, происходящих когда клиент и машины-серверы используют общие каталоги спулинга, вывод непосредственно посылается в каталог

Page 150:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

спулинга машины-приемника.

STAT

Команда из каталога LPLIB/stat выводит статус устройства и список заданий, находящихся в очереди печати. Информация статуса зависит от доступного принтерного и интерфейсного ПО. Информация об очереди должна быть изменена для вывода информации, полезной при проблемах трассировки. Команда SCHED используется для вывода заданий в порядке печати.

KILL Команда из каталога LPLIB/kill, удаляющая задания из очереди. Задания, которые должны быть удалены, подаются как аргументы lp.

DAEMONКоманда из каталога LPLIB/daemon предназначена для асинхронного запуска и удаления заданий из очереди. Задания должны или передаваться другому хосту, или отправляться на устройство печати.

SCHEDКоманда из каталога LPLIB/sched используется для представления имен заданий демону и программам статистики в определенном порядке, напр., первый пришел — первый вышел, минимальный первый.

5. Поддерживаемые программы

В следующих секциях описаны основные функции программ, расположенных в подкаталогах $LPLIB. Программы в специфическом каталоге меняются вместе с типом используемых устройств вывода или сетей.

5.1 Каталог процессов

Препроцессор под названием generic является препроцессором по-умолчанию для большинства принтеров. Для определения формата файла ввода используется команда file (1) , затем происходит выборка подходящего препроцессора для преобразования файла в подходящий для принтера формат.

Ниже представлен список препроцессоров с описанием их функций. За полным списком препроцессоров и их описаниями обращайтесь к man-странице lp (8) .

dvipost Преобразование вывода TeX или LaTeX (файлы .dvi) в формат PostScript.

ppost Преобразование текстовых файлов в кодировке UTF в формат PostScript. Шрифт по-умолчанию — Courier со шрифтами Lucida, заполняющими оставшуюся часть (доступного) пространства символов Unicode.

tr2post Преобразование (устройство-незавасимого) вывода troff для устройства типа utf. Смотрите каталог /sys/lib/troff/font/devutf за табличными описаниями шрифтов troff. Также смотрите каталог /sys/lib/postscript/troff за отображениями символьного пространства troff UTF в шрифтовое пространство PostScript.

p9bitpost Преобразование растровых изображений Plan 9 (см. bitfile(9.6)) в формат PostScript.

g3post Преобразование факсов (формата CCITT-G31) в формат PostScript.

hpost Обработка заголовков страниц и инвертирование страниц.

5.2 Каталог спулинга

Спулер generic отвечает за выполнение препроцессора и направление его вывода в файл

Page 151:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Определенные программы обработки принтера не требуют разделения предварительной обработки и спулинга. В таких случаях используется спулер под названием nospool, который лишь выполняет программу предварительной обработки. Программа принимает функции обработки и спулинга и вывод отправляется на OUT_DEV или стандартный вывод, если OUT_DEV имеет значение «-».

Спулер pcclone используется для непосредственной отправки заданий печати на принтер, подключенный к 386-совместимому порту принтера (см. lpt (3) ).

5.3 Каталог статистики

Функцией сценариев оболочки в каталоге stat является представление информации о статусе принтера и его очереди печати. Если необходимо, сценарии stat могут быть доработаны для вывода информации не только о локальной, но и удаленной очередях. Эта возможность отсутствует в Plan 9 потому-что многие системы работают с общим каталогом очереди. Планировщик используется для печати очереди в порядке выполнения задания.

5.4 Каталог удаления

Сценарии kill получают аргументы из командной строки, отправляемые lp, и удаляют задание и идентификационные файлы. После того как задание удалено, общая процедура удаления выглядит таким образом:

1. если удаляемое задание находится первым в очереди, то происходит удаление демона этой очереди,

2. удаление файлов, связанных с заданием из очереди, 3. попытка запуска демона.

5.5 Каталог демона

Сценарии оболочки daemon вызываются последними в lp посредством опции -Q. Процесс-демон выполняется асинхронно со своими стандартными выводом и ошибками, записываемыми в журнальный файл принтера. Последний описан в следующем разделе. Так как демон запускается асинхронно, то должен принимать сигналы, которые могут вызывать ненормальное завершение работы. Сперва демон выполняет проверку один ли он запущен, для этого используется программа LOCK из каталога /$cputype/bin/aux. Команда LOCK создает одноименный файл, также называемый файлом блокировки, в каталоге очереди принтера. Затем демон вызывает планировщик для получения имени следующего задания из очереди.

Обработка заданий может влечь их передачу на другой хост или принтер. Для индивидуальных демонов детали этой операции достаточно специфичны. Если задание было выполнено без ошибок, то оно подлежит удалению из очереди, в противном случае происходит перемещение связанных файлов в специфический для принтера каталог $LPLIB/prob. Также, демон может сделать запись в журнальный файл принтера. Перед выполнением, демон должен очистить файлы блокировок путем вызова UNLOCK.

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

Page 152:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

5.6 Каталог планировщика

Планировщик решает, какие файлы заданий должны быть выполнены, и в каком порядке. Наиболее часто используемым планировщиком считается программа FIFO, выглядит она так:

ls -tr $* | sed -n -e 's/.* *//' \ -e '/^[0-9][0-9]*.[1-9][0-9]*$/p'

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

6. Когда что-то идет не так, как нужно

Всего есть четыре каталога, куда lp записывает файлы. В версии Plan 9 они находятся в каталоге временной файловой системы (стоит отметить тот факт, что она не вспомогательная) /n/emelieother/lp. Он построен на вершине файловой системы other, которая монтируется на файловом сервере emelie. Четыре каталога временной файловой системы — это log, prob, queue и tmp. Lp связывает (см. bind (1) ) первые три в каталог /sys/lib/lp для процессов и их потомков. Каталог tmp связывается в каталог /tmp, в результате чего демоны lp, запущенные пользователем «none», тоже имеют права на запись в этот каталог.

При любой инсталляции важно, чтобы эти каталоги были созданы и команда /rc/bin/lp имела правильные установки. Если вы не владеете временной файловой системой для этих каталогов, то можете создать четыре каталога log, prob, queue и tmp в $LPLIB (/sys/lib/lp) так, чтобы все имели право записывать в них.

6.1 Каталог журнальных файлов

Журнальные файлы для конкретного принтера появляются в подкаталоге каталога спулинга log/принтер. В данный момент существует всего два типа журнальных файлов. Первый используется демоном для записи ошибок и успешных завершений заданий. Это файл принтер.день, где день — это трехбуквенная аббревиатура дня недели. Он перезаписывается один раз в неделю во избежание необходимости в регулярной очистке. Второй тип журнального файла содержит статус принтера и записывается программой, которая сама держит с ним связь. Он называется принтер.st и переписывается с каждым новым заданием и хранится в каталоге $LPLIB/prob пока задание не будет выполнено. Если принтер не функционирует, эти файлы должны быть проверены первыми.

6.2 Каталог проб и ошибок :)

Если задание не создает вывод, первым делом должны быть проверены журнальные файлы. Если очевидных проблем не было найдено, попробуйте создать каталог с правами на чтение и запись в $LPLIB/prob. Последующие неудачи задания заставят демон оставить копию задания и журнальный файл связи принтера в каталоге $LPLIB/prob/принтер. Это общий прием для вывода принтера из критических состояний, за исключением ручного выключения питания принтера. После этого демон печати должен восстановится сам (дайте ему минуту). Если он не восстановится, для аварийного завершения работы демона удалите файл блокировки LOCK из каталога спулинга принтера. Перезапуск демона произойдет при отправке нового задания на принтер. Для PostScript принтеров используйте команду:

echo '%!PS' | lp

Page 153:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

6.3 Зависшие демоны

Бывают ситуации? когда управление печатью невозможно с помощью демонов. Одной из таких ситуаций считается вхождение принтера в коматозное состояние. В таком состоянии он никак не реагирует на отправляемые ему сообщения. После сброса демон должен восстановить работу и в журнальных файлах должно появится сообщение ошибки. Если ничего не помогает, удалите первое задание из очереди печати или файл блокировки LOCK из каталога очереди. Эта операция завершит работу демона, после чего он будет перезапущен.

7. Интерпроцессорная связь

CPU сервер Plan 9 может быть установлен как принтерный спулинг хост. Таким образом, получится машина, принимающая задания для печати и отправляющая их непосредственно на принтер. Чтобы сделать это, CPU должен прослушивать TCP порт 515, который известен как порт демона строчного принтера BSD. Когда приходит вызов из порта, выполняется файл /rc/bin/service/tcp515. Plan 9 lpdaemon может принимать задания, отправленные из систем BSD LPR/LPD. Команда /$cputype/bin/aux/lpdaemon выполняется из служебного вызова и принимает задания для печати, запросы статуса и запросы на удаление заданий. Команда /$cputype/bin/aux/lpsend отправляет задания на машины Plan 9 и обычно вызывается спулером или сценарием демона. Команда /$cputype/bin/aux/lpdsend отправляет задания на машины и принтеры, использующие протокол BSD LPR/LPD, и она также вызывается спулером или сценарием демона.

8. Благодарности

Особая признательность выражается Ричу Дричслеру (Rich Drechsler) за создание и поддержку большей части интерфейсных программ и конвертеров PostScript, без которых lp был бы пустой оболочкой. Томас Рокики (Tomas Rokicki) создал программу преобразования TeX в формат PostScript.

9. Литература

[1] Ralph Campbell, 4.3BSD Line Printer Spooler Manual, UNIX System Manager's Manual, May, 1986, Berkeley, CA[2] Request for Comments: 1179, Line Printer Daemon Protocol, Aug 1990[3] System V manual, date unknown

Copyright © 2000 Lucent Technologies Inc. All rights reserved.Copyright © 2003 Перевод Андрей С. Кухар.

Различные портыВ этом документе собраны комментарии об поддерживающихся в Plan 9 аппаратных архитектурах. Система пытается вуалировать множество архитектурных различий, вследствие чего машины, как это кажется пользователю Plan 9, отличаются лишь коммерческим программным обеспечением. Также, поскольку мы небольшая группа, то не в силах сделать и предусмотреть все: использовать каждую оптимизацию, поддерживать каждую модель, управлять каждым устройством. В документе описаны сугубо то, что нам удалось осуществить. В первой части для каждой архитектуры обсуждается тройка компилятор/ассемблер/загрузчик. Во второй идет речь об операционной системе и ее реализации для представленных машин.

Page 154:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Компилятор Motorola MC68020

Самый старый компилятор из рассматриваемой группы. Генерирует довольно хороший код относительно своих коммерческих компиляторов-конкурентов для этого типа машин. Принимает по крайней мере архитектуру 68020: некоторые сгенерированные им режимы адресации не подходят для 68000 и 68010.

Также мы пользуемся этим компилятором для 68040. За исключением нескольких команд и регистров, доступных только посредством языка ассемблера, единственное видимое различие между этими машинами состоит в вычислениях с плавающей точкой. Все наличествующие у нас 68020-е имеют устройства для вычислений с плавающей точкой: 68881 или 68882, так что для выполнения FP-программ мы, разумеется, зависим от соответствующего оборудования. К сожалению, 68040 не досконально чиста в своей реализации стандарта IEEE 754 или предоставлении встроенных команд для трансцендентных функций. Впрочем, мы легко обходим это ограничение, не используя последние на 68020, и отдавая предпочтение собственной библиотеке -l68881, которая необходима при потребности в производительности (что, кстати сказать, бывает вполне обоснованно, например, наш сервер astro получил двойной прирост). Поскольку мы изъявляем желание запускать те же двоичные файлы на обоих машинах без эмуляции FCOSH в операционной системе, то мы не пользуемся этой библиотекой по умолчанию.

Проблема с IEEE намного противней. У нас не было в планах связываться с постепенной потерей значимости (gradual underflow) и ей подобными, поэтому после того как на половине дюжины машин нам понадобилось иметь с ними дело, мы на 68040 реализовали потерю значимости без организации ловушек (non-trapping underflow) как округление до нуля и не трогали денормализированные числа и «не-числа». Посему машины 68020 и 68040 не являются строго совместимыми.

Компилятор Motorola MC68000

Этот компилятор является упрощенной версией компилятора MC68020, построенной для не выпущенного порта процессора Dragonball для Palm Pilot. Он генерирует переместимый код, общее качество которого значительно хуже чем у MC68020.

Компилятор MIPS

Компилятор генерирует код для машин R2000, R3000 и R4000, сконфигурированных как big-endian архитектуры. Хотя ассемблер и загрузчик поддерживают новые команды пользовательского режима, компилятор не генерирует R4000-специфических команд. Машины little-endian не поддерживаются. (Порт little-endian существует, но не включается в дистрибутив. Свяжитесь с нами, если он вам необходим.) Что касается скорости, то хотя компилятор Plan 9 и генерирует хороший код, но, все-же, коммерческий MIPS компилятор со всеми остановками, выпущенными последовательно, бывает проворнее его на 20%, а то и более. Так как наш компилирует в 10 раз быстрее и основное свое время мы тратим на компиляцию, то мы им удовлетворены.

Компилятор довольно-таки стабильный: мы использовали его в нескольких больших проектах и, естественно, генерировали код приложений именно посредством него. Поведение программ с плавающей точкой во многом схоже с 68040: когда необходимо получить потерю значимости без организации ловушек и потерю значимости операционная система эмулирует их; постепенная потеря значимости, денормализированные числа и «не-числа» отсутствуют.

Компилятор SPARC

Компилятор SPARC, также как и предыдущий, довольно стабилен и быстр, хотя мы не

Page 155:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

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

Мы обычно запускали некоторые старые SPARC-машины без команд умножения и деления, так что компилятор не производит их по умолчанию. Взамен он вызывает внутренние подпрограммы. Флаг загрузчика, -M, вызывает выдачу команд. Операционная система владеет кодом прерываний для их эмуляции, но прерывания более медлительны, чем их эмуляция в пользовательском режиме. В любой современной лаборатории, где SPARC машины имеют команды, полезно включить опцию -M по-умолчанию.

Что касается вычислений с плавающей точкой, то здесь та же самая история что и с MIPS.

Компилятор Intel i386

Это настоящий x86-компилятор, для x>2. Он работает только на машинах с 32-битным защищенным режимом. Он быстр и генерирует сносный код; сегодня это наш основной компилятор.

Плавающая точка хоть и хорошо ведет себя, но для выполнения команд компилятор применяет i387-совместимое аппаратное обеспечение. С обеспечением 387 система выполняет работу стандарта IEEE 754, также как MC68881. По-умолчанию, библиотеки не используют внутренние команды 387 для трансцендентных функций. Если же у вас есть желание их использовать, постройте код из каталога /sys/src/libc/386/387.

Компилятор Intel i960

Этот компилятор был создан как «хэк для уикэнда» (weekend hack), для работы с платами Cyclone. Он использовался лишь для запуска одного наплатного кода программы в Cyclone. Компилятор владеет большим количеством не использующихся оптимизаций кода. К примеру, компилятор не поддерживает конвейеры. Код запускается в режиме little-endian.

Компилятор DEC Alpha

Компилятор Alpha основан на порте, который Дэвид Хоган (David Hogan) написал во время обучения в Сиднейском университете, на отделении computer science Бассера. Он был использован для построения текущей версии операционной системы, но не выделялся как другие компиляторы.

Так как Alpha — это 64-битная архитектура, компилятор обрабатывает типы int, long, и указатели как 32-битные. Доступ к 64-битным операциям осуществляется с помощью типа vlong (аналогично другим компиляторам).

Принято, что целевой процессор поддерживает дополнительные операции с памятью: byte и word (расширение «BWX»). Если у вас старая система, вы можете генерировать код без использования расширений путем указания опции -x загрузчику.

Существует большое количество оптимизаций кода, которые рекомендует справочник по архитектуре Alpha, но компилятор их не поддерживает. К настоящему времени нет поддержки выравниванию и планированию оптимизаций кода.

Компилятор пытается соответствовать стандарту IEEE, но некоторые процессоры Alpha не осуществляют все режимы округлений и прерываний в кремнии. Локализация этой проблемы требует программную эмуляцию кода в ядре; к настоящему времени проблема все еще присутствует.

Page 156:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Компилятор PowerPC

Компилятор PowerPC поддерживает лишь 32-битную архитектуру PowerPC; он не поддерживает ни 64-битные расширения, ни POWER-команды совместимости. Он использовался для получения операционной системы для процессоров 603, 603e, 604e, 821, 823 и 860. На процессорах 8xx операции с плавающей точкой должны эмулироваться. Команда планирования не реализована. Компилятор не использует или использует, но совсем ничтожную часть, необычных характеристик PowerPC. К ним относятся: регистр-счетчик, несколько регистров кода завершения, и команды умножения-накапливания, но они иногда используются программами на языке ассемблера в библиотеках.

Компилятор Acorn ARM

Компилятор ARM довольно стабилен; он использовался при работах над операционной системой Inferno и ядром Plan 9 для iPAQ, где используется StrongArm SA1. В компиляторе есть поддержка архитектуры ARMv4, зато нет поддержки для набора команд Thumb. Он эксплуатировался на процессорах ARM7500FE и машинах с Strongarm SA1. Компилятор генерирует команды для ARM-сопроцессора с плавающей точкой.

Компилятор AMD 29000

Компилятор использовался при портировании операционной системы на процессор AMD 29000. Проект давно заброшен, но компилятор все-же существует.

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

Данная ОС выполнялась на терминалах: MIPS R4400 PC-подобных устройствах (Carrera) со сделанными на заказ фреймовыми буферами. Теперь почти все они коммисированы, но мы включаем исходный код Carrera в дистрибутив на тот случай, если кто-нибудь захочет запускать MIPS-основанную систему.

Операционная система для IBM PC

PC-версия Plan 9 может загружаться из MS-DOS или непосредственно с созданного при помощи команды format диска (см. prep (8) ). Plan 9 запускается в 32-битном режиме, который требует процессор 386 или более поздний, с управляемой прерываниями системой ввода-вывода, т.е. не использующей BIOS (за исключением небольшой части загрузочной программы загрузочного блока дискеты). Это улучшает производительность, но ограничивает набор устройств ввода-вывода, которые могут поддерживаться без какого-либо специального кода.

Plan 9 поддерживает как шины ISA, EISA и PCI, так и устройства PCMCIA. Но, в любом случае, невозможно указать все поддерживаемые машины, потому как рынок PC-клонов слишком изменчив и нет гарантий, что компоненты машины, которую вы купили сегодня, будут совпадать с компонентами завтрашней покупки. (Что касается нашей лаборатории, то мы сами покупаем и собираем машины в попытке уменьшить этот эффект.) Диски IDE/ATA и SCSI поддерживаются, также есть поддержка больших ATA дисков. Приводы CD-ROM поддерживаются в двух вариантах: на шине SCSI и как устройства ATA(PI). SCSI адаптер должен быть экземпляром серии Mylex Multimaster (Buslogic BT-*) или же Symbios 53C8XX. Поддерживаются карты Ethernet, включая AMD79C790, 3COM Etherlink III, серия 3C589, NE2000, WD8003, WD8013, SMC Elite и Elite Ultra, Linksys Combo EthernetCard и EtherFast 10/100, и различные контроллеры, основанные на чипах Intel i8255[789] и Digital (сейчас Intel) 21114x. Мы по большей части используем Etherlink III, i8255[789], и 21114x, так что драйверы этих устройств вероятно должны быть более надежными. Для периферии должен

Page 157:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

наличествовать явный драйвер Plan 9; драйверы для DOS или Windows не подходят. Также, Plan 9 не может эксплуатировать специальные характеристики аппаратных средств, не входящие в стандартную модель IBM PC, такие как управление питанием, за исключением архитектура-зависимого кода, который добавлен в ядро. За детальной информацией об этих и подобных вещах обращайтесь к man-странице plan9.ini (8) .

Годами ОС Plan 9 работала на множестве VGA-карт. Тем не менее, последние изменения в графической системе не были протестированы на большинстве старых карт; все-таки некоторые усилия придется приложить, чтобы заставить их работать вновь. В нашей лаборатории большинство машин используют чипы ATI Mach64, S3 ViRGE, или S3 Savage, так что данные устройства должны быть наиболее надежными. Мы также пользуемся несколькими картами Matrox и TNT. Системе требуется аппаратный курсор. За информацией обращайтесь к man-страницам vgadb (6) и vga (8) . Wiki содержит окончательный список поддерживаемых карт.

Что касается аудио, то Plan 9 поддерживает карты семейства Sound Blaster 16 и совместимые. (8-битные карты Sound Blaster не работают в Plan 9.) Существует поддержка USB аудио устройств, см. usb (4) .

И наконец, очень важно иметь мышь с тремя кнопками. Plan 9 работает мышками PS/2, COM, а также USB.

Как только вы установили Plan 9 (смотрите документ с установочными инструкциями) запустите программу ld из DOS, или же воспользуйтесь загрузочной дискетой. За детальной информацией обращайтесь к booting (8) , 9load (8) и prep (8) .

Операционная система для Alpha PC

Plan 9 запускается на машине Alpha PC 164. Порт Alpha не использовался так часто как другие, и должен рассматриваться как предварительная версия.

Он использует изюминку PALcode — OSF/1, и должен загружаться из микропрограммы SRM (загрузка из ARC не поддерживается). Поддерживаемые устройства являются подмножеством PC-единиц, включая DECchip 2114x-основанные Ethernet карты, карты S3 VGA, Sound Blaster 16-совместимые аудио карты, флоппи дисководы, винчестеры ATA интерфейса.

Система должна загружаться посредством tftp (см. booting (8) ).

Операционная система для PowerPC

Мы владеем версией операционной системы для архитектуры PowerPC, но она запускается только на машине под названием Viaduct. Viaduct — это небольшой (с габаритами 12x9x3 см) дешевый встраиваемый компьютер, который состоит из: 50 MHz MPC850, 16 MB SDRAM, 2 MB Flash, и двух портов 10 Mb Ethernet. Он разработан для домашних/SOHO сетевых приложений, таких как VPN, брандмауэры, NAT, и т.п.

Ядро также было портировано на встраиваемую материнскую плату Motorola MTX. Порт (включен в дистрибутив) предназначен сугубо для процессора 604e (значительно разнится с 603e) и на текущий момент разрешен лишь один CPU.

Операционная система для Compaq iPAQ

Plan 9 портирована на PDA-компьютер iPAQ Pocket PC (Compaq), в котором используется процессор StrongArm SA1. Порт выполнен для модели 3630, известно, что граничащие с ней модели также функционируют. Ядро распознает контроллер PCMCIA с картой WaveLAN, но другие PCMCIA-устройства портированию подданы еще не были.

Page 158:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

На iPAQ возможен запуск rio. Ввод: небольшое приложение-клавиатура, благодаря которому возможен рукописный ввод в стиле Palm, вместе с тем доступен вариант ввода посредством миниатюрной клавиатуры.

Франциско Дж. Баллестэрос (Fco. J. Ballesteros) добавил поддержку функции перехода в состояние ожидания (hibernation), но, к сожалению, мы не можем заставить ее работать вновь в новом ядре; код открыт, так что добровольцы только приветствуются. За информацией об установке Plan 9 на iPAQ смотрите файл /sys/src/9/bitsy/Booting101.

Файловый сервер

Файловый сервер работает лишь на определенных машинах. Он представляет собой отдельную программную систему, отдаленно имеющую отношение к коду CPU сервера, на нем не выполняется никаких пользовательских процессов: все, что он делает — это постоянно хранит информацию и выдает ее в сеть как иерархию файлов. Он поддерживает SCSI и IDE диски, которые могут чередоваться для высокой производительности. DOS файл на диске IDE может хранить конфигурационную информацию. За информацией как сконфигурировать файловый сервер смотрите fsconfig (8) .

Чтобы загрузить файловый сервер, следуйте инструкциям по загрузке CPU сервера с использованием имени файла 9machtypefs, где machtype — это pc, и т.п., соответственно. Мы выпускаем только PC-версию.

Файловый сервер IBM PC

Кроме ограничений на SCSI-диски, файловый сервер PC имеет те же аппаратные требования, что и основная операционная система для этой архитектуры. Тем не менее, только подмножество поддерживаемых SCSI (Adaptec 1542, Mylex Multimaster и Symbios 53C8XX) и Ethernet (Digital 2114x, Intel 8255x и 3Com) контроллеров корректно функционирует. Применен может быть любой из способов загрузки, описанных на странице 9load (8) .

Чтобы загрузить любую PC-версию, файл 9load должен быть размещен на MS-DOS-отформатированной дискете, IDE-диске, или SCSI-разделе. Тем не менее, персональные компьютеры не владеют статической памятью RAM, в которой файловый сервер мог бы хранить конфигурационную информацию, так что взамен система хранит ее в файле файловой системы MS-DOS. Впрочем, файл этот не может хранится на SCSI-дисках, таким образом, только на дискете или IDE. (Это ограничение избегает большинство дублирований интерфейсов в системе.) Смотрите plan9.ini (8) за информацией о переменной nvr и определением консольного устройства.

Резервное копирование

Наш главный файловый сервер в лаборатории вряд ли имеет сходство с вашим. Это ПК с 128 MB кеш-памяти, 56 GB SCSI-диском и магнито-оптическим дисковым блоком Hewlett-Packard SureStore Optical 1200ex емкостью 1,2 TB. Драйвер запускает стандартный SCSI jukebox протокол. У нас также есть драйвер для (не стандартного) дисковода с автоматической сменой WORM-дисков SONY WDA-610, который вмещает около 350 GB данных.

WORM представляет собой основной накопитель; SCSI-диск — это не что иное, как кеш-память для улучшения производительности. Каждое утро система создает на WORM-диске образ всей системы предыдущего дня. Следовательно, наша система резервного копирования является файловым сервером, который позволяет просматривать вчерашнюю (или прошлогоднюю) файловую систему.

Если у вас отсутствует магнито-оптический накопитель, вы можете подключить привод CD-R

Page 159:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

или даже использовать WORM-диск и управлять дампами. Естественно, у вас будет немного меньше автоматики. Но утверждать, что распределенная система для резервного копирования может использовать лишь WORM-накопитель было бы не верно.

На самом деле не каждый может себе позволить такое дорогостоящее аппаратное обеспечение, хотя это было бы очень роскошно. Но существует выход, состоит он в том, чтобы пользоваться сервером mkfs (8) для создания регулярных архивов файловой системы и scuzz (8) — для их направления на ленточный накопитель SCSI 8mm. Затем извлекать данные из этих архивов можно с помощью mkext. Другая альтернатива — использование программы dump9660 (см. mk9660 (8) ), которая записывает пошаговые «бэкапы» на CD в виде иерархии dump.

Также возможно обращение к обычному диску или даже к его части, как к «псевдо-WORM». Когда он заполнится, данные можно направлять на ленточный накопитель. Это плохая идея для эксплуатации системы, но великолепный путь узнать больше ПО WORM. Чтобы узнать о других особенностях, прочитайте страницу fsconfig (8) .

Copyright © 2004 Lucent Technologies Inc. All rights reserved. © Перевод на русский язык, Андрей С. Кухар, 2004

Factotum и secstore7 августа 2002 года на конференции USENIX Security, которая проходила в Сан-Франциско, Bell Labs, исследовательское подразделение компании Lucent Technologies, представило новый программный комплекс для обеспечения безопасности сетевого доступа, значительно облегчающий процесс доступа к ресурсам при одновременном повышении уровня защиты.

Комплекс состоит из двух дополняющих друг друга программ, — это хранилище персональной информации Secure Store и агент аутентификации Factotum. В отличие от других приложений, где данными о пользователе управляет либо сама компания, либо некая третья фирма, здесь этот процесс выполняется самим пользователем. Другим преимуществом данного комплекса является возможность аутентификации пользователя на любом сайте без необходимости применения какой-либо единой парольной системы.

«Такая модель аутентификации изначально более защищена, так как пользователь сам контролирует свои данные, персональная информация хранится в сети, а не на каком-нибудь устройстве, плюс используются новые протоколы», отмечает Аль Эхо (Al Aho), профессор computer science Колумбийского университета и бывший вице-президент научно-исследовательского центра вычислительной техники Bell Labs. «Кроме того, система чрезвычайно удобна, так как пользователю теперь не нужно по несколько раз вводить одни и те же данные и запоминать множество паролей для всех необходимых ему служб.»

Для работы с сервисами Factotum и Secure Store, пользователю нужно ввести все его имена и пароли для различных сайтов, на которых он зарегистрирован, будь-то онлайновое банковское дело, электронная почта, покупки и т.п. в Secure Store. Сервер Secure Store размещается в недоступном для пользователя сегменте сети и обеспечивает защиту переданной ему информации на базе AES (Advanced Encryption Standard).

Для входа в свою систему, пользователь должен ввести пароль в приложении Factotum, запущенном на локальном устройстве вроде лэптопа или PDA. Оно разблокирует пароли и другие конфиденциальные данные, хранящиеся в Secure Store. Всякий раз, когда приложение, web-сайт или другие ресурсы, к которым ранее выполнялось обращение, требует для аутентификации имя пользователя и пароль, Factotum предоставляет их автоматически. Factotum хранит эту информацию не на жестком диске, а в не своппируемой и защищенной от отладчика оперативной памяти, поэтому она удаляется при каждой перезагрузке или выключении машины.

Page 160:  · Plan 9 от Bell Labs Роб Пайк Дейв Пресотто Шон Доруорд Боб Фландрена Кен Томпсон Говард Трики Фил ...

Дейв Пресотто, Роб Пайк и Эрик Гросс в научно-исследовательском центре вычислительной техники Bell Labs совещаются по поводу нового инновационного комплекса обеспечения безопасности.

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

«Обмен информацией о пароле между Factotum и Secure Store осуществляется по новому улучшенному протоколу PAK (Password Authenticated Key Exchange), разработанному в Bell Labs. Информация в Secure Store защищена математически сильной криптографией и шифрованием», говорит Дейв Пресотто (Dave Presotto). «Другие улучшенные технологии безопасности встроены в Factotum против стандартных методов взлома.»

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

На первый взгляд эта система похожа на другие средства поддержки единой точки входа, но техническая реализация Factotum и Secure Store исключительно индивидуальна. В других механизмах поддержки единой точки входа каждое приложение, к которому обращается пользователь, должно поддерживать данную технологию. Предлагаемые Bell Labs инструменты этого не требуют. «Пользователи могут работать со всеми унаследованными протоколами и самыми разнообразными системами — мы просто автоматизируем те процессы, которые в любом случае выполняются», — объясняет Эрик Гросс (Eric Gross), директор подразделения, занимающегося исследованиями в области сетевых технологий.

Данные программы являются последними из длинного потока приложений обеспечения безопасности сетевого доступа от Bell Labs, начавшемся еще в 70-х годах вместе с созданием операционной системы Unix Деннисом Ритчи (Dennis Ritchie) и Кеном Томпсоном (Ken Thompson). «Даже тогда мы работали над уровнем безопасности», вспоминает Гросс. «Мы с самого начала были новаторами в области сетевой безопасности.»

Программный комплекс разработан для запуска в операционной системе Plan 9. Созданная группой программистов в научно-исследовательском центре вычислительной техники, четвертая версия Plan 9 недавно стала доступна в Internet, со встроенными Factotum и Secure Store. Комплекс также может использоваться в комбинации с любой другой операционной системой, включая Linux, Windows NT, Sun Solaris и Unix, и доступен для лицензирования в форме исходного кода для промышленных поставщиков и высших учебных заведений.

Новая полностью переработанная архитектура безопасности описана в документе симпозиума USENIX Security 2002: [html, ps, pdf], который, кстати, получил премию за лучший документ конференции.

Если у вас возникло желание просмотреть код всего этого, загрузите дистрибутив Plan 9 и зайдите в каталог /sys/src/cmd/auth, он содержит подкаталоги factotum и secstore. Библиотеки /sys/src/libmp и /sys/src/libsec также могут заинтересовать вас.

Copyright © 2003 Андрей С. Кухар.

Powered by werc