Prácticas de Sistemas operativos David Arroyo Guardeño Escuela Politécnica Superior de la Universidad Autónoma de Madrid Segunda Semana: Procesos, Procesos Padre y Procesos Hijo, familia exec() 1 Entregas 2 Procesos Fork Estados de un proceso Terminación de procesos Wait Exec Entregas 3 Ejercicios 2, 3, 4, 5,6, 7 y 8 ☠ Ejercicios 4, 5, 6 y 8 Definición de proceso 7 Instancia de un programa en ejecución 3 Programa = 1 o más procesos 3 Proceso → espacio en memoria + datos: conjunto de estructuras de datos 7 Elemento central en un SO 7 SO ↔ gestión de procesos Programa Colección de instrucciones y de datos almacenados en un fichero (a.out) 3 Conjunto de cabeceras → atributos del fichero 3 Texto del programa → intrucciones lenguaje máquina 3 bss: block started by symbol → datos a inicializar al arrancar 3 Otras secciones Proceso Programa leı́do por el núcleo y cargado en memoria para ejecutarse 3 Segmento de texto → instrucciones CPU 3 Segmento de datos → variables estáticas y globales 3 Segmento de pila → marcos de pila Marcos de pila 3 Ejecución función → marco de pila 3 Información necesaria para restaurar el marco de pila anterior a la llamada 3 Contador de programa y puntero de pila anteriores a la llamada a la función Modos de ejecución Modo usuario Pila: argumentos, variables locales, datos funciones en modo usuario Modo supervisor Marcos de pila de las llamada a sistema Estructuras de control del SO 7 7 7 7 Tabla de memoria Tabla de dispositivos de E/S Tabla de ficheros Tabla de procesos Estructuras de control del SO 7 Tabla de memoria 3 Gestión de la memoria principal y secundaria 3 Asignación de memoria a procesos, atributos de protección de memoria, información para gestionar memoria 7 Tabla de dispositivos de E/S 7 Tabla de ficheros 7 Tabla de procesos Estructuras de control del SO 7 Tabla de memoria 7 Tabla de dispositivos de E/S 3 Administración de dispositivos y canales de E/S 3 Almacena si dispositivo asignado a proceso 3 Estado del dispositivo: información en curso 7 Tabla de ficheros 7 Tabla de procesos fork→ man fork 7 Proceso en UNIX: entidad tras llamada a fork. . . salvo el proceso número 0 fork 7 Proceso padre −−→ proceso hijo 7 proceso → PID fork 7 Proceso 0: tras arrancar el sistema −−→ arrancar init (proceso 1 −−−−→ /etc/rc*): proceso 0, intercambiador | gestión de la memoria virtual Estados de un proceso 1 llamada al sistema o 7 retorno interrupción exit 9 2 dormir despertar bio de cam o text con orden en ejecución sı́ mem oria 1 ⇒ Ejecución modo usuario 2 ⇒ Ejecución modo supervisor 3 ⇒ en MP: listo para ejecutarse 4 ⇒ en MP: durmiendo 5 ⇒ en MS: listo para ejecutarse 6 ⇒ en MS: durmiendo 3 4 sacar de MP sacar de MP 6 introducir en MP 5 oria no mem 8 fork # include <u n i s t d . h> # include < s t d l i b . h> # include <s t d i o . h> i n t main ( i n t argc , char ∗ argv [ ] , char ∗env [ ] ) { i n t i , a =1; f o r ( i =0; i <10; i ++) { switch ( f o r k ( ) ) { case 0 : a = 3; p r i n t f ( ” a=%d\n ” , a ) ; break ; } p r i n t f ( ‘ ‘ a=%d\n ” , a ) ; } exit (0) ; } Llamada a fork I 1 2 3 4 5 6 Verificar si espacio en tabla de procesos Asignar memoria al proceso hijo Imagen proceso padre → memoria proceso hijo Hallar una ranura de proceso libro y copiar la ranura del proceso padre en él Asociar mapa de memoria a la tabla del proceso Elegir un pid para el proceso hijo Llamada a fork II 7 8 9 Notificar la existencia del proceso hijo al kernel y al sistema de archivo Informar del mapa de la memoria del proceso hijo al kernel Enviar mensajes de notificación al proceso padre y al proceso hijo ¿Por qué puede fallar fork? Ø Hay que controlar la respuesta de fork ¿Por qué puede fallar fork? Ø Hay que controlar la respuesta de fork Ø No hay recuros suficientes ¿Por qué puede fallar fork? Ø Hay que controlar la respuesta de fork Ø No hay recuros suficientes Ø Número máximo de procesos en ejecución # include < s t d l i b . h> # include <s t d i o . h> i n t main ( i n t argc , char ∗ argv [ ] , char ∗env ) { int i = 0; switch ( f o r k ( ) ) { case −1: p e r r o r ( ” E r r o r a l c r e a r procesos ” ) ; e x i t ( −1) ; break ; case 0 : while ( i <10) { sleep ( 1 ) ; p r i n t f ( ” \ t \ t Soy e l proceso h i j o : %d\n ” , i ++) ; } break ; default : while ( i <10){ p r i n t f ( ” Soy e l proceso padre : %d\n ” , i ++) ; sleep ( 2 ) ; } }; } Terminación de procesos # include < s t d l i b . h> void e x i t ( i n t s t a t u s ) ; ... # include <sys / w a i t . h> p i d t wait ( int ∗ s t a t l o c ) ; ... p i d t pid ; i n t estado ; ... p i d = w a i t (& estado ) ; p i d = w a i t ( NULL ) ; # include <sys / w a i t . h> # include < s t d l i b . h> # include <s t d i o . h> # define NUM PROCESOS 5 int I = 0; void c o d i g o d e l p r o c e s o ( i n t i d ) { int i ; f o r ( i =0; i <50; i ++) { p r i n t f ( ” Proceso %d : i = %d , I = %d\n ” , i d , i , I ++) ; } exit ( id ) ; } main ( ) { i n t p , pid , s a l i d a ; i n t i d [NUM PROCESOS] = { 1 , 2 , 3 , 4 , 5 } ; f o r ( p =0; p<NUM PROCESOS; p++) { pid = fork ( ) ; i f ( p i d == −1){ p e r r o r ( ” E r r o r a l c r e a r un proceso : ” ) ; e x i t ( −1) ; } else i f ( p i d == 0 ) codigo del proceso ( id [ p ] ) ; } f o r ( p =0; p < NUM PROCESOS; p++) { p i d = w a i t (& s a l i d a ) ; p r i n t f ( ” Proceso %d con i d = %x terminado \n ” , pid , s a l i d a >>8) ; } } # include <u n i s t d . h> # include <s t d i o . h> # include < s t d l i b . h> i n t main ( ) { p i d t pid , p p i d ; / / o b t e n e r e l p i d d e l proceso pid = getpid ( ) ; / / o b t e n e r e l p i d d e l padre d e l proceso ppid = getppid ( ) ; p r i n t f ( ” Mi p i d e : %d\n ” , p i d ) ; p r i n t f ( ” E l p i d de mi padre es %d\n ” , p p i d ) ; return 0; } Familia exec Ø No se debe realizar ningún tratamiento tras llamada a exec Ø Sólo tratamiento de error: exec no vuelve a la función que la llaman a menos que se produzca un error # include <u n i s t d . h> # include < s t d l i b . h> # include <s t d i o . h> i n t main ( i n t argc , char ∗ argv [ ] ) { / / Para e j e c u t a r l s , l o s argmuentos de e n t r a d a son : l s − l / b i n char ∗ l s a r g s [ 4 ] = { ” / b i n / l s ” , ”− l ” , ” / b i n ” , NULL} ; / / ejecuta l s execv ( l s a r g s [ 0 ] , l s a r g s ) ; / / a q u i s o l o se l l e g a s i se ha p r o d u c i d o un e r r o r p e r r o r ( ” execv ha f a l l a d o ” ) ; r e t u r n 2 ; / / se devuelve codigo de e r r o r } } # include <u n i s t d . h> # include < s t d l i b . h> # include <s t d i o . h> i n t main ( i n t argc , char ∗ argv [ ] ) { char ∗ l s a r g s [ 4 ] = { ” l s ” , ”− l ” , ” / b i n ” , NULL} ; execvp ( l s a r g s [ 0 ] , l s a r g s ) ; p e r r o r ( ” execvp ha f a l l a d o ” ) ; return 2; } # include # include # include # include # include <u n i s t d . h> < s t d l i b . h> <s t d i o . h> <sys / t y p e s . h> <sys / w a i t . h> i n t main ( i n t argc , char ∗ argv [ ] ) { char ∗ l s a r g s [ 4 ] = { ” l s ” , ”− l ” , ” / b i n ” , NULL} ; p i d t pid 0 , pid ; int status ; pid 0 = fork ( ) ; i f ( p i d 0 == 0 ) { / ∗ HIIJO ∗ / p r i n t f ( ” H i j o : e j e c u t a n d o l s \n ” ) ; execvp ( l s a r g s [ 0 ] , l s a r g s ) ; p e r r o r ( ” execvp ha f a l l a d o ” ) ; } else i f ( p i d 0 > 0 ) { / ∗ PADRE ∗ / i f ( ( p i d = w a i t (& s t a t u s ) ) < 0 ) { p e r r o r ( ” w a i t ha f a l l a d o ” ) ; exit (1) ; } p r i n t f ( ” Padre : he terminado \n ” ) ; } else { p e r r o r ( ” Ha f a l l a d o e l f o r k ” ) ; exit (1) ; } r e t u r n 0 ; / / r e t o r n o con e x i t o } Referencias ⇒ Francisco M. Márquez. Unix, Programación Avanzada. Editorial: Ra-Ma. 3a Edición. ISBN: 84-7897-603-5