Все операционные системы написаны на С. Не пора ли переписать их на Rust?
Системный программист рассказывает, почему операционную систему нельзя написать на Python или Java, но можно на Rust.
Кадр: сериал «Мистер Робот»
Брайан Кантрилл
об авторе
Системный программист с двадцатилетним стажем, сооснователь и технический директор Oxide Computer Company. С 1996 по 2006 год разрабатывал ядро ОС Solaris в Sun Microsystems, а с 2010 по 2019 год — SmartOS в компании Joyent.
В докладе на конференции QCon Брайан Кантрилл объясняет, почему многим системным программистам нравится Rust и почему на этом языке будут писать современные операционные системы.
В статье мы пересказали основные идеи доклада.
Если я спрошу, не пора ли переписать все операционные системы на Rust, по закону заголовков Беттериджа вы можете сказать «нет». Но я приведу много доводов, почему стоит ответить «да». Ещё я расскажу, зачем ставлю в названии статьи вопросительный, а не восклицательный знак.
Что такое операционная система
На первый взгляд это простой вопрос, но начнём с определения программного обеспечения. Считается ли им, например, алгоритм Евклида? Нет, потому что он появился раньше компьютеров.
То же и с операционной системой. ОС — это то, что работает поверх железа. Но не только физического, ведь её можно запустить в облаке на виртуальном оборудовании. Получается, что и здесь всё сложно.
Если говорить проще, операционная система — программа, которая позволяет запускать на железе стороннее ПО. Если ОС перестаёт работать, все остальные процессы завершаются вместе с ней.
У операционной системы есть ядро — часть с полным доступом к ресурсам процессора, памяти и другого оборудования. Но кроме ядра в ОС ещё есть библиотеки, команды и демоны.
Как развивались операционные системы
Подобия ОС писали на ассемблере уже после Второй мировой. Но полноценная операционная система появилась в 1961 году — это была MCP, написанная на языке ESPOL. Её создали для компьютера Burroughs B5000, который опередил своё время, но был коммерчески бесполезен.
В 1964 году в MIT попытались развить идею и начали разрабатывать CTSS — мультизадачную операционную систему, которая умела распределять аппаратные ресурсы между разными программами и пользователями. Её назвали Multics.
Создатели Multics хотели сделать всё правильно, но случилось то, что я называю синдромом второй системы. Они решили переписать с нуля почти все компоненты, поэтому проект получился огромный, а сроки сдачи переносились всё дальше.
ОС писали на языке PL/I, а его компилятор отдали разрабатывать аутсорсинговой компании, но у той ничего не вышло. Чтобы спасти положение, команда учёных создала язык EPL и продолжила работу на нём.
В 1969 году Bell Labs, одна из участниц программы, посчитала проект бесперспективным и вышла из него. А сотрудник Bell Labs Кен Томпсон сделал на его базе UNIX — операционную систему для мини-компьютера PDP-7.
UNIX и языки высокого уровня
Некоторые думают, что UNIX написали на С, но это не так — её полностью разработали на ассемблере. В отличие от авторов Multics, у разработчиков UNIX не было синдрома второй системы. Её создатели сначала делали работающий компонент, а потом писали к нему документацию.
В том же 1969 году в Bell Labs создали язык B. На нём написали некоторые утилиты UNIX, причём и тут не обошлось без ассемблера.
Но разработчиков UNIX не устраивала производительность языка B. Да, они считали, что операционную систему можно сделать на языке высокого уровня, но B для этого не годился — в нём не хватало байтовой адресации.
Тогда придумали язык С. В первой версии в нём не было структур — они появились только к 1973 году (понадобились для ядра UNIX). По той же причине добавили и битовые поля.
Язык дорабатывали постепенно — как раз в этом и его сила, и его слабость. Меня бесит, что в нём нет логического XOR — один из создателей языка объяснял это тем, что XOR не подходит для вычислений по короткой схеме.
Но С всё равно развивался. В нём появились макросы — а это одна из вещей, которые мне очень нравятся и в Rust. То же и с препроцессорами — многие не любят их использовать, но они важны для DTrace, ZFS и других систем.
Операционные системы в 1980–1990-е годы
В 1980-е годы С доминировал. На нём были написаны почти все операционные системы. Но в 1990-е стало популярным объектно-ориентированное программирование, и ОС на C объявили устаревшими. Считали, что скоро их заменят ОС на Java и C++. Но эти попытки провалились, и одна из причин — синдром второй системы.
Я помню 1990-е годы, когда гендиректором Apple был Джил Амелио. Компания громко рекламировала Mac OS Copland, но никак не могла её выпустить. Остальные же компании из Кремниевой долины ждали, пока Apple разорится, чтобы по дешёвке выкупить её имущество.
А Sun Microsystems разрабатывала операционную систему Spring — на C++. Ещё в студенчестве мне в руки попал CD-диск со Spring: я попробовал её установить, но компьютер не запустился. Оказалось, что у меня только 32 МБ оперативной памяти, а система требовала минимум 128 МБ. В наше время это всё равно что 2 ТБ RAM.
Не получилось сделать и ОС на Java. В этом языке нет беззнакового типа данных, без которого системе трудно взаимодействовать с железом.
Операционные системы в 2000-х
Когда появился Linux, написание систем на языке C стало мейнстримом. Много кто пробовал создать ядро ОС на C++, но из этих попыток ничего не вышло. Хотя есть исключения — та же Haiku. С одной оговоркой — всё-таки это был любительский проект, ничего серьёзного.
В то же время, в начале 2000-х, главными языками были Java и C++. А потом заметными стали Ruby, Python и JavaScript. Но все они фокусируются на увеличении скорости разработки. Никто в здравом уме не пробовал создать ОС на Ruby или Python.
JavaScript сначала был не слишком популярным. Но им стали активно пользоваться в 2006 году, когда все поняли, что в браузерах появился полноценный язык, на котором можно создавать веб-приложения. Для меня JavaScript — это замаскированный Lisp в браузере, но без многочисленных скобок.
К 2010-м годам системные программисты хотели получить язык, который был бы таким же производительным, как C, но в то же время обладал бы преимуществами других языков — например, методом split () и регулярными выражениями.
Из этого вышло много интересного. Например, появились мощные среды выполнения JavaScript, в частности движок V8, который можно было запускать на сервере. Потом появился Node.js. Мне очень нравится JS, но в мире системного программного обеспечения с ним было бы чересчур много проблем.
Некоторые сотрудники Bell Labs перешли в Google и разработали там язык Go. Он лишён многих недостатков JavaScript, но у него есть некоторые особенности.
В своём выступлении разработчик из Google Адин Сканнелл рассказал, что на Go можно создать ядро операционной системы, но у Go и JavaScript есть общая проблема — сборщики мусора. Они только замедляют системные программы, а потому не подходят для создания операционных систем.
Что особенного в языке Rust
Я написал на C++ сто тысяч строк кода и больше никогда не хочу к нему возвращаться. Меня всё сильнее и сильнее интересует Rust, потому что мне нравятся его ценности — это быстрый и безопасный язык для системного ПО.
Одна из самых интересных особенностей Rust — понятие владения. Язык статически определяет, кому что принадлежит. Компилятор выделяет вам память, а затем освобождает её, когда вы закончите с ней работать. А если он не знает, кому принадлежит память, то он её одалживает. Это называется заимствованием. Такой процесс исключает утечку ресурсов и обеспечивает безопасность — одна программа не может перезаписать память другой. И это действительно важно.
В Rust есть и другие функции, которые мне нравятся:
Алгебраические типы. Позволяют превосходно обрабатывать ошибки, работают примерно как объединение в C.
Гигиенические макросы. У меня их не было в C, и я буквально не знал, как пишется слово «гигиенический». Но такой макрос, который можно получить в выводе абстрактного синтаксического дерева вместе с другим программным кодом, — это удивительно.
Продуманные внешние функции. Интерфейс внешней функции в Rust очень хорошо продуман — вы можете взять код C и вставить его в программу на Rust или наоборот.
Ключевое слово unsafe. Его используют, чтобы выключить безопасный доступ к памяти и выполнять операции, которые компилятор иначе бы не разрешил.
Можно ли написать операционную систему на Rust
Я думаю, что на Rust можно смело писать операционные системы. Подобный язык мы ждали последние 30 лет.
Первая попытка, о которой я знаю, — система Weenix. Её создал студент Захари Эспириту для своей дипломной работы. Он подробно описывает проблемы, с которыми столкнулся в процессе.
С 2015 года небольшие операционные системы на Rust появлялись одна за другой: вышли Redox, Tock, IntermezzOS, BlogOS, QuiltOS, Rux и другие. IntermezzOS и BlogOS — учебные проекты, а Tock создана для интернета вещей.
К сожалению, у этих ОС нет бинарной совместимости с Linux, а значит, на них не запускается большая часть линуксовых программ. Поэтому я думаю, что гибридные подходы — самый правильный способ написать ОС на Rust:
Подход | В чём его смысл |
---|---|
Добавлять в ядра на С новые компоненты на Rust | Мне нравится, что С и Rust умеют взаимодействовать друг с другом. Можно сохранить ядро, написанное на C или ассемблере, а на Rust разрабатывать драйверы, файловые системы и прошивки |
Писать на Rust компоненты операционной системы | В ОС входит не только ядро, но и утилиты, демоны, диспетчер служб, диспетчер устройств, управление сбоями и отладчики. Их можно с успехом переписать на Rust |
Переписать прошивку с DOS на Rust | Много критически важного системного ПО работает под управлением DOS. Большинство проблем этой прошивки можно решить, если переписать её на Rust. Тот, кто это сделает, окажет человечеству огромную услугу |
Почему я жду появления гибридных операционных систем на С и Rust
Я очень оптимистично отношусь к Rust. Думаю, мы можем использовать его в операционных системах: в прошивке, в расширениях для ядра, при создании компонентов ОС, хотя на практике наверняка будет много трудностей.
Rust совместим с системами на C, и в этом его красота. Такой язык открывает новые возможности.