Один из краеугольных камней архитектуры Inferno - юниксовая идея с файлами-устройствами доведена до предела: в Inferno файлами представлено абсолютно всё. Например, в Inferno нет понятия "сокет".
Файлы.
В Inferno файлами представлены не только устройства (аналог /dev/) и процессы (аналог /proc/), но и такие вещи как DNS resolver, сокеты и переменные окружения (environment).
Например, для того, чтобы открыть tcp-соединение на сайт www.habrahabr.ru, нужно проделать следующие операции:
-
открыть файл /net/cs
-
записать в него строку tcp!www.babrahabr.ru!http
-
считать из него ответ (это будет строка /net/tcp/clone 217.147.30.151!80)
-
открыть файл /net/tcp/clone
-
считать из него число (идентификатор этого соединения, далее ID), при этом в каталоге /net/tcp/ автоматически появится новый подкаталог /net/tcp/ID/ с файлами ctl, data, status, etc.
-
записать в файл /net/tcp/ID/ctl строку connect 217.147.30.151!80
-
читать/писать файл /net/tcp/ID/data
Пояснения к примерам. Примеры для краткости приведены на sh, а не Limbo.
-
";" - это приглашение sh.
-
">[1=0]" это перенаправление STDOUT на STDIN.
-
"<>/path" это открытие STDIN на чтение+запись в /path.
-
"read" читает из STDIN и выводит на STDOUT заданное кол-во байт.
-
"`{…}" это выполнить команду и вернуть её вывод.
; { echo -n 'tcp!www.habrahabr.net!http' >[1=0]; read -o 0 8192; } <>/net/cs /net/tcp/clone 209.85.84.157!80 ; { id=`{read} echo 'connect 209.85.84.157!80' >/net/tcp/$id/ctl echo 'HEAD / HTTP/1.0' >/net/tcp/$id/data echo 'Host: www.habrahabr.ru' >/net/tcp/$id/data echo >/net/tcp/$id/data read </net/tcp/$id/data } <>/net/tcp/clone HTTP/1.1 200 OK Date: Sun, 27 May 2007 11:33:42 GMT Server: Apache/2.0.52 (Red Hat) X-Powered-By: PHP/5.1.4 Set-Cookie: vsid=3X02X521137108; expires=Fri, 25-May-2012 11:33:43 GMT; path=/ Connection: close Content-Type: text/html; charset=UTF-8
С переменными окружения работа идёт аналогично - есть каталог /env/, файлы в котором это имена переменных, а содержимое файлов - значения переменных. Соответственно создание/удаление файла это создание/удаление переменной окружения.
Для доступа к информации по процессам используется каталог /prog/. Причём абсолютно все операции выполняются через его подкаталоги и файлы - в том числе отладка (т.е. не нужен сискол POSIX ptrace) и получение информации о статусе процесса (т.е. не нужны сисколы wait/waitpid).
Работа всех этих виртуальных файлов обеспечивается разными средствами - например /net/tcp/ и /env/ реализованы через драйвера Inferno, а DNS ресолвер /net/cs реализован обычным приложением.
Такой подход позволил упростить множество вещей:
-
для работы с сетью достаточно обычного файлового API, отдельные функции POSIX (socket, connect, bind, listen, etc.) стали не нужны
-
аналогично, нет специального API для работы с переменными окружения (clearenv, putenv, setenv, getenv, etc.)
-
поскольку протокол Styx позволяет расшаривать файлы по сети, то можно делать, например, следующие трюки:
-
если машина в локальной сети, не имеющая реального IP-адреса, подмонтирует себе каталог /net шлюза в инет, то она получит прямой выход в инет без необходимости настраивать на шлюзе штуки типа NAT или маскарада
-
если на удалённый сервер подмонтировать по сети файлы /dev/cons, /dev/keyboard и /dev/pointer с рабочей станции, то на сервере можно будет запускать графические приложения которые будут управляться с терминала рабочей станции - и всё это без специального протокола а-ля X-Window, со встроенной (в Styx) авторизацией, аутентификацией и шифрованием
-
если на локальную машину подмонтировать каталог /prog (аналог /proc) с удалённого сервера, то можно будет локальным отладчиком отлаживать процессы выполняющиеся на удалённой машине - и отладчик об этом даже знать не будет, потому что он просто работает через файлы в /prog
-
Но, с моей точки зрения, гораздо важнее не то, что отпала необходимость в куче сисколов, а то, что "объектов" особенности поведения которых необходимо знать для качественного программирования стало намного меньше! К примеру, в юниксах у файлов одни особенности, у специальных файлов (юникс-сокеты, пайпы, некоторые устройства) другие, а у сокетов третьи - а в Inferno всё это одинаковые файлы с одинаковым поведением.
Распределённые вычисления.
"Правильная" программа в Inferno должна писаться не в стиле традиционных юниксовых утилит (читаем STDIN, пишем STDOUT), а в стиле файлового сервера Styx. Иными словами входом/выходом у такой утилиты должен быть не STDIN/STDOUT, а виртуальный файл или каталог с файлами а-ля /net/cs или /net/tcp/.
Это позволит очень легко строить распределённые системы. Например, предположим в нашем проекте есть модуль который что-то считает. Он реализован в виде отдельного процесса, который экспортирует файл ./calc, в который можно писать задания и считывать из него результат. Если возникает потребность ускорить вычисления перенеся эту подзадачу на отдельный, более мощный сервер, то достаточно двух шагов: запустить этот модуль на другом сервере; подмонтировать файл ./calc с этого сервера. И всё - остальная часть проекта даже не заметит что этот модуль выполняется на другом сервере!
Namespaces.
Пространства имён (namespace) в Inferno аналогичны тем, которые используются во многих языках программирования… только в Inferno они применяются к файлам и каталогам.
Фактически привилегии и возможности программы под Inferno ограничены тем, к каким файлам (ибо любой ресурс = файл) она имеет доступ. Манипулируя namespace можно для каждого приложения создать свою, изолированную (а-ля chroot) среду, со своими устройствами в /dev (как выше в примере с удалённым терминалом), со своими сетевыми картами в /net (как выше в примере с NAT), etc.
К примеру, в винде есть такая фича - вы логинитесь с любого компа в сети и получаете СВОЙ рабочий стол и СВОЙ каталог "мои документы". В Inferno вы, залогинившись с любого терминала и имея доступ к своим ключам/сертификатам можете манипулируя namespace создать 100% ту же самую среду, которую вы имеете на своём основном компе. И для реализации этого никаких специальных "фич" в Inferno нет - обычные команды mount, bind и протокол Styx.
Возможно всё это звучит не очень принципиально, но принцип работы с приложениями кардинально изменяется - обычно мы пытаемся добиться того, чтобы приложение работало в самых разных условиях (что значительно его усложняет), а в Inferno мы для каждого приложения с помощью namespace, команд mount и bind создаём именно ту среду, на которую расчитано это приложение.