Empecé a pensar en este tema en el contexto de etiqueta en la lista de correo del kernel de Linux. Como el proyecto de software libre más conocido e indiscutiblemente más exitoso e importante del mundo, el núcleo de Linux recibe mucha prensa. Y el fundador y líder del proyecto, Linus Torvalds, claramente no necesita presentación aquí.
Linus ocasionalmente atrae controversia con sus llamas en el LKML. Estas llamas son frecuentemente, por su propia admisión, que ver con romper el espacio del usuario. Lo cual me lleva a mi pregunta.
¿Puedo tener una perspectiva histórica de por qué romper el espacio del usuario es algo tan malo? Según tengo entendido, romper el espacio del usuario requeriría correcciones en el nivel de la aplicación, pero ¿es esto algo malo si mejora el código del núcleo?
Según tengo entendido, la política declarada de Linus es que no romper el espacio del usuario supera todo lo demás, incluida la calidad del código. ¿Por qué es esto tan importante y cuáles son los pros y los contras de dicha política?
(Claramente, hay algunas desventajas de tal política, aplicada de manera consistente, ya que Linus ocasionalmente tiene "desacuerdos" con sus principales lugartenientes en la LKML sobre exactamente este tema. Hasta donde puedo decir, siempre se sale con la suya en el asunto).
fuente
Respuestas:
La razón no es histórica sino práctica. Hay muchos, muchos, muchos programas que se ejecutan sobre el kernel de Linux; Si una interfaz del núcleo rompe esos programas, entonces todos tendrían que actualizar esos programas.
Ahora es cierto que la mayoría de los programas no dependen de las interfaces del kernel directamente (las llamadas del sistema ), sino solo de las interfaces de la biblioteca estándar C (las envolturas de C alrededor de las llamadas del sistema). Ah, pero ¿qué biblioteca estándar? Glibc? uClibC? Dietlibc? ¿Biónico? Musl? etc.
Pero también hay muchos programas que implementan servicios específicos del sistema operativo y dependen de las interfaces del núcleo que no están expuestas por la biblioteca estándar. (En Linux, muchos de estos se ofrecen a través de
/proc
y/sys
.)Y luego hay binarios compilados estáticamente. Si una actualización del núcleo rompe uno de estos, la única solución sería recompilarlos. Si tiene la fuente: Linux también admite software propietario.
Incluso cuando la fuente está disponible, reunirlo todo puede ser una molestia. Especialmente cuando está actualizando su kernel para corregir un error con su hardware. Las personas a menudo actualizan su kernel independientemente del resto de su sistema porque necesitan el soporte de hardware. En palabras de Linus Torvalds :
También explica que una razón para hacer de esto una regla fuerte es evitar el infierno de la dependencia, donde no solo tendría que actualizar otro programa para que funcione un núcleo más nuevo, sino que también tenga que actualizar otro programa, y otro, y otro , porque todo depende de una cierta versión de todo.
En el espacio de usuario, esas dependencias mutuas generalmente se resuelven manteniendo diferentes versiones de la biblioteca; pero solo puede ejecutar un núcleo, por lo que tiene que soportar todo lo que la gente quiera hacer con él.
oficialmente ,
En la práctica, sin embargo,
Lo que cambia con más frecuencia son las interfaces que solo están destinadas a ser utilizadas por programas relacionados con el hardware, en
/sys
. (/proc
, por otro lado, que desde la introducción de/sys
se ha reservado para servicios no relacionados con el hardware, casi nunca se rompe de manera incompatible).En resumen,
y eso es malo porque solo hay un kernel, que la gente quiere actualizar independientemente del resto de su sistema, pero hay muchas aplicaciones con interdependencias complejas. Es más fácil mantener estable el kernel que mantener miles de aplicaciones actualizadas en millones de configuraciones diferentes.
fuente
En cualquier sistema interdependiente hay básicamente dos opciones. Abstracción e integración. (A propósito no estoy usando términos técnicos). Con Abstracción, estás diciendo que cuando haces una llamada a una API que, si bien el código detrás de la API puede cambiar, el resultado siempre será el mismo. Por ejemplo, cuando llamamos
fs.open()
no nos importa si se trata de una unidad de red, un SSD o un disco duro, siempre obtendremos un descriptor de archivo abierto con el que podamos hacer cosas. Con la "integración", el objetivo es proporcionar la "mejor" forma de hacer algo, incluso si la forma cambia. Por ejemplo, abrir un archivo puede ser diferente para un recurso compartido de red que para un archivo en el disco. Ambas formas se usan ampliamente en el escritorio moderno de Linux.Desde el punto de vista de los desarrolladores, se trata de "funciona con cualquier versión" o "funciona con una versión específica". Un gran ejemplo de esto es OpenGL. La mayoría de los juegos están configurados para funcionar con una versión específica de OpenGL. No importa si estás compilando desde la fuente. Si el juego fue escrito para usar OpenGL 1.1 y estás intentando que se ejecute en 3.x, no lo vas a pasar bien. En el otro extremo del espectro, se espera que algunas llamadas funcionen sin importar qué. Por ejemplo, quiero llamar
fs.open()
No quiero importarme en qué versión del kernel estoy. Solo quiero un descriptor de archivo.Hay beneficios en cada sentido. La integración proporciona características "más nuevas" a costa de la compatibilidad con versiones anteriores. Mientras que la abstracción proporciona estabilidad sobre las llamadas "más nuevas". Aunque es importante tener en cuenta que es una cuestión de prioridad, no de posibilidad.
Desde un punto de vista comunitario, sin una muy buena razón, la abstracción siempre es mejor en un sistema complejo. Por ejemplo, imagine si
fs.open()
funcionó de manera diferente dependiendo de la versión del kernel. Entonces, una simple biblioteca de interacción del sistema de archivos necesitaría mantener varios cientos de métodos diferentes de "archivo abierto" (o bloques probablemente). Cuando salió una nueva versión del kernel, no podría "actualizarse", tendría que probar cada pieza de software que utilizó. Kernel 6.2.2 (falso) puede simplemente romper su editor de texto.Para algunos ejemplos del mundo real, OSX tiende a no preocuparse por romper el espacio del usuario. Apuntan a la "integración" sobre la "abstracción" con mayor frecuencia. Y en cada actualización importante del sistema operativo, las cosas se rompen. Eso no quiere decir que una forma es mejor que la otra. Es una decisión de elección y diseño.
Lo más importante es que el ecosistema de Linux está lleno de increíbles proyectos de código abierto, donde las personas o grupos trabajan en el proyecto en su tiempo libre, o porque la herramienta es útil. Con eso en mente, en el momento en que deja de ser divertido y comienza a ser un PIA, esos desarrolladores irán a otro lugar.
Por ejemplo, envié un parche a
BuildNotify.py
. No porque sea altruista, sino porque uso la herramienta y quería una función. Fue fácil, así que aquí tienes un parche. Si fuera complicado o engorroso, no lo usaríaBuildNotify.py
y encontraría algo más. Si cada vez que salía una actualización del núcleo, mi editor de texto se rompía, simplemente usaría un sistema operativo diferente. Mis contribuciones a la comunidad (por pequeñas que sean) no continuarían ni existirían, y así sucesivamente.Entonces, la decisión de diseño se tomó para abstraer las llamadas al sistema, de modo que cuando lo hago
fs.open()
, simplemente funciona. Eso significa mantenerfs.open
mucho tiempo después defs.open2()
ganar popularidad.Históricamente, este es el objetivo de los sistemas POSIX en general. "Aquí hay un conjunto de llamadas y valores de retorno esperados, usted se da cuenta del medio". De nuevo por razones de portabilidad. El motivo por el cual Linus elige usar esa metodología es interno de su cerebro, y usted tendría que pedirle que sepa exactamente por qué. Sin embargo, si fuera yo, elegiría la abstracción sobre la integración en un sistema complejo.
fuente
Es una decisión de diseño y elección. Linus quiere poder garantizar a los desarrolladores de espacio de usuario que, excepto en circunstancias extremadamente raras y excepcionales (por ejemplo, relacionadas con la seguridad), los cambios en el núcleo no interrumpirán sus aplicaciones.
Las ventajas son que los desarrolladores de espacio de usuario no encontrarán que su código se rompa repentinamente en nuevos núcleos por razones arbitrarias y caprichosas.
Las desventajas son que el núcleo tiene que mantener el código antiguo y las llamadas de sistema antiguas, etc. para siempre (o, al menos, más allá de las fechas de caducidad).
fuente