sesion04soprocesoslinuxi

13
U.N.S.A Sistemas Operativos (Laboratorio) Página: Programación de Procesos en C para Linux I OBJETIVOS Conocer y aplicar los conceptos sobre Procesos en LINUX Creación y ejecución de Procesos Finalización de procesos Señales Compilación y ejecución de programas en LINUX Realizar ejercicios. II TEMAS El árbol de procesos El proceso init ps, pstree Identificadores (PID, PPID, UID, EUID, GID y EGID) Cómo crear un proceso La llamadas al sistema fork() La llamadas al sistema exec() Obtención de Identificadores (getpid(), getppid()) exit,wait, waitpid Señales GCC (Compilación) ./ (Ejecución) III MARCO TEORICO El árbol de procesos Al igual que con los archivos, todos los procesos que corren en un sistema Linux están organizados en forma de árbol, y cada proceso tiene un número (su PID, Process ID, «identificador de procesos»), junto con el número de su proceso padre (PPID, Parent Process ID, «identificador del proceso padre»). Ing. Eveling Gloria Castro Gutierrez Sesion 04: Programación de Procesos en C para Linux 13

Upload: veronica

Post on 26-Jun-2015

225 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

Programación de Procesos en C para

Linux

I

OBJETIVOS

Conocer y aplicar los conceptos sobre Procesos en LINUX Creación y ejecución de Procesos Finalización de procesos Señales Compilación y ejecución de programas en LINUX Realizar ejercicios.

II

TEMAS

El árbol de procesos El proceso init ps, pstree Identificadores (PID, PPID, UID, EUID, GID y EGID) Cómo crear un proceso

La llamadas al sistema fork() La llamadas al sistema exec()

Obtención de Identificadores (getpid(), getppid()) exit,wait, waitpid Señales GCC (Compilación) ./ (Ejecución)

III

MARCO TEORICO

El árbol de procesos

Al igual que con los archivos, todos los procesos que corren en un sistema Linux están organizados en forma de árbol, y cada proceso tiene un número (su PID, Process ID, «identificador de procesos»), junto con el número de su proceso padre (PPID, Parent Process ID, «identificador del proceso padre»).

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

13

Page 2: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

Esto significa que hay un proceso en el tope de la estructura de árbol, el equivalente de la raíz para los sistemas de archivos: INIT, que siempre posee PID =1.

El proceso init Cuando arranca el sistema se desencadena una secuencia de procesos que a grandes rasgos es la siguiente. Primero se carga el núcleo de Linux (Kernel) de una forma totalmente especial y distinta a otros procesos. Dependiendo de los sistemas puede existir un proceso con PID=0 planificador, o swapper. Lee un fichero llamado inittab donde se relacionan una serie de procesos que deben arrancarse para permanecer activos (demonios). Algunos de ellos están definidos para que en caso de morir sean arrancados de nuevo inmediatamente garantizando la existencia de ese servicio de forma permanente. Es decir 'init' es un proceso que va a generar nuevos procesos pero esta no es una cualidad especial. Es muy frecuente que un proceso cualquiera genere nuevos procesos y cuando esto ocurre se dice que genera procesos hijos.

ps y pstree

Estos dos comandos muestran una lista de los procesos presentes en el sistema de acuerdo con los criterios que Ud., desee:

ps

Al enviar este comando sin un argumento se mostrarán solo los procesos iniciados por Ud., en la terminal que está utilizando:

$ ps PID TTY TIME CMD 5162 ttya1 00:00:00 zsh 7452 ttya1 00:00:00 ps

Las opciones son numerosas, citaremos las más comunes: a: también muestra los procesos iniciados por los otros usuarios; x: también muestra los procesos sin terminal de control alguna (esto se aplica a casi todos los servidores); u: muestra, para cada proceso, el nombre del usuario que lo inició y la hora a la cual fue iniciado.Hay muchas otras opciones. Refiérase a la página de manual para más información (man ps).

La salida de este comando está dividida en campos diferentes: el que más le interesará es el campo PID, que contiene el identificador del proceso. El campo CMD contiene el nombre del comando ejecutado.

Una forma muy común de invocar a ps es la siguiente: $ ps ax | less

Esto le da una lista de todos los procesos que se están ejecutando corrientemente, entonces Ud., puede identificar uno o más procesos que estén causando problemas y, subsecuentemente, puede matarlos.

pstree

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

14

Page 3: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

