El núcleo Linux está compuesto de más de 21 millones de líneas de código, cada una de las cuales carga con importantes instrucciones. Semejante cantidad de código merece un artículo igualmente grande para describir cómo cada tarea en el kernel es desempeñada, ¿verdad?.
Pero antes de explicarte cómo funciona el kernel de cualquier sistema operativo, primero debemos saber cuáles son las responsabilidades de un kernel o núcleo. El kernel proporciona abstracciones para los programadores que desarrollan aplicaciones para la plataforma del mismo. Estas abstracciones son básicamente simplificaciones para llevar a cabo tareas complejas.
Un conjunto de abstracciones
El kernel, siendo la parte más fundamental en un sistema operativo, no es la única pieza de software proporciona abstracciones, pero es sin duda una de las más importantes en dicho aspecto. Otros conjuntos de abstracciones son los que proporcionan los controladores de hardware; los drivers de hardware hablan el lenguaje del kernel, así el kernel no necesita saber cómo hablarle a cada pieza de hardware que se crea. Esto es lo que le permite a un sólo kernel correr en diferentes marcas y modelos de hardware.Así que, cuando hablamos de abstracción, es importante también saber qué significa exactamente el término. Así como en el arte una abstracción o pieza abstracta sirve para representar algo en su forma más básica y esencial, una abstracción en informática es una forma de ocultar lo que en ocasiones sería una abrumadora cantidad de detalles detrás de un determinado proceso, preservando únicamente la información que resulta relevante.
Fíjate, por ejemplo, en las lectura y escritura de variables en la memoria RAM. Cada placa madre puede tener un controlador de memoria muy diferente al de otro; tu computadora podría tener un procesador Intel, ARM, PowerPC, AMD, SPARC o MIPS, pero eso no debería importarle a los programas que usas, y usualmente no les importa, porque el kernel abstrae todas esas diferencias en hardware en forma de una única interfaz uniforme.
Para un programador, esta interfaz luce igual que cualquier otra llamada de función, pero esta es especial debido a que es una llamada de sistema. Una llamada al sistema es simplemente una función que solicita algo del kernel (una invocación), es aquí donde el kernel lleva a cabo la solicitud, independientemente del hardware subyacente.
¿De qué es responsable el kernel Linux?
Ahora lo que necesitamos saber, de qué tareas es responsable el núcleo Linux, ¿cuáles son? ¿qué abstracciones debemos esperar del núcleo de cualquier sistema operativo moderno?Memoria de Acceso Aleatorio (RAM) — lectura y escritura de variables y datos en memoria
Almacenamiento permanente — lectura y escritura de archivos en dispositivos de almacenamiento
Sistema de archivos virtual
Acceso a la red
Independiente de medios físicos (Ethernet, Wi-Fi, LTE, Dialup)
Parcialmente independiente de protocolos
Planificación de tareas (Task Scheduling)
Tiempo compartido de CPU
Balanceo de carga y establecimiento de prioridades
Protocolos de dispositivos (USB, FireWire, Serie, Paralelo)
Medios extraíbles por USB
Cámaras web
Mouse y teclados
Seguridad
Permisos de grupo y usuarios
Permisos de acceso a recursos
Almacenamiento de datos
[right-side]Hay dos formas de almacenamiento, 1) el almacenamiento temporal y 2) el almacenamiento permanente. El almacenamiento temporal, que podría no ser tan obvio para muchos lectores, es la memoria RAM. No todo lo que llega a la RAM debe ser almacenado permanentemente, llega ahí porque eventualmente será descartado. Un buen ejemplo de esto es cuando navegas por internet, por obvias razones no quieres que cada página web que visitas sea almacenada permanentemente en tu PC. El almacenamiento permanente es, como ya has deducido, tu disco duro, SSD o Flash.El núcleo Linux proporciona una completamente transparente lectura y escritura de datos en (1) la RAM, independientemente de sobre qué plataforma de hardware esté ejecutándose. No interesa si estás corriendo Linux en una antigualla con procesador Intel i386 o en el más reciente flagship Android con procesador ARM. Ten en mente que es Linux el que se modifica para soportar diferentes arquitecturas de hardware, y son estas modificaciones en el kernel las que las que le permiten brindar una intefaz uniforme a pesar del hardware no-tan-uniforme.
Además, el kernel aisla cada proceso en su propio espacio de memoria, lo que significa que dicho proceso no tiene por qué saber cuánta memoria le pertenece ya que toda la memoria visible para el proceso le pertenece. Este particionado de memoria supone un aumento de la seguridad sin ningún costo adicional para el desarrollador.
De forma similar, con (2) el almacenamiento permanente, el kernel oculta las diferencias de comunicación con SATA, USB, SCSI, PATA, M.2 y otros protocolos de almacenamiento y permite que un sólo programa pueda leer y escribir archivos en cualquier medio conectado usando cualquier protocolo y sistema de archivos soportado sin que dicho programa sufra ningún cambio. Eso pone mucho poder y responsabilidad en manos tanto del desarrollador como del usuario; y aumenta la re-utilización del código y la productividad del desarrollador porque no hay necesidad de código especializado.
Acceso a la red
Cuando se trata de redes, el asunto se torna diferente ya que cada protocolo tiene su propio formato de direccionamiento, así que la necesidad de escribir código especializado para soportar cada protocolo de red es inherente. Aquí, sólo IPv4 e IPv6 son comunes. En cuanto a los muchos otros protocolos hoy por hoy casi desaparecidos como DECnet, IPX y AppleTalk, sí hay soporte para ellos en Linux, pero soportar estos protocolos en cualquier aplicación moderna es tan poco benéfico que difícilmente valdría la pena el esfuerzo, salvo que razones de retrocompatibilidad lo exigan desesperadamente.Volviendo al tema de IPv4 e IPv6, la forma en que se representan sus direcciones son muy diferentes entre uno y el otro, lo que es tanto una ventaja como un inconveniente. El tipo de protocolo necesario puede ser fácilmente deducido por la dirección IP. Adicionalmente, el kernel proporciona soporte para TCP, UDP, SCTP e ICMP, que pueden ser fácilmente utilizados haciendo una llamada al sistema. No importa si tu computadora está conectada usando el protocolo Ethernet, LTE o Dialup, las llamadas al sistema seguirán siendo las mismas.
Imagínate a ti mismo necesitando diferentes versiones específicas de Chrome o Firefox dependiendo de si estás conectado por Wi-Fi o Ethernet, no sólo sería incómodo para ti, sino también mucho más incómodo para los desarrolladores. Esta abstracción, nuevamente, es muy poderosa y brinda una flexibilidad que incrementa la productividad del desarrollador y una experiencia más satisfactoria de cara al usuario.
Planificador de tareas (Task Scheduler)
La planificación de tareas o task scheduling, un tópico que nunca falla a la hora de generar discusiones y opiniones contrarias. Así que no nos vamos a molestar hablando de los distintos algoritmos de scheduling que existen en Linux y sólo vamos a enfocarnos en las responsabilidades que tiene el kernel al respecto, para asegurarse de que cada proceso tenga su tajada de CPU, incluso cuando hay cientos de ellos.Antes de que salieran los CPUs multi-núcleo, las computadoras en realidad sólo podían hacer una cosa al mismo tiempo. A cada proceso se le daba su parte justa de tiempo calculado uno por uno, pero esto se hacía tan rápido que daba la ilusión de estar corriendo los procesos simultáneamente. Antes de que apareciesen los procesadores multi-núcleo, los fabricantes de computadoras podían poner más de una CPU en una sola placa madre para permitir que más de un proceso pudiese correr de forma simultánea. Esto aún se hace en la actualidad, pero con CPUs multi-núcleo y algunas incluso con hyperthreading que permite correr dos procesos en simultáneo por cada núcleo (logrando sistemas que pueden soportar hasta más de 100 hilos a la vez).
Cada proceso quiere tiempo en la CPU, y es el kernel el que se asegura de que todos tengan su turno a tiempo. Más allá de esto, algunos procesos requieren demoras, tal vez mientras esperan a que la operación de E/S concluya, o un juego esperando por un intervalo de tiempo; y todo esto puede ser asistido por el kernel.
En lugar de que un proceso ocupe la CPU mientras espera, otro proceso puede ser ejecutado mientras tanto y así el proceso original puede regresar para terminar lo que debía, aumentando así el rendimiento general del sistema. En términos generales, la planificación de tareas significa que un desarrollador no necesita preocuparse de otros procesos ejecutándose en la máquina, sólo tiene que preocuparse del programa que desarrolla.
Vaya, el número de abstracciones en el núcleo Linux es probablemente demasiado inmenso para que una sola persona (llámese también cuerda) intente recitarlas todas y cada una. Mientras que el número de abstracciones proporcionadas por Linux puede ser abrumador, sin éstas, la cantidad de detalles que un programador necesitaría saber para implementar una aplicación sería aún más abrumadora. Con semenjante cantida de abstracciones, no podemos simplemente cubrirlas todas en este artículo. Si conoces a fondo una abstracción específica, no olvides por favor comentarla para todos en la caja de comentarios.
Artículo original escrito por Devin McElheran para Fossbytes