.. include:: ../../my-header_2.txt

Los procesos UNIX
-----------------

Decíamos que el concepto de *fichero* es una abstracción fundamental en el mundo UNIX/Linux, en torno a la cual gira toda la entrada-salida. Existe una segunda abstracción fundamental en UNIX/Linux, el *proceso*, en torno a la cual se describe todo lo relativo a la ejecución de los programas. 

Hasta ahora hablábamos de la "ejecución de un programa". Ahora sabemos que este término es demasiado simple para describir las posibilidades de la *ejecución de programas* en el entorno UNIX/Linux.

Un *programa* se identifica mediante el nombre del *fichero* ejecutable que contiene su código, representado de acuerdo a un formato determinado. Un programa es por lo tanto una entidad *estática*. Una característica del fichero ejecutable es que el sistema operativo lo puede *ejecutar*, lo que significa cargarlo en memoria y cederle el control, tal como hace el *shell*. 

Cuando el programa se ejecuta hay que considerar más información que la que contiene el fichero ejecutable. Por ejemplo, hay que asignar direcciones de memoria a variables y código, una tabla de descriptores de ficheros con sus descriptores estándar, y una pila para la ejecución, además de un *puntero al programa* (o contador de programa). Finalmente, el programa podría requerir recursos adicionales durante su ejecución, por ejemplo cuando abre un fichero, o cuando requiere memoria dinámicamente mediante ``malloc(3)``. 

¿Qué pasa si ejecutamos el mismo programa dos veces concurrentemente? Por ejemplo::

   ./sim_pos & ./sim_pos

Esto deja bien claro que el nombre del programa no es válido como identificador del *programa en ejecución*. Por si fuera poco, la llamada ``fork()`` permite crear un *flujo de ejecución* nuevo en el programa, que es una copia del código y las variables del *padre* (esto incluye la tabla de descriptores de ficheros y más cosas). Es como si el programa se hubiese *clonado* a sí mismo. Definitivamente, necesitamos una forma de identificar y describir estas entidades de ejecución *dinámicas*, a diferencia de los ficheros ejecutables, estáticos.

El concepto de **proceso** es precisamente eso, un flujo de ejecución del programa, identificado por un **identificador de proceso** único en el sistema (de nuevo, no tendremos que preocuparnos de rebasar el número máximo de identificadores, ya que es muy elevado). Además de su identificador, hay mucha información que describe a un proceso UNIX/Linux:

  * El código que ejecuta el proceso.
  * Las variables globales del proceso.
  * La pila asignada al proceso, donde se almacenan las variables locales.
  * Los descriptores de ficheros.
  * El estado de las señales.
  * El usuario y grupo propietarios del proceso.
  * El identificador del proceso padre.
  * Información para contabilidad: tiempos, recursos consumidos, etc.

Toda esta información conforma el **contexto** privado del proceso. El proceso dispone de una copia propia de todo ello durante toda su vida, que se libera cuando el proceso acaba (ya sea ejecutando ``exit()`` o de formas más expeditivas). 

A modo de ejemplo, el *shell* contiene un buen número de variables, las *variables de entorno*, que forman parte de su contexto privado. Esto lo podemos comprobar con el ``bash`` al ejecutar la siguiente secuencia de órdenes::

  pwd
  bash
  pwd
  cd un_subdirectorio
  exit
  pwd


Ahora podemos ser más precisos. Un proceso se crea cuando otro proceso ejecuta ``fork()``. El proceso recién creado, **proceso hijo**, hereda el contexto del **proceso padre** al proporcionarle el sistema operativo una copia idéntica a la del padre. Con una sola diferencia: el sistema asigna un identificador de proceso nuevo al proceso hijo. Así, a partir del valor devuelto por ``fork()`` podemos hacer que el código sea ejecutado solo por el hijo, solo por el padre, o por ambos. Observa finalmente que un proceso puede conocer su nombre (llamada al sistema ``getpid()``) y el nombre de su padre (llamada ``getppid()``), así como los nombres de sus hijos a través del valor de retorno de ``fork()``.

De igual forma que representamos todo el sistema de ficheros de Linux en un árbol, también podemos dibujar el árbol genealógico de los procesos de Linux en un momento dado. ¿Cuál es el proceso progenitor de todos los procesos, la raíz del árbol? Podrás identificarlo con ``ps aux`` como el proceso con identificador *1*. Este proceso, tradicionalmente conocido como proceso *init*, es también el proceso encargado de *adoptar* como hijos a los  procesos que se quedan *huérfanos*. Como ves, la historia de los procesos en Linux se presenta apasionante :-)


.. include:: ../../my-footer_2.txt