El comando pstree muestra los procesos en forma de estructura de árbol. Una ventaja es que Ud., puede ver inmediatamente quien es el proceso padre de otro: cuando quiere matar toda una serie de procesos, y si son todos padres e hijos, es suficiente matar al ancestro común. Se puede usar la opción -p, que muestra el PID de cada proceso, y la opción -u que muestra el nombre del usuario que inició el proceso. Como generalmente la estructura de árbol es grande, es más fácil invocar a pstree de la siguiente manera:

$ pstree -up | less

Esto le da una visión general de toda la estructura de árbol de los procesos. Envío de señales a los procesos: kill, killall y top

kill, killall

Estos dos comandos se usan para enviar señales a los procesos. El comando kill necesita el número de un proceso como argumento, mientras que el comando killall necesita el nombre de un comando.

Los dos comandos opcionalmente pueden recibir el número de una señal como argumento. Predeterminadamente, ambos envían la señal 15 (TERM) a el o los procesos relevantes. Por ejemplo, si quiere matar el proceso con PID 785, Ud., ingresa el comando:

$ kill 785

Si quiere enviarle la señal 9, ud., ahora ingresa:

$ kill -9 785

Supongamos que quiere matar un proceso del cual ud. conoce el nombre del comando. En vez de encontrar el número de proceso usando ps, puede matar el proceso directamente:

$ killall -9 netscape

Pase lo que pase, Ud., solo matará sus propios procesos (a menos que Ud. sea root), por lo que no debe preocuparse acerca de los procesos de otro usuario, que tienen el mismo nombre, ellos no serán afectados.

Identificadores PID, PPID, UID, EUID, GID y EGID

Process ID (PID)Al crear un nuevo proceso se le asigna un identificador de proceso único. Este número debe utilizarse por el administrador para referirse a un proceso dado al ejecutar un comando.

Los PID son asignados por el sistema a cada nuevo proceso en orden creciente comenzando desde cero. Si antes de un reboot del sistema se llega al nro. máximo, se vuelve a comenzar desde cero, salteando los procesos que aún estén activos.

Parent Process ID (PPID)La creación de nuevos procesos en Unix se realiza por la vía de duplicar un proceso existente invocando al comando fork(). Al proceso original se le llama "padre" y al nuevo proceso "hijo". El PPID de un proceso es el PID de su proceso padre.

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

15

Page 4: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

UID y EUID

Los procesos tienen un EUID (Effective User ID), y un UID normalmente ambos coinciden. El UID es el identificador de usuario real que coincide con el identificador del usuario que arrancó el proceso. El EUID es el identificador de usuario efectivo y se llama así porque es el identificador que se tiene en cuenta a la hora de considerar los permisos.

El UID es uno de los atributos de un proceso que indica por decirlo de alguna manera quien es el propietario actual de ese proceso y en función de ello podrá hacer ciertas cosas.

El UID también es un atributo presente en otros elementos del sistema. Por ejemplo los ficheros y directorios del sistema tienen este atributo. De esta forma cuando un proceso intenta efectuar una operación sobre un fichero. El kernel comprobará si el EUID del proceso coincide con el UID del fichero. Por ejemplo si se establece que determinado fichero solo puede ser leido por su propietario, el kernel denegará todo intento de lectura a un proceso que no tenga un EUID igual al UID del fichero salvo que se trate del root

La forma más habitual de hacer que el EUID de un proceso sea el de un usuario diferente del que lanza a correr el programa es activando el flag setuid en el archivo del programa. Un ejemplo de esto son los comandos que permiten a un usuario modificar su password, en que se debe modificar el archivo passwd o equivalente del sistema sobre el cual el usuario obviamente no tiene permiso de escritura. Habitualmente ese comando es un archivo de root con setuid y el proceso corre con EUID de root.

GID y EGIDEs totalmente análogo a los identificadores de usuario pero para grupos de usuarios. El GID se hereda del proceso padre. El EGID puede utilizarse igual que el EUID para controlar el acceso del proceso a archivos.

En la mayoría de los versiones actuales de Unix el proceso puede estar en varios grupos y se chequea contra toda la lista de grupos para definir si el proceso puede acceder o no a un recurso.

Como se crea un nuevo procesoEl núcleo del sistema llamado también kernel es el encargado de realizar la mayoría de funciones básicas que gestiona entre otras cosas los procesos. La gestión de los procesos se realizan con las llamadas al sistema estas están implementadas en lenguaje C y hablaremos ahora un poco sobre un par de ellas llamadas fork() y exec().

