Думаю, общей информации по Inferno уже достаточно, и можно перейти к главному вопросу: что из себя представляет Inferno изнутри, с точки зрения программиста? В чём заключается взаимодействие программиста со средой предоставляемой Inferno? Сколько нюансов поведения и разных видов сущностей должен держать в голове программист в Inferno?
Например, под линухом для эффективного и качественного программирования нужно держать в голове как минимум несколько очень толстых томов Стивенса, начиная с APUE (Advanced Programming in the UNIX Environment, Second Edition, 925 страниц, обошлась мне в $75+доставка с амазона). И слава Богу, что такая книга вообще есть в природе, без неё было бы совсем туго, кстати!
А всё потому, что под линухом мы имеем множество разных сущностей (файлы/каталоги, процессы, терминалы, сигналы, нити, пайпы, сообщения, семафоры, разделяемая память, сетевые сокеты, unix сокеты, псевдо-терминалы, etc.), и у каждой море нюансов поведения (блокирующий I/O, неблокирующий I/O, асинхронный I/O, мультиплексирование I/O, fcntl/ioctl, etc.) в разных условиях! Насколько я понимаю, под виндой ситуация ещё хуже т.к. плюс к примерно аналогичному зоопарку добавляется по несколько версий API, которые Microsoft называет "новыми революционными технологиями" и выпускает раз в 2-3 года (у Джоэля Спольски была хорошая статья на эту тему).
Так вот, в Inferno таких сущностей ровно ТРИ: нити, каналы и файлы. И нюансов поведения у них значительно меньше: файлы поддерживают исключительно блокирующий I/O без возможности мультиплексирования, каналы тоже блокирующие но их можно мультиплексировать, файлы все "обычные" и никаких fcntl/ioctl в природе нет, etc. Причём этих трёх сущностей хватает, чтобы покрыть практически всю ту функциональность, для которой в UNIX-системах развели этот зоопарк!
1-я сущность: процесс/нить.
В Inferno нет отличия между процессами и нитями. Изолирование и группирование нитей осуществляется через namespaces. Вот сравнительная таблица свойств процессов Inferno по сравнению с процессами линуха:
Linux | Inferno | |
---|---|---|
Open files | + | + |
UID, GID, EUID, EGID | + | ? |
Supplementary group IDs | + | |
Process group ID | + | + |
Session ID | + | |
Controlling terminal | + | |
SUID and SGID flags | + | |
Current working dir | + | + |
Root dir | + | + |
umask | + | |
Signal mask and dispositions | + | |
The close-on-exec flag for open files | + | |
Environment | + | + |
Attached shared memory segments | + | |
Memory mappings | + | |
Resource limits | + | |
File locks for open files | + | |
Pending alarms | + | |
Namespace | + |
Что касается UID/GID/EUID/EGID, то UID, теоретически, в Inferno есть. А практически его как бы и нет - разделение прав доступа к ресурсам обеспечивается сертификатами, протоколом Styx, и namespace… а имя юзера никакой роли в этом процессе не играет и используется, насколько я понимаю, исключительно для определения имени домашнего каталога. Возможно я что-то не уловил, но похоже что Inferno под типовые определения однопользовательской/многопользовательской системы просто не попадает, это нечто иное. :)
Для управления практически всеми (кроме текущего каталога) свойствами процесса Inferno служит один, довольно простой сискол pctl.
Процессы в Inferno можно: порождать (оператором spawn в Limbo), изменять их свойства (сисколом pctl), завершать (оператором exit в Limbo) и … и всё, в общем! По крайней мере в той части, которая касается API Inferno. В принципе кроме этого можно ещё оперировать процессами через файлы в каталоге /prog/, но это уже относится к файловому API.
2-я сущность: каналы.
С каналами всё ещё проще, чем с процессами:
-
их можно создавать (как переменные в Limbo типа chan of что-то)
-
можно удалять (когда переменная выходит из области видимости либо в неё присваивают nil)
-
можно с помощью операторов Limbo chan← и ←chan атомарно, в блокирующем режиме принимать/передавать данные между нитями
-
можно мультиплексировать ввод/вывод в каналы
Этой функциональности достаточно, чтобы заменить все виды синхронизации и IPC существующие в линухе.
3-я сущность: файлы/каталоги.
Работа с файлами в Inferno не намного проще, чем в линухе - за исключением не нужных fcntl и ioctl API практически идентичное: mount, bind, chdir, open, dup, read, stat, diropen, dirread, etc…
Жизнь, правда, заметно упрощается за счёт того, что весь I/O в файлы только блокирующий, и мультиплексирования тоже нет - если что-то из этого арсенала необходимо это решается выделением блокирующих задач в отдельные нити (что, кстати, стимулирует более продуманную архитектуру приложения).
В принципе в Inferno ещё есть такой рудимент как пайпы. Но, в отличие от линуха, где они используются как одно из основных средств IPC, в Inferno пайпы это что-то типа workaround-а для случая, когда кому-нить (например, библиотечной функции) нужен файловый дескриптор, а вам хочется вместо дескриптора реального файла подсунуть ей "виртуальный" дескриптор ведущий не в реальный файл, а в ваш код.
Ещё добавляется работа со специфичными фичами Inferno - namespaces, поддержка протокола Styx и его сертификаты, авторизация, аутентификация и шифрование. Но эта часть работы обычно выполняется админом в командной строке (или в sh-скрипте запускающем ваше приложение), и никак не усложняет программирование приложения.
И всё?
И всё! Всё остальное это голые вычисления - обсчитывание данных в переменных: поддержка разных форматов файлов, баз данных, сетевых протоколов, etc. Это всё прикладуха, и никак не усложняет среду в которой работают программы и не вводит новых сущностей.
Бонус.
На закуску я повторю список сущностей линуха и покажу чем все они заменяются в Inferno:
Linux | Inferno |
---|---|
файлы/каталоги | файлы/каталоги |
процессы | нити |
терминалы | - |
сигналы | каналы |
нити | нити |
пайпы | - (тот workaround не считается) |
сообщения | каналы |
семафоры | каналы |
разделяемая память | каналы |
сетевые сокеты | файлы |
unix сокеты | - (надеюсь, скоро здесь будут стоять "файлы") |
псевдо-терминалы | - |