B.5. El espacio de usuario
El «espacio de usuario» se refiere al entorno de ejecución de procesos normales (en contraste con el núcleo). Esto no significa necesariamente que usuarios iniciaron realmente estos procesos debido a que un sistema estándar frecuentemente posee procesos «demonio» (o en segundo plano), procesos que se ejecutan antes que el usuario inicie una sesión. Los procesos demonio son procesos considerados en espacio de usuario.
Cuando el núcleo supera su fase de inicialización, ejecuta el primer proceso: init
. El proceso #1 rara vez es útil por sí mismo, y los sistemas similares a Unix ejecutan con un ciclo de vida con muchos procesos adicionales.
Primero que nada, un proceso puede clonarse a sí mismo (esto es conocido como bifurcación — «fork»). El núcleo reserva un nuevo (pero idéntico) proceso de espacio en memoria, y otros procesos para usarlo. En este momento, la única diferencia entre estos dos procesos es su pid. Al nuevo proceso se le suele llamar proceso hijo al nuevo proceso y proceso padre al proceso cuyo pid no cambió.
A veces, el proceso hijo continúa su vida de forma independiente a su padre, con sus propios datos copiados del proceso padre. En muchos casos, sin embargo, el proceso hijo ejecuta otro programa. Con unas pocas excepciones, simplemente se reemplaza su memoria con aquella del nuevo programa y comienza la ejecución del mismo.Este es un mecanismo usado para el proceso de inicio (con el número 1 de proceso) para iniciar servicios adicionales y ejecutar toda la secuencia de arranque. En algún punto, uno de los proceso de la descendencia de
init
inicia una interfaz gráfica en la que los usuarios pueden iniciar sesión (describimos con más detalle la secuencia real de eventos en la
Sección 9.1, “Arranque del sistema”).
Cuando un proceso finaliza la tarea para la que fue iniciado, termina. El núcleo recupera la memoria asignada a este proceso y no le asignará más divisiones de tiempo de ejecución. Se le informa al proceso padre sobre la finalización de su proceso hijo, lo que permite a un proceso esperar que se complete una tarea que delegó a un proceso hijo. Este comportamiento es obvio a simple vista en los intérpretes de línea de órdenes (conocidos como consolas — «shells»). Cuando se ingresa una orden en una consola, sólo vuelve el prompt cuando finaliza la ejecución de dicha orden. La mayoría de las consolas permiten ejecutar programas en segundo plano, sólo es cuestión de agregar un &
al final de la orden. Se mostrará el prompt inmediatamente, lo que puede llevar a problemas si la orden necesita mostrar datos por su cuenta.
Un «demonio» es un proceso iniciado automáticamente por la secuencia de inicio. Continúa ejecutando (en segundo plano) para realizar tareas de mantenimiento o proveer servicios a otros procesos. Esta «tarea en segundo plano» es realmente arbitraria y no tiene un rol especial desde el punto de vista del sistema. Simplemente son procesos, muy similares a otros proceso, que se ejecutarán cuando le corresponda a su división de tiempo. Esta distinción es sólo para los humanos: se dice de un proceso que ejecuta sin interacción de un usuario (en particular, sin una interfaz gráfica) que ejecuta «en segundo plano» o «como un demonio».
B.5.3. Comunicación entre procesos
Un proceso aislado, sea un demonio o una aplicación interactiva, rara vez es útil por sí misma, razón por la que existen varios métodos que permiten la comunicación entre dos procesos separados, ya sea para intercambiar datos o para que se controlen entre sí. El término genérico para referirse a esto es comunicación entre procesos (abreviado IPC: «Inter-Process Communication»).
El sistema IPC más simple es utilizar archivos. El proceso que desea enviar datos, los escribe en un archivo (cuyo nombre ya conozca), mientras que el receptor sólo debe abrir este archivo y leer su contenido.
En el caso en que no deseemos almacenar datos en el disco, podemos utiliza una tubería («pipe»), que simplemente es un objeto con dos extremos; los bytes escritos en uno de ellos son legibles en el otro. Si dos procesos separados controlan los extremos, esto se convierte en un canal de comunicación entre procesos simple y conveniente. Podemos clasificar las tuberías en dos: tuberías con nombre y tuberías anónimas. Se representa a una tubería con nombre como un elemento en el sistema de archivos (aunque los datos transmitidos no se almacenen en él), para que ambos procesos puedan abrirlo independientemente si ya conocen la ubicación de la misma. En los casos en los que los procesos que se comunican están relacionados (por ejemplo, un proceso padre y su hijo), el proceso padre también puede crear una tubería anónima antes de bifurcarse que será heredada por el hijo. Ambos procesos podrán intercambiar datos a través de la tubería sin necesitar el sistema de archivos.
Sin embargo, no toda la comunicación entre procesos es para mover datos. En muchas situaciones, la única información que se necesita transmitir son mensajes de control como «suspender la ejecución» o «continuar la ejecución». Unix (y Linux) provee un mecanismo llamado señales, a través de las que un proceso puede simplemente enviar una señal específica (elegida de una lista predefinida de señales) a otro proceso. El único requisito es saber el pid del objetivo.
Para comunicaciones más complejas también existen mecanismos que le permiten a un proceso acceder, o compartir, parte de la memoria reservada para otros procesos. La memoria ahora compartida entre ellos puede ser usada para mover datos entre procesos.
Finalmente, las conexiones de red también pueden ayudar a comunicar un proceso; estos procesos inclusive puede estar ejecutando en diferentes equipos, posiblemente a miles de kilómetros de distancia.
Es bastante estándar que un sistema similar a Unix típico, utilice en varios niveles estos mecanismos.
Las bibliotecas de funciones tienen un rol crucial en un sistema operativo similar a Unix. No son programas completos ya que no se las puede ejecutar por su cuenta, sino colecciones de fragmentos de código que los programas estándar pueden utilizar. Entre las bibliotecas comunes podemos encontrar a:
la biblioteca estándar C (glibc), que contien funciones básicas como aquellas para abrir archivos o conexiones de red y otras que facilitan la interacción con el núcleo;
herramientas gráficas, como Gtk+ y Qt, que permiten que muchos programas reutilicen los objetos gráficos que proveen;
la biblioteca libpng, que permite cargar, interpretar y guardar imágenes en el formato PNG.
Gracias a estas bibliotecas, las aplicaciones puede reutilizar código existente. El desarrollo de la aplicación se simplifica cuando muchas aplicaciones reutilizan las mismas funciones. Debido a que diferentes personas desarrollan las bibliotecas, el desarrollo global del sistema es más cercano a la filosofía histórica de Unix.
Lo que es más, estas bibliotecas generalmente son llamadas «bibliotecas compartidas» ya que el núcleo puede cargarlas en memoria sólo una vez, aún cuando varios procesos utilicen la misma biblioteca simultáneamente. Esto permite ahorrar memoria si lo comparamos con la situación opuesta (e hipotética) en la que se cargará el código de una biblioteca tantas veces como haya procesos que la utilizan.