La llamada al sistema fork()

La forma en que un proceso arranca a otro es mediante una llamada al sistema con la función fork(). Lo normal es que el proceso hijo ejecute luego una llamada al sistema exec(). fork() duplica un proceso generando dos procesos casi idénticos. En realidad solo se diferenciaran en los valores PID y PPID. Un proceso puede pasar al proceso hijo una serie de variables pero un hijo no puede pasar nada a su padre a través de variables. Además fork() retorna un valor numérico que será -1 en caso de fallo, pero si tiene éxito se habrá producido la duplicación de procesos y retornará un valor distinto para el proceso hijo que para el proceso padre. Al proceso hijo le

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

16

Page 5: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

retornará el valor 0 y al proceso padre le retornará el PID del proceso hijo. Después de hacer fork() se pueden hacer varias cosas pero lo primero que se utiliza después del fork es una pregunta sobre el valor retornado por fork() para así saber si ese proceso es el padre o el hijo ya que cada uno de ellos normalmente deberá hacer cosas distintas.

int PID = fork() // crea un nuevo proceso (hijo del que hace la llamada a fork). padre e hijo continúan la ejecución en la instrucción inmediatamente posterior al fork.

PID = 0 en el hijo,PID > 0 en el padre (y contiene el pid del hijo)PID < 0 si error

La llamada al sistema exec()

Un proceso puede evolucionar y cambiar totalmente desde que arranca hasta que muere. Lo único que no cambia es su identificador de proceso PID. Una de las cosas que puede hacer un proceso es cambiar por completo su código. Por ejemplo un proceso encargado de procesar la entrada y salida de un términal (getty) puede transformarse en un proceso de autentificacion de usuario y password (login) y este a su vez puede transformarse en un interprete de comandos (bash). Si la llamada exec() falla retornará un –1, cuando esta llamada tiene éxito no se produce jamás un retorno. En realidad no tendría sentido retornar a ningún lado. Cuando un proceso termina simplemente deja de existir. La llamada exec() mantiene el mismo PID y PPID pero transforma totalmente el código de un proceso en otro que cargará desde un archivo ejecutable.

EXEC. se ejecuta en el espacio del proceso llamador, posibilidades:

int execl(char *path, char *arg0, char *arg1,......, char *argn, null);int execv(char *path, char *argv[]);int execlp(char *file, char *arg0, char *arg1,......, char *argn, null);int execvp(char *file, char *argv[]);

El sistema operativo UNIX ofrece una llamada al sistema llamada 'exec' para lanzar a ejecución un programa, almacenado en forma de fichero. Aunque en el fondo sólo existe una llamada, las bibliotecas estándares del C disponen de varias funciones, todas comenzando por 'exec' que se diferencian en la manera en que se pasan parámetros al programa.

La versión típica cuando se conoce a priori el número de argumentos que se van a entregar al programa se denomina execl. Su sintaxis es

int execl ( char* fichero, char* arg0, char* arg1, ... , 0 );

Es decir, el nombre del fichero y luego todos los argumentos consecutivamente, terminando con un puntero nulo (vale con un cero). Sirva este ejemplo:

Para ejecutar

/bin/ls -l /usr/include

escribiríamos

execl ( "/bin/ls", "ls", "-l", "/usr/include", 0 );

Obsérvese que el primer argumento coincide con el nombre del programa.

En caso de desconocer con anticipación el número de argumentos, habrá que emplear la función execv, que tiene este prototipo:

execv ( char* fichero, char* argv [] );

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

17

Page 6: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

El parámetro argv es una tira de cadenas que representan los argumentos del programa lanzado, siendo la última cadena un nulo (un cero). El ejemplo anterior se resolvería así:

char* parametros [] = { "ls", "-l", "/usr/include", 0 }; ...

execv ( "/bin/ls", parametros );

En los anteriores ejemplos se ha escrito el nombre completo del fichero para ejecutar ("/bin/ls" en vez de "ls"). Esto es porque tanto execl como execv ignoran la variable PATH, que contiene las rutas de búsqueda. Para tener en cuenta esta variable pueden usarse las versiones execlp o execvp. Por ejemplo:

execvp ( "ls", parametros );

ejecutaría el programa "/bin/ls", si es que la ruta "/bin" está definida en la variable PATH.

Todas las llamadas exec... retornan un valor no nulo si el programa no se ha podido ejecutar. En caso de que sí se pueda ejecutar el programa, se transfiere el control a éste y la llamada exec... nunca retorna. En cierta forma el programa que invoca un exec desaparece del mapa.

