Historia

jueves, 22 de marzo de 2012

Proceso daemon y zombie


Proceso Daemon
Un demonio, daemon o dæmon (de sus siglas en inglés Disk And Execution MONitor), es un tipo especial de proceso informático no interactivo, es decir, que se ejecuta en segundo plano en vez de ser controlado directamente por el usuario. Este tipo de programas se ejecutan de forma continua (infinita), vale decir, que aunque se intente cerrar o matar el proceso, este continuará en ejecución o se reiniciará automáticamente. Todo esto sin intervención de terceros y sin dependencia de consola alguna.

  • Características
Los demonios suelen tener las siguientes características:
§  No disponen de una "interfaz" directa con el usuario, ya sea gráfica o textual.
§  No hacen uso de la entradas y salidas estándar para comunicar errores o registrar su funcionamiento, sino que usan archivos del sistema en zonas especiales (/var/log/ en los UNIX más modernos) o utilizan otros demonios especializados en dicho registro como el syslogd.
Por ejemplo, una máquina que alberga un servidor web utilizará un demonio httpd (HTTP Daemon) para ofrecer el servicio y que los visitantes a dicha web puedan acceder. Otro ejemplo son los demonios "cronológicos" como cron, que realizan tareas programadas como mantenimiento del sistema en segundo plano.

Proceso Zombie
En sistemas operativos Unix, un proceso zombie o "defunct" (difunto) es un proceso que ha completado su ejecución pero aún tiene una entrada en la tabla de procesos, permitiendo al proceso que lo ha creado leer el estado de su salida. Metafóricamente, el proceso hijo ha muerto pero su "alma" aún no ha sido recogida.
Cuando un proceso acaba, toda su memoria y recursos asociados a él se desreferencian, para que puedan ser usados por otros procesos. De todas formas, la entrada del proceso en la tabla de procesos aún permanece. Al padre se le envía una señal SIGCHLD indicando que el proceso ha muerto; el manejador para esta señal será típicamente ejecutar la llamada al sistema wait, que lee el estado de salida y borra al zombie. El ID del proceso zombie y la entrada en la tabla de procesos pueden volver a usarse.

LLamadas al sistema


Llamadas al sistema para procesos


Llamada fork()
fork() esta función crea un proceso nuevo o “proceso hijo” que es exactamente igual que el “proceso padre”. Si fork() se ejecuta con éxito devuelve:
·         Al padre: el PID del proceso hijo creado.
·         Al hijo: el valor 0.
pid_t fork();


Llamadas exec()
  • Son similares en todas las versiones de Unix.
  • Carga de un fichero el código a ejecutar. Se utiliza para , después de ejecutar un fork() cargar un nuevo código para el proceso hijo.

Llamada getpid()
  • Devuelve el pid del proceso que lo llama. En caso de error devuelve -1.
  • Esta llamada devuelve en el estandar Posix un pid_t
pid_t getpid();


Llamada getppid()
  • Devuelve el pid del proceso padre al que lo llama. En caso de error devuelve -1.
  • La definición de esta función en estandar Posix es
pid_t getppid();


Llamada exit()
  • Termina la ejecución de un proceso. Existe también en Unix BSD y System V.
  • La definición es del tipo:
void exit (int status);
status: estado de terminación del proceso. Se usa para que el proceso padre conozca la forma en que finaliza un hijo. Puede ser cualquier tipo de entero, pero se suelen usar las macros:

EXIT_FAILURE
EXIT_SUCCESS
  • exit() cierra ficheros, vacía bufferes,...


Llamada wait()
  • Permite a un proceso sincronizarse con la finalización de un proceso hijo.
pid_t wait (int *status);



Llamadas al sistema para señales


SIGNAL(señal, &funcion) 

Esta llamada se utiliza para indicar que se está preparado  para recibir algún tipo de
señal y suministrar la dirección del  procedimiento manejador de la señal.
Después del SIGNAL, si se recibe una señal por ejemplo SIGINT  (pulsar la tecla DEL),
se efectúa:
     1) El estado del proceso se guarda en su propia pila.
     2) Se ejecuta el manejador de la señal.
int señal;
int (*función)(); función a realizar cuando se recibe una señal


SIGRETURN (&contexto)   

Es llamado por el manejador que atiende la señal cuando termina.   
Recupera el estado del proceso interrumpido desde la pila y lo continúa.       


SIGACTION (sig, *act, *oact) 

Es una nueva versión de signal, examina, pone o modifica los atributos de una señal.
Sig es un entero que indica la señal.
*act es una estructura que contiene los atributos y manejador de la señal
*oact es la estructura que recibe los atributos antes de la llamada


KILL 

La llamada kill, permite enviar señales entre  procesos que tienen el mismo uid
(identificador de usuario) la  forma es: kill (pid, sig)
       pid -> identificador del proceso
  sig -> tipo de señal
                     
sig = 9 es la señal SIGKILL, que mata cualquier proceso, aún  en modo tanda, esta
señal no puede ser ignorada.


ALARM (segundos) 

 Esta llamada se utiliza para interrumpir un proceso al cabo  de un cierto tiempo, su
parámetro especifica el tiempo en  segundos, después del cual el núcleo envía la señal
SIGALRM al proceso.
Un proceso solo puede tener una alarma pendiente, para  resetear una alarma, basta
hacer una llamada de alarma con  parámetro cero.


PAUSE (segundos) 

Esta llamada le dice al S.O. que suspenda al proceso, hasta  que se reciba una señal.


SIGPROCMASK(how, &set, &old)

Esta señal permite bloquear un conjunto de señales mediante una mascara de bits que
le envía al núcleo del sistema.


SIGPENDING(SET) 

Obtiene el conjunto de señales bloqueadas.


SIGSUSPEND(sigmask)

Permite a un proceso establecer atómicamente el mapa de bits de las señales
bloqueadas y suspenderse a sí mismo.

Programa para crear un proceso


Crear un proceso

#include

int main() {
         int pid;

         printf("PADRE: Soy el proceso padre y mi pid es: %d\n", getpid());

         pid = fork();

         // En cuanto llamamos a fork se crea un nuevo proceso. En el proceso
         // padre 'pid' contendrá el pid del proceso hijo. En el proceso hijo
         // 'pid' valdrá 0. Eso es lo que usamos para distinguir si el código
         // que se está ejecutando pertenece al padre o al hijo.

         if (pid) // Este es el proceso padre
         {
                 printf("PADRE: Soy el proceso padre y mi pid sigue siendo: %d\n", getpid());
                 printf("PADRE: Mi hijo tiene el pid: %d\n", pid);
         }
         else // Proceso hijo
         {
                 printf("HIJO: Soy el proceso hijo y mi pid es: %d\n", getpid());
                 printf("HIJO: mi padre tiene el pid: %d\n", getppid());
         }
}