Я начал думать об этой проблеме в контексте этикета в списке рассылки ядра Linux. Ядро Linux, как самый известный в мире и, пожалуй, самый успешный и важный проект свободного программного обеспечения, получает много прессы. И основатель и руководитель проекта, Линус Торвальдс, явно не нуждается в представлении здесь.
Линус время от времени привлекает противоречие с его пламенем на LKML. По его собственному признанию, эти языки пламени часто нарушают пространство пользователя. Что подводит меня к моему вопросу.
Могу ли я иметь исторический взгляд на то, почему нарушение пользовательского пространства - это такая плохая вещь? Насколько я понимаю, нарушение пользовательского пространства потребовало бы исправлений на уровне приложения, но разве это плохо, если оно улучшает код ядра?
Насколько я понимаю, заявленная политика Линуса заключается в том, что не нарушая пользовательского пространства, нужно все остальное, включая качество кода. Почему это так важно, и каковы плюсы и минусы такой политики?
(Очевидно, что у такой политики есть определенные недостатки, которые последовательно применяются, поскольку у Линуса иногда возникают «разногласия» с его старшими лейтенантами в LKML именно по этой теме. Насколько я могу судить, он всегда в этом разбирается.)
источник
Ответы:
Причина не историческая, а практическая. Есть много-много-много программ, которые работают поверх ядра Linux; если интерфейс ядра ломает эти программы, то все должны будут обновить эти программы.
Теперь это правда, что большинство программ на самом деле не зависят напрямую от интерфейсов ядра ( системные вызовы ), а только от интерфейсов стандартной библиотеки C ( оболочки C) вокруг системных вызовов). О, но какая стандартная библиотека? Glibc? uClibC? Dietlibc? Bionic? MUSL? и т.п.
Но есть также много программ, которые реализуют специфичные для ОС сервисы и зависят от интерфейсов ядра, которые не предоставляются стандартной библиотекой. (В Linux многие из них предлагаются через
/proc
и/sys
.)И тогда есть статически скомпилированные двоичные файлы. Если обновление ядра нарушает один из них, единственным решением будет перекомпилировать их. Если у вас есть источник: Linux также поддерживает проприетарное программное обеспечение.
Даже когда источник доступен, собрать все это может быть больно. Особенно, когда вы обновляете свое ядро, чтобы исправить ошибку с вашим оборудованием. Люди часто обновляют свое ядро независимо от остальной части своей системы, потому что им нужна аппаратная поддержка. По словам Линуса Торвальдса :
Он также объясняет, что одна из причин сделать это строгое правило состоит в том, чтобы избежать ада зависимости, когда вам придется не только обновить другую программу, чтобы заставить работать какое-то более новое ядро, но также обновить еще одну программу, и другую, и другую. потому что все зависит от определенной версии всего.
В пользовательском пространстве эти взаимные зависимости обычно разрешаются путем хранения разных версий библиотек; но вы можете запустить только одно ядро, поэтому оно должно поддерживать все, что люди могут захотеть сделать с ним.
Официально ,
На практике, однако,
Что чаще всего меняется, так это интерфейсы, предназначенные только для использования аппаратными программами, в
/sys
. (/proc
с другой стороны, который с момента введения/sys
был зарезервирован для сервисов, не связанных с аппаратным обеспечением, в значительной степени он никогда не ломался несовместимыми способами.)В итоге,
и это плохо, потому что есть только одно ядро, которое люди хотят обновить независимо от остальной части своей системы, но существует множество приложений со сложной взаимозависимостью. Поддерживать стабильность ядра проще, чем обновлять тысячи приложений на миллионах различных настроек.
источник
В любых взаимозависимых системах есть два основных варианта. Абстракция и интеграция. (Я специально не использую технические термины). С Abstraction вы говорите, что когда вы вызываете API, который, хотя код API может измениться, результат всегда будет одинаковым. Например, когда мы звоним,
fs.open()
нам все равно, сетевой диск, SSD или жесткий диск, мы всегда получим дескриптор открытого файла, с которым мы можем что-то сделать. С помощью «интеграции» цель состоит в том, чтобы предоставить «лучший» способ сделать что-либо, даже если путь изменится. Например, открытие файла для сетевого ресурса может отличаться от файла на диске. Оба способа довольно широко используются в современном рабочем столе Linux.С точки зрения разработчиков, это вопрос «работает с любой версией» или «работает с определенной версией». Отличным примером этого является OpenGL. Большинство игр настроено на работу с определенной версией OpenGL. Неважно, если вы компилируете из исходного кода. Если игра была написана для использования OpenGL 1.1, и вы пытаетесь заставить ее работать на 3.x, вы не сможете хорошо провести время. На другом конце спектра некоторые вызовы, как ожидается, будут работать, несмотря ни на что. Например, я хочу позвонить,
fs.open()
мне не важно, какая у меня версия ядра. Я просто хочу дескриптор файла.Есть преимущества для каждого пути. Интеграция предоставляет «новые» функции за счет обратной совместимости. При этом абстракция обеспечивает стабильность по сравнению с «новыми» вызовами. Хотя важно отметить, что это вопрос приоритета, а не возможности.
С общественной точки зрения, без действительно очень веских причин, абстракция всегда лучше в сложной системе. Например, представьте,
fs.open()
работает ли по- разному в зависимости от версии ядра. Тогда простая библиотека взаимодействия с файловой системой должна будет поддерживать несколько сотен различных методов «открытого файла» (или, вероятно, блоков). Когда выйдет новая версия ядра, вы не сможете «обновиться», вам придется протестировать каждую часть программного обеспечения, которую вы использовали. Ядро 6.2.2 (подделка) может просто сломать ваш текстовый редактор.В некоторых реальных примерах OSX не заботится о взломе пользовательского пространства. Они стремятся к «интеграции» над «абстракцией» чаще. И при каждом серьезном обновлении ОС все ломается. Это не значит, что один способ лучше другого. Это выбор и дизайнерское решение.
Наиболее важно, что экосистема Linux заполнена удивительными проектами с открытым исходным кодом, где люди или группы работают над проектом в свободное время или потому, что инструмент полезен. Имея это в виду, что после того, как он перестанет быть веселым и станет PIA, эти разработчики пойдут куда-то еще.
Например, я представил патч для
BuildNotify.py
. Не потому, что я альтруист, а потому, что я использую инструмент, и мне нужна особенность. Это было легко, поэтому здесь есть патч. Если бы это было сложно или громоздко, я бы не использовалBuildNotify.py
и нашел бы что-то еще. Если бы каждый раз, когда выходило обновление ядра, мой текстовый редактор ломался, я бы просто использовал другую ОС. Мой вклад в сообщество (пусть и небольшой) не будет продолжаться или существовать, и так далее.Итак, проектное решение было принято, чтобы абстрагировать системные вызовы, чтобы когда я это делал,
fs.open()
он просто работал. Это означает сохранение в течениеfs.open
долгого времени послеfs.open2()
завоевания популярности.Исторически это было целью систем POSIX в целом. «Вот набор вызовов и ожидаемых возвращаемых значений, вы выясните середину». Опять же по причинам портативности. Почему Линус выбирает использовать эту методологию, является внутренним для его мозга, и вам придется попросить его точно знать, почему. Однако, если бы это был я, я бы выбрал абстракцию вместо интеграции в сложной системе.
источник
Это дизайнерское решение и выбор. Линус хочет иметь возможность гарантировать разработчикам пользовательского пространства, что, за исключением крайне редких и исключительных (например, связанных с безопасностью) обстоятельств, изменения в ядре не будут нарушать их приложения.
Плюсы в том, что разработчики в пользовательском пространстве не обнаружат, что их код внезапно сломается на новых ядрах по произвольным и капризным причинам.
Недостатки в том, что ядро должно хранить старый код, старые системные вызовы и т. Д. Всегда (или, по крайней мере, после их использования).
источник