viernes, 14 de febrero de 2014

Programación de Procesos en GNU/Linux

Procesos

Un proceso en términos generales es un programa en ejecución, una instancia de programa que tiene asociado un conjunto de recursos como registros internos del procesador, un espacio
en memoria con segmentos de dato, código y pila.

Estado de un Proceso

Un proceso en el transcurso de su ejecución cambia de un estado a otro. Los diferentes estados posibles son:
  • Ejecución. El proceso es ejecutado por el procesador.
  • Listo. El proceso está en espera de ser seleccionado para ejecutarse.
  • Suspendido. El proceso está en espera de un recurso.
  • Parado. El proceso ha sido suspendido por una intervención externa.
  • Zombi. El proceso ha terminado su ejecución pero sigue siendo referenciado en el sistema.
El proceso se caracteriza por tener varios atributos mantenidos por el sistema:

  • Estado
  • Identificador, número único (PID)
  • Valor de los registros del procesador.
  • Identificador de usuario
  • Prioridad
  • Información de contabilidad
  • Otros.


Programar Procesos con Fork

Un proceso puede crear procesos hijo utilizando la llamada al sistema fork. El proceso actual se duplica y crea una copia idéntica con excepción de su identificador (PID). Fork retorna el PID del proceso hijo al padre y cero al proceso hijo. Es necesario conocer este valor de retorno para distinguir el código que ejecutará el proceso padre y el que ejecutará el proceso hijo. En caso de fallo, fork devuelve -1 por dos posibles razones:

  • Se ha llegado al número máximo de procesos de usuario o de sistema.
  • El kernel no ha podido asignar suficiente memoria para crear un nuevo proceso.


Para utilizar la llamada al sistema fork es necesario incluir la cabecera unistd.h

Ejemplo:

#include <errno.h>
#include <stdio.h>
#include <unistd.h>

void main() {

    pid_t pid;
    pid = fork();

    if(pid != -1) {
        if(pid == 0) {
            /*Instrucciones para el proceso Hijo*/
            printf("Hijo: pid = %d\n", pid);
        }
        else {
            /*Instrucciones para el proceso Padre*/
            printf("Padre: pidHijo = %d\n",pid);
        }
    }
    else {
        /*Error. no se creo el proceso hijo*/
        perror("fork");
    }
}

El proceso actual termina automáticamente cuando deja de ejecutar la función main. Si desea que el proceso termine su ejecución en algún momento, utilice la llamada la sistema exit.

void _exit (int estado);

El parámetro estado especifica el código de retorno, entre 0 y 255, que recibe el proceso padre. Se debe retornar 0 si finalizó de manera normal y otro valor si hubo algún error.

Espera de conclusión de procesos Hijo

El proceso padre puede esperar a que un proceso hijo finalice, mediante wait y waitpid.

La primitiva wait suspende la ejecución del proceso actual hasta que acabe algún proceso hijo. Si un proceso hijo ha terminado, wait devuelve el resultado inmediatamente.

pid_t wait (int *estadoProceso);

Ejemplo:

#include <stdio.h>
#include <unistd.h>

void main() {

    int estadoProceso;
    pid_t pid = fork();

    if(pid == 0) {
        printf("Proceso hijo, pid = %d\n", pid);
    }
    else {
        wait(&estadoProceso);
        printf("Proceso padre, pid hijo = %d\n", pid);
    }
}

La primitiva waitpid suspende la ejecución del proceso actual hasta que un proceso hijo específico termine.

pid_t waitpid (pid_t pid, int *estadoProceso, int opciones);

Ejemplo

#include <stdio.h>
#include <unistd.h>

void main() {

    pid_t pid1, pid2;
    int estadoProc1, estadoProc2;

    pid1 = fork();
    if (pid1 == 0) {
        printf("Proceso hijo 1 ejecutandose\n");
    }
    else {
        pid2 = fork();
        if(pid2 == 0) {
            printf("Proceso hijo 2 ejecutandose\n");
        }
        else {
            waitpid(pid1, &estadoProc1, 0);
            printf("Fin del proceso 1\n");
            waitpid(pid2, &estadoProc2, 0);
            printf("Fin del proceso 2\n");
            printf("Proceso padre: pidHijo1 = %d, pidHijo2 = %d\n", pid1, pid2);
        }
    }
}

Lectura y Modificación de atributos

El kernel Linux nos permite obtener y modificar los atributos de los procesos, entre estas llamadas al sistema están:

  • pid_t get pid() Retorna el identificador único del proceso actual
  • pid_t get ppid() Retorna el identificador único del proceso padre
  • uid_t get uid() Retorna el identificador del usuario que ejecutó el proceso
  • int setuid(uid_t uid) Modifica el identificador de usuario


Para que la llamada setuid() cambie efectivamente el identificador de usuario, el proceso debe ejecutarse
como superusuario.

Si te gustó esta publicación no olvides compartirlo. Espero sus comentarios.



No hay comentarios:

Publicar un comentario