Фэндом



Роб ПайкBell LabsLucent Technologiesrob@plan9.bell-labs.com4 февраля 2000 года

1. ИсторияПравить

Тема: внешняя и, особенно, внутренняя конструкция Rio, (новой) оконной системы ОС Plan 9.

Потомок 8½:

Pike, Rob, ‘‘8½, the Plan 9 Window System’’, Proceedings of the Summer 1991 USENIX Conference, Nashville, 1991, pp. 257-265.

Оконная система 8½ первоначально была написана на языке C с использованием процессов и основанных на setjmp и longjmp дополнительных сопрограмм (интересное упражнение).

В 1995 году для проекта Brazil система была переписана на языке Alef и конвертирована в настоящие потоки (threads) и процессы.

В 1999 году конвертирована для использования потоковой библиотеки.

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

2. Общая конструкцияПравить

По сути, не считая очевидных, оконная система состоит из трех составляющих:

  • системного интерфейса (для доступа к оборудованию);
  • программного интерфейса (для манипулирования окнами);
  • пользовательского интерфейса (мышь, клавиатура, меню…).

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

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

3. 9P: файл-серверный протокол Plan 9Править

(Почти) все «население» мира Plan 9 является файловым сервером или как минимум представителем одной из категорий:

  • процессы (для отладки);
  • переменные окружения;
  • консоль;
  • графика;
  • сеть;

Клиент подключается к серверу.
Клиент запрашивает — сервер отвечает.

Запросы:


Walk, Open, Read, Write, Close, Create
Remove, Stat

Могут работать через любой надежный канал: TCP/IP, pipe,…

4. Пространство именПравить

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

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

Пользовательский файл профиля ($home/lib/profile) формирует пространство имен начиная с корневого каталога / и монтирует, подключая, сервисы.

«Превращает» все сервисы, включая основные устройства, в файловые серверы.

Таковы основы Plan 9.

5. Примеры устройствПравить

Процессы:

    /proc/1/…
    …
    /proc/27/ctl
    /proc/27/mem
    /proc/27/note
    /proc/27/notepg
    /proc/27/proc
    /proc/27/status
    /proc/27/text
    …

Консоль:

    /dev/cons
    /dev/time
    /dev/cputime
    /dev/pid

(Все файлы текстовые)

6. Примеры устройств (управляемые)Править

Сетевые:

    /net/il/clone
    /net/il/stats
    /net/il/29/ctl
    /net/il/29/data
    /net/il/29/err
    /net/il/29/listen
    /net/il/29/local
    /net/il/29/remote
    /net/il/29/status
    …
    /net/tcp/…
    /net/udp/…
    /net/cs
    …

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

7. Примеры устройств (управляемые)Править

Мышь:

    /dev/mouse
    /dev/cursor

Растровая графика:

    /dev/screen
    /dev/window
    /dev/draw

Формат файла /dev/draw — RPC (уделенный вызов процедур), заканчивающийся еще одним файлом. (Так называемый, вложенный RPC.)

    void
    draw(Image *dst, Rectangle dr,
        Image *src, Point sp,
        Image *mask, Point mp);
    /dev/draw:
        ’d’
        2 байта для идентификатора назначения
        4x4 байтов назначения
        2 байта исходного идентификатора
        …

8. Структура оконной системы (I)Править

Для записи оконной системы,

Для получения символов ввода — чтение /dev/cons.
Для получения позиции мыши и нажатых кнопок — чтение /dev/mouse.
Для обновления экрана — запись /dev/draw.

Что же делает клиент?

Для получения символов ввода — чтение /dev/cons.
Для получения позиции мыши и нажатых кнопок — чтение /dev/mouse.
Для обновления экрана — запись /dev/draw.

Как вы видите, действия оконной системы и ее клиента идентичны!

9. Структура оконной системы (II)Править

Таким образом, Rio — это все лишь мультиплексор:

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

Файлы /dev/cons и /dev/mouse для каждого окна отличаются. (Фактически, 8½ обеспечивала также разные файлы /dev/draw, но Rio не делает этого, что увеличивает ее эффективность.)

В отличие от Unix, где /dev/tty — это одни и те же файлы, но с различными содержимыми, в Rio /dev/cons действительно являются другими файлами, но с одинаковыми именами и различными содержимыми. (Я могу доказать, что этот вариант гораздо лучше.)

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

10. Останов: хорошие побочные эффектыПравить

Удаление окна: контрольный счет открытых файлов.

Del (прерывание)

    /dev/cons

Удаленная прозрачность: если есть возможность экспортировать файл (напр., NFS), то есть и возможность экспортировать целую оконную систему.

Рекурсия:

  • Легкая отладка: запуск оконной системы в окне.
  • Легкая загрузка: запуск оконной системы на CPU-сервере.
  • Легкая имитация: возможность запуска X в окне.

11. ПроблемаПравить

Rio должна управлять всеми следующими операциями:

  • ввод с помощью мыши;
  • клавиатурный ввод;
  • оконное управление (в отличие от X, пользовательский интерфейс для оконного управления является частью Rio);
  • вывод на экран;
  • запросы ввода-вывода в 9P от клиента для чтения и записи /dev/cons, /dev/mouse, /dev/window, и т.п.

Как же управлять всем этим параллельно, одновременные требования?

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

12. Параллельный дизайн (I): распределение процессовПравить

Итак, теперь давайте подойдем поближе к вопросу «процессы против потоков». Давайте дадим каждому отдельному компоненту процесс, управляющий им:

  1. Окна. (Каждый запустит пример одинаковой winctl-функции с разными аргументами.)
  2. Мышь
  3. Клавиатура.
  4. Интерфейс пользователя для оконного управления.
  5. Соединение с файловым сервером, который будет получать запросы 9P.
  6. Каждый входящий клиентский запрос ввода-вывода.

Все эти процессы будут общаться лишь посредством сообщений в каналах.

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

13. Процессы против потоковПравить

Выбор любого из них зависит от двух факторов: (1) системные вызовы блокировки и (2) протоколы с блокировкой.

1. При блокировке процесса с помощью системного вызова (read, write, и т.п.) будут заблокированы все потоки данного процесса. Следовательно, нам необходимо выполнять системные вызовы блокировки (прочитать мышь, прочитать 9P pipe, и т.п.) в отдельных процессах, и передавать их данные через каналы после того как они их получат.

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

Наша общая конструкция такова:

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

14. КартинаПравить

Прямоугольники — процессы, эллипсы — потоки.

Наличествуют и другие связи, напр., поток интерфейса пользователя также общается с потоками управления окном (window control threads — Wctl) для выполнения команды resize, и т.д.

15. КомментарииПравить

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

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

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

Этот метод позволяет писать ПО относительно легко.

16. Xfids (1)Править

Xfids отвечает за состояние единого сообщения 9P. Они управляются как пул анонимных потоков, которые размещаются и передаются сообщению 9P динамически.

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

17. Xfids (2): процесс 9PПравить

      Xfid *x;

      for(;;){
          read(fd, message);
          if(x == 0){
              sendp(cxfidalloc, nil);
              x = recvp(cxfidalloc);
          }
          преобразование message в x;
          x = (*fcall[x->type])(x);
      }
  extern void xfidread(Xfid*);

  static
  Xfid*
  fsysread(Xfid *x)
  {
      if(read of directory){
      оперирование message;
      return x;
      }
      sendp(x->c, xfidread);
      return nil;
  }

18. Xfids (3): потоки в основном процессеПравить

Процесс-распределитель тривиален; большая часть кода в данном примере опущена. Он запускает новый Xfid схожий с этим:

    x=emalloc(sizeof(Xfid));
    x->c=chancreate(sizeof(void(*)(Xfid*)), 0);
    threadcreate(xfidctl, x, 16384);

Контроллер Xfid во многом схож с этим:

  void
  xfidctl(void *arg)
  {
      Xfid *x;
      void (*f)(Xfid*);
      x = arg;
      for(;;){
          f = recvp(x->c);
          (*f)(x);
          if(decref(x) == 0)
               sendp(cxfidfree, x);
          }
  }
  void
  xfidread(Xfid *x)
  {
      /* управление чтением как потоком главного процесса */
  }

Оригинал: http://cm.bell-labs.com/who/rob/lec5.pdf  © Перевод на русский язык, Андрей С. Кухар, 2004

Обнаружено использование расширения AdBlock.


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

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

Также на Фэндоме

Случайная вики