Obtención de Identificadores (getpid(), getppid())

getpid(void) Devuelven el ID del procesogetppid(void) devuelve el ID del padre (del proceso), en general, se ejecutan en silencio sin necesidad de interacción.

Finalización de Procesos

exit

void exit (int status)

exit finaliza al proceso que lo llamó, con un código de estado igual al byte inferior del parámetro status. Todos los descriptores de archivo abiertos son cerrados y sus buffers sincronizados. Si hay procesos hijo cuando el padre ejecuta un exit, el PPID de los hijos se cambia a 1 (proceso init). Es la única llamada al sistema que nunca retorna. El valor del parámetro status se utiliza para comunicar al proceso padre la forma en que el proceso hijo termina. Por convenio, este valor suele ser 0 si el proceso termina correctamente y cualquier otro valor en caso de terminación anormal. El proceso padre puede obtener este valor a través de la llamada al sistema wait.

wait y waitpid:

Espera a que pare o termine un proceso hijo, permitiendo obtener sus estados de salida. Una señal no bloqueada o no ignorada puede reactivar el proceso padre.

pid_t wait (int *statusp)

Si hay varios procesos hijos, wait espera hasta que uno de ellos termina. No es posible especificar por qué hijo se espera. wait retorna el PID del hijo que termina (o -1 si no se crearon hijos o si ya no hay hijos por los que esperar) y almacena el Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

18

Page 7: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

código del estado de finalización del proceso hijo (parámetro status en su llamada al sistema exit) en la dirección apuntada por el parámetro statusp. Un proceso puede terminar en un momento en el que su padre no le esté esperando. Como el kernel debe asegurar que el padre pueda esperar por cada proceso, los procesos hijos por los que el padre no espera se convierten en procesos zombies (se descartan su segmentos, pero siguen ocupando una entrada en la tabla de procesos del kernel). Cuando el padre realiza una llamada wait, el proceso hijo es eliminado de la tabla de procesos. No es obligatorio que todo proceso padre espere a sus hijos. Un proceso puede terminar por:

Causa de terminación Contenido de *statusp

Llamada al sistema exit byte más a la derecha = 0 byte de la izquierda = parámetro status de exit

Recibe una señal

En los 7 bits más a la derecha se almacena el número de señal que terminó con el proceso. Si el 8º bit más a la derecha está a 1, el proceso fue detenido por el kernel y se generó un volcado del proceso en un archivo core.

Caída del sistema (Ej.: pérdida de la alimentación del equipo)

Todos los procesos desaparecen bruscamente. No hay nada que devolver.

Proceso zombi: proceso parado que queda en la tabla de procesos hasta que termine su padre. Este hecho se produce cuando el proceso padre no recoge el código de salida del proceso hijo. Proceso huérfano: proceso en ejecución cuyo padre ha finalizado. El nuevo identificador de proceso padre (PPID) coincide con el identificador del proceso init (1).

SEÑALES.

Una señal es evento que debe ser procesado y que puede interrumpir el flujo normal de un programa. Capturar una señal: Una señal puede asociarse con una función que procesa el evento que ha ocurrido. Ignorar una señal: El evento no interrumpe el flujo del programa. Las señales SIGINT y SIGSTOP no pueden ser ignoradas (ver tabla de señales). Acción por defecto: Proceso suministrado por el sistema para capturar la señal (ver tabla de señales). Alarma: Señal que es activada por los temporizadores del sistema. Error: Fallo o acción equivocada que puede provocar la terminación del proceso. Error crítico: Error que provoca la salida inmediata del programa.

Tabla de señales más importantes.Núm. Nombre Comentarios

1 SIGHUP Colgar. Generada al desconectar el terminar. 2 SIGINT Interrupción. Generada por teclado. 3 SIGQUIT1 Salir. Generada por teclado.

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

19

Page 8: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

4 SIGILL1 Instrucción ilegal. No se puede recapturar. 5 SIGTRAP1 Trazado. No se puede recapturar. 6 SIGABRT1 Abortar proceso. 8 SIGFPE1 Excepción aritmética, de coma flotante o división por cero. 9 SIGKILL1 Matar proceso. No puede capturarse, ni ignorarse.

10 SIGBUS1 Error en el bus. 11 SIGSEGV1 Violación de segmentación. 12 SIGSYS1 Argumento erróneo en llamada al sistema. 13 SIGPIPE Escritura en una tubería que otro proceso no lee. 14 SIGALRM Alarma de reloj. 15 SIGTERM Terminación del programa. 16 SIGURG2 Urgencia en canal de E/S. 17 SIGSTOP3 Parada de proceso. No puede capturarse, ni ignorarse. 18 SIGTSTP3 Parada interactiva. Generada por teclado. 19 SIGCONT4 Continuación. Generada por teclado. 20 SIGCHLD2 Parada o salida de proceso hijo. 21 SIGTTIN3 Un proceso en 2o plano intenta leer del terminal. 22 SIGTTOU3 Un proceso en 2o plano intenta escribir en el terminal. 23 SIGIO2 Operación de E/S posible o completada. 24 SIGXCPU Tiempo de UCP excedido. 25 SIGXFSZ Excedido el límite de tamaño de fichero. 30 SIGUSR1 Definida por el usuario número 1. 31 SIGUSR2 Definida por el usuario número 2. 34 SIGVTALRM Alarma de tiempo virtual. 36 SIGPRE Excepción programada. Definida por el usuario.

Notas sobre la acción por defecto para la señal.

1. Generar un fichero core.

2. Ignorar la señal.

3. Parar el proceso que recibe la señal.

4. Reiniciar o continuar el proceso que recibe la señal.

Las señales comprendidas entre la 37 y la 58 (ambas inclusive) están reservadas por el sistema. El rango de señales en el UNIX de Berkeley (BSD) es de 1 a 31.

Capturar señales.

Subrutina signal: Asocia una acción determinada con una señal. - Formato:

#include <signal.h> void (*signal (señal, accion)) ( ) int señal; void (*accion) ( );

- Parámetros: señal: Número de señal, excepto SIGKILL. acción: Puntero a la rutina asociada con la señal o uno de los valores:

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

20

Page 9: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

• SIG_DFL: acción por defecto para dicha señal.

• SIG_IGN: ignorar la señal,

- Devuelve: Valor de la acción anteriormente asociada; -1, en caso de error.

GCC

Cada vez que ud. desea compilar un programa con extensión .c (dentro de las principales) lo puede hacer con el comando gcc por ejemplo:

gcc programas.c –o programas.exe

el primer parámetro implica el programa a compilarse y el segundo el archivo objeto de salida el cual posteriormente se podrá ejecutar.

./ Con la siguiente instrucción ud. Podrá ejecutar el programa del cual creo su ejecutable anteriormente ejemplo:

./ programas.exe

por ahora solo necesitamos saber esa información para empezar a crear nuestros programas y ejecutarlos en C.

Desarrollar en Laboratorio los siguientes ejerciciosI. Realice la escritura, compilación y ejecución de los siguientes programas

1. En cualquier editor digite el siguiente programa y evalúe el resultado

// Nos dá el PPID y el PID #include <unistd.h>#include <stdio.h>#include <stdlib.h>

int main(void){ printf("Proceso hijo PID= %d\n", getpid()); printf("Proceso padre PPID= %d\n", getppid()); exit(0);}

2. Escriba el siguiente programa y verifique de acuerdo a la siguiente tabla:

Atributo............................Tipo............................Función ID de proceso.....................pid_t.........................getpid(void);ID de padre de proceso.......pid_t.........................getppid(void);ID de usuario real...............uid_tg........................getuid(void);

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

21

Page 10: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

ID de usuario efectivo.........uid_t.........................geteuid(void);ID grupo real......................gid_t.........................getgid(void);ID de grupo efectivo...........gid_tg........................getegid(void);

// Muestra los UID y los GUID #include <unistd.h>#include <stdio.h>#include <stlib.h>

int main(void){ printf("ID de usuario real: %d\n", getuid()); printf("ID de usuario efectivo: %d\n", geteuid()); printf("ID de grupo real: %d\n", getgid()); printf("ID de grupo efectivo: %d\n", getegid()); exit(0);}

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

22

Page 11: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

3. Ejecutar el siguiente programa:

#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main () { pid_t rf;

int i, j;int global = 1000; rf = -1;rf = fork (); for (i=0; i<500; i++) {

global = global + 1; printf("\t%d (%d)", rf, global);

for (j=0; j<10000; j++) {}

}printf ("\nFinal de ejecucion del proceso %d \n", getpid());exit (0);

}

4. Ejecute el programa anterior en segundo plano. 5. Verifique su ejecución con la orden ps. Observe los valores PID y PPID.

Describa lo que sucede6. Digite el siguiente programa:

#include <stdio.h>#include <unistd.h>int main(void) {int pid;printf("Hasta aquí hay un único proceso...\n");printf("Primera llamada a fork...\n");/* Creamos un nuevo proceso. */pid = fork();if (pid == 0) {printf("HIJO1: Hola, yo soy el primer hijo...\n");printf("HIJO1: Voy a pararme durante 60 seg. y luego terminaré...\n");sleep(60);}else if (pid > 0) {printf("PADRE: Hola, soy el padre. El pid de mi hijo es: %d\n",pid);/* Creamos un nuevo proceso. */pid = fork();if (pid == 0) {printf("HIJO2: Hola, soy el segundo hijo...\n");printf("HIJO2: El segundo hijo va a ejecutar la orden 'ls'...\n");execlp("ls","ls",NULL);printf("HIJO2: Si ve este mensaje, el execlp no funcionó...\n");}else if (pid > 0) {printf("PADRE: Hola otra vez. Pid de mi segundo hijo: %d\n",pid);printf("PADRE: Voy a esperar a que terminen mis hijos...\n");printf("PADRE: Ha terminado mi hijo %d\n",wait(NULL));printf("PADRE: Ha terminado mi hijo %d\n",wait(NULL));}elseprintf("Ha habido algún error al llamar por 2ª vez al fork\n");}

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

23

Page 12: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

elseprintf("Ha habido algún error al llamar a fork\n");}

7. A los programas de los incisos 3 y 6 colocarles la llamada exec() donde crea conveniente para finalizar correctamente los procesos.

8. Escriba un programa en el cual se creen procesos y uno de ellos se encuentre en el estado zombie.

9. Digite los siguientes códigos y explique la salida de éstos

9.1/* fork_huerf.c - Ejemplo de proceso huérfano *#include <stdio.h>#include <unistd.h>main () { printf ("Ejemplo de proceso huérfano.\n"); printf ("Inicio del proceso padre. PID=%d\n", getpid ()); if (fork () == 0)

{printf ("Inicio proceso hijo. PID=%d, PPID=%d\n",getpid (), getppid ());sleep (1);printf ("El proceso queda huérfano. PID=%d PPID=%d\n",getpid (), getppid ());}

else printf ("Continuación del padre. PID=%d\n", getpid ());

printf ("Fin del proceso %d\n", getpid ()); exit (0); }

9.2/* signal.c - Contar el número de CTRL-C en 15 segundos */ #include <unistd.h>

#include <stdlib.h>#include <signal.h>

int numcortes=0;int enbucle=1;void alarma ();void cortar ();

int main () { signal (SIGINT, cortar); signal (SIGALRM, alarma); printf ("Ejemplo de signal.\n"); printf ("Pulsa varias veces CTRL-C durante 15 segundos.\n"); alarm (15); while (bucle); signal (SIGINT, SIG_IGN); printf ("Has intentado cortar %d veces.\n", numcortes); printf ("Hasta luego Lucas.\n"); exit (0); }

void alarma ()Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

24

Page 13: Sesion04SOProcesosLinuxI

U.N.S.A Sistemas Operativos (Laboratorio) Página:

{ signal (SIGALRM, SIG_IGN); bucle=0; /* Salir del bucle */ printf ("¡Alarma!\n"); }

void cortar () { signal (SIGINT, SIG_IGN); printf ("Has pulsado CTRL-C\n"); numcortes++; signal (SIGINT, cortar); }

V

CUESTIONARIO

1. ¿Qué hace el comando pstree –p?

2. ¿Cuál es el comando que permite visualizar los procesos en ejecución?

3. Realizar ejemplos con las diferentes llamadas de exec.

4. ¿Por qué cualquier comando en linux se considera un proceso?.Explique.

5. Deduzca que procesos intervienen en la ejecución de la orden man y la jerarquía entre ellos. Para ello, ejecute dicha orden e interrumpa su ejecución con CONTROL + Z y compruebe los procesos existentes con la orden ps y la opción -l

6. ¿Cómo puede comprobar, antes de finalizar su sesión, si tiene trabajos pendientes? ¿Cómo finalizaría dichos trabajos?

Salga de su usuario con logout y si está como root apague la maquina con :$ shutdown –hY si está como usuario no se olvide de digitar :$ poweroff

No se olvide de hacerlo cada vez que finalice la sesión de Linux

Ing. Eveling Gloria Castro Gutierrez

Sesion 04: Programación de Procesos en C para Linux

25