Про операционную систему House

В одной давней уже дискуссии речь зашла о том, что все современные операционные системы — говно, и true-программисты должны писать все на правильных языках, а именно — на Haskell. В качестве примера правильной ОС была приведена система House — как утверждает Википедия, «экспериментальная операционная система, написанная целиком на функциональном языке программирования Haskell».

Я не сторонник подхода «а давайте везде использовать ООП/функции высших порядков/монады (манды?)/Haskell/чистый ассемблер/придумать-и-вписать-что-то-свое» — особенно когда объявляется, что только этот подход позволит избавиться от багов, ускорить десятикратно работу программистов, и главное — является единственно верным. Именно это заставило меня со скептицизмом отнестись к заявлению [info]udpn о том, что Haskell — правильный язык для написания операционных систем, после чего я пообещал «посмотреть» на пресловутый House.

Разумеется, пообещав, я благополучно записал это обещание в свой импровизированный todo list, где оно и протерялось. Вспомнить про него меня заставил вчерашний срач, начатый на хабре силами [info]vit_r и продолженный в ЖЖ [info]metaclass.

Как известно, в любых компьютерных программах «волшебным образом» заводятся ошибки. С ними можно поступить тремя способами — грубо говоря, Abort, Retry и Ignore. За третий способ бьют морду уже в программистских ПТУ, так что речь пойдет о двух более принятых в приличном обществе стратегиях. Более подробно об этом можно почитать по ссылкам выше, а также найти в ЖЖ [info]vit_r расширенный вариант хабровской записи. Я же вернусь к теме операционных систем.

Стратегии «обработки ошибок», которые я назвал abort и retry, появились, видимо, уже на заре программирования. В операционной системе MULTICS, созданной в середине 60-х, по разного рода пересказам одних и тех же жареных фактов в учебниках по операционным системам, большую часть кода занимала обработка ошибок — то есть попытки восстановить состояние системы, «несмотря ни на что». Это можно отнести к стратегии «retry».

Другой вариант был реализован в «потомке» MULTICS — точнее, в самых первых версиях Unix. При каких-либо странных ситуациях система просто «впадала в панику» и благополучно «грохалась». Сформулированный в виде «Если надо выйти из строя, делайте это шумно и как можно быстрее», этот подход обычно относят к «философии UNIX» вообще.

Естественно, что для «операционных систем вообще» желательно «выходить из строя» как можно реже. Именно этому посвящено и замечание [info]migmit с последовавшей небольшой дискуссией про микроядра в целом (как один из способов совместить fail fast и общую «отказоустойчивость») и горячо мной любимый Minix в частности.

vityaz

Если верить адептам Haskell-ной веры, то в вопросе «налево пойдешь — коня потеряешь, направо пойдешь — сам пропадешь» «Abort или Retry?» имеется еще один вариант — якобы их истинно правильный язык программирования сам не дает допустить ошибку. В качестве примера такого применения Haskell и была приведена ОС House.

К сожалению, в данном случае мы имеем дело с совершенно искренним заблуждением о том, что используя «правильные инструменты», можно полностью оградить себя от ошибок в программах. Говоря терминами из провокационной записи [info]vit_r, так ведут себя «гении». Это поведение очень похоже на разнообразных новоявленных великих фотографов, которые покупают в «Эльдорадо» в кредит недорогую зеркалку и ведут себя, как Картье-Брессоны. К сожалению, ни дорогой фотоаппарат, ни Haskell в руках «идиота» не превратят его в «гения».

Вернемся непосредственно к House. Архитектура этой системы, согласно ее описанию, довольно проста. Это «микроядерная» операционная система, с явным разделением «политики» (реализованной на Haskell) и «механизма» (на C с ассемблерными вставками). Ядро ОС — это примерно 1200 тысячи строчек на Haskell и 750 строчек на C. На C реализованы некоторые компоненты, необходимые для работы Haskell-ного рантайма и «низкоуровневого» взаимодействия с «железом».

Сишная часть реализует в этой операционке специальную монаду H — от Hardware, позволяющую хаскелльному коду выполнять операции с такими штуками, как страницы памяти или обработчики прерываний. Кроме того, микроядро на Haskell умеет взаимодействовать с драйверами устройств — тоже написанными на Haskell, но выполняющимися не в Ring 0, а в нормальном «пользовательском» Ring 3. В общем, классическое микроядро, ничего особенного.

Правда, весь кайф обламывает вот какой момент. Ядро тащит с собой весь рантайм от GHC, который оценивается где-то в 50 тысяч строк кода на Си. Там, в этом рантайме, находится хаскельное расширение Concurrent Haskell — которое в этой ОС выполняет функции планировщика и менеджера процессов. Получается типичный пример «каши из топора» — с тем же успехом House можно называть «написанной на Си». Более того, trusted computing base оказывается просто громадной по сравнению, скажем, с Minix, где все ядро — это около 7 тысяч строк на Си с небольшими ассемблерными вставками.

Очень сложно говорить о написании ОС на языках с «богатым» рантаймом, как у Haskell. Как только в этом рантайме реализованы потоки — то теряется смысл разговора о планировщике, он реализуется исключительно средствами, встроенными в язык. Если рантайм окажется, так сказать, POSIX-эквивалентным, то говорить о разработке ОС на таком языке уже как-то смешно.

Что интересно — от ошибок не спасает даже Haskell. В более поздней статье с описанием этой операционки приводится пример типичной ошибки с «граничными условиями» — вместо 4096 байт менеджер памяти пытался обнулить 4097, правда, с оговорочкой — мол, если бы мы аккуратно использовали вывод типов, то этой ошибки и не возникло бы. Так используйте, кто мешает?

В целом — проект заслуживает внимания, как своего рода «технический курьез», типа построенного без единого гвоздя деревянного здания. Правда, при внимательном рассмотрении гвозди все же обнаруживаются — но тщательным образом замаскированы. Более интересно тут другое — что в «настоящей» микроядерной ОС системное и прикладное программирование мало чем отличаются. В принципе, в том же Minix никто не мешает написать системный компонент, типа драйвера устройства или даже планировщика задач на каком-нибудь экзотическом для этой задачи языке. А что, вас не устроит драйвер сетевой карты на Common Lisp?

Про операционную систему House: 2 комментария

    1. Если только идеей использовать «нетрадиционный» язык программирования.

      В Singularity вся межпроцессная изоляция осуществляется только за счет фич .NET и проверки инвариантов на этапе инсталляции. Использование для этого возможностей «железа» выглядит как-то надежней.

Добавить комментарий для Шура Люберецкий Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *