В одной давней уже
дискуссии речь зашла о том, что все современные операционные системы - говно, и true-программисты должны писать все на правильных языках, а именно - на Haskell. В качестве примера правильной ОС была приведена система
House - как утверждает Википедия, “экспериментальная операционная система, написанная целиком на функциональном языке программирования Haskell”.
Я не сторонник подхода “а давайте везде использовать ООП/функции высших порядков/монады (манды?)/Haskell/чистый ассемблер/придумать-и-вписать-что-то-свое” - особенно когда объявляется, что только этот подход позволит избавиться от багов, ускорить десятикратно работу программистов, и главное - является единственно верным. Именно это заставило меня со скептицизмом отнестись к заявлению
udpn о том, что Haskell - правильный язык для написания операционных систем, после чего я пообещал “посмотреть” на пресловутый House.
Разумеется, пообещав, я благополучно записал это обещание в свой импровизированный todo list, где оно и протерялось. Вспомнить про него меня заставил вчерашний срач,
начатый на хабре силами
vit_r и
продолженный в ЖЖ
metaclass.
Как известно, в любых компьютерных программах “волшебным образом” заводятся ошибки. С ними можно поступить тремя способами - грубо говоря, Abort, Retry и Ignore. За третий способ бьют морду уже в программистских ПТУ, так что речь пойдет о двух более принятых в приличном обществе стратегиях. Более подробно об этом можно почитать по ссылкам выше, а также найти в ЖЖ
vit_r расширенный вариант хабровской записи. Я же вернусь к теме операционных систем.
Стратегии “обработки ошибок”, которые я назвал abort и retry, появились, видимо, уже на заре программирования. В операционной системе MULTICS, созданной в середине 60-х, по разного рода пересказам одних и тех же жареных фактов в учебниках по операционным системам, большую часть кода занимала обработка ошибок - то есть попытки восстановить состояние системы, “несмотря ни на что”. Это можно отнести к стратегии “retry”.
Другой вариант был реализован в “потомке” MULTICS - точнее, в самых первых версиях Unix. При каких-либо странных ситуациях система просто “впадала в панику” и благополучно “грохалась”. Сформулированный в виде “Если надо выйти из строя, делайте это шумно и как можно быстрее”, этот подход обычно относят к “философии UNIX” вообще.
Естественно, что для “операционных систем вообще” желательно “выходить из строя” как можно реже. Именно этому посвящено и
замечание migmit с последовавшей небольшой дискуссией про микроядра в целом (как один из способов совместить fail fast и общую “отказоустойчивость”) и горячо мной любимый Minix в частности.
Если верить адептам Haskell-ной веры, то в вопросе “налево пойдешь - коня потеряешь, направо пойдешь - сам пропадешь” “Abort или Retry?” имеется еще один вариант - якобы их истинно правильный язык программирования сам не дает допустить ошибку. В качестве примера такого применения Haskell и была приведена ОС House.
К сожалению, в данном случае мы имеем дело с совершенно искренним заблуждением о том, что используя “правильные инструменты”, можно полностью оградить себя от ошибок в программах. Говоря терминами из провокационной записи
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?
Запись опубликована в
блоге Шуры Люберецкого. Вы можете оставлять свои комментарии
там, используя свое имя пользователя из ЖЖ (вход по OpenID).