Está en la página 1de 25

Universidad de Murcia

Facultad de Informtica Departamento de Ingeniera y Tecnologa de Computadores

rea de Arquitectura y Tecnologa de Computadores

PRCTICAS DE SS.OO.
I.I./I.T.I. Sistemas/I.T.I. Gestin

Prctica 3  Llamadas al Sistema en Linux

Enero de

ndice
1. La llamada

1.1. Ejemplo de uso de fork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2. Ejemplo de uso de exec . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3. Ejemplo de uso de fork y exec conjuntamente . . . . . . . . . . . . . . . . . . . . . 2.1. fork_exec_wait.c 2.2. runcom.c . . . . . 2.3. signal.c . . . . . 2.4. sigaction.c . . . . 2.5. sigaction_chld.c 2.6. envia.c . . . . . . 2.7. alarma.c . . . . . 2.8. pipe3men.c . . . 2.9. pipecapa.c . . . . 2.10. pipe2com.c . . . 2.11. fo_esc.c . . . . 2.12. fo_lee.c . . . .
PROCESOS COMUNICACIONES ENTRE PROCESOS. SEALES COMUNICACIONES ENTRE PROCESOS. TUBERAS COMUNICACIONES ENTRE PROCESOS. FIFO's BIBLIOGRAFA Listados

fork

3 4 5

2.

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

6 7 8 9 10 12 13 15 16 17 19 21
22 23 24 25 25

3. 4. 5. 6. 7.

1.

La llamada

fork

1.1. Ejemplo de uso de fork

1.2. Ejemplo de uso de exec

1.3. Ejemplo de uso de fork y exec conjuntamente

2.

Listados

2.1. fork_exec_wait.c
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43

/ El s i g u i e n t e programa muestra e l uso de f o r k , e x e c y w a i t . . . /

#include <s t d i o . h> #include < s t d l i b . h> #include <u n i s t d . h> int main ( void ) { int p i d ;
p r i n t f ( " Hasta a q u hay un n i c o p r o c e s o . . . \ n" ) ; p r i n t f ( " Primera llamada a f o r k . . . \ n" ) ;

/ Creamos un nuevo p r o c e s o . / pid = f o r k ( ) ;

if

else if if

( p i d == 0 ) { p r i n t f ( "HIJO1 : p r i n t f ( "HIJO1 : sleep (60) ; } ( pid > 0) p r i n t f ( "PADRE:

Hola , yo soy e l p r i m e r h i j o . . . \ n" ) ; Voy a pararme d u r a n t e 60 s e g . y l u e g o t e r m i n a r . . . \ n" ) ; { Hola , soy e l padre . El p i d de mi h i j o e s : % d\n" , p i d ) ;

/ Creamos un nuevo p r o c e s o . / pid = f o r k ( ) ; ( p i d == 0 ) { p r i n t f ( "HIJO2 : Hola , soy e l segundo h i j o . . . \ n" ) ; p r i n t f ( "HIJO2 : El segundo h i j o va a e j e c u t a r l a orden ' l s ' . . . \ n" ) ; e x e c l p ( " l s " , " l s " ,NULL) ; p r i n t f ( "HIJO2 : S i ve e s t e mensaje , e l e x e c l p no f u n c i o n . . . \ n" ) ; } ( pid > 0) { p r i n t f ( "PADRE: Hola o t r a vez . Pid de mi segundo h i j o : % d\n" , p i d ) ; p r i n t f ( "PADRE: Voy a e s p e r a r a que t e r m i n e n mis h i j o s . . . \ n" ) ; p r i n t f ( "PADRE: Ha terminado mi h i j o % d\n" , w a i t (NULL) ) ; p r i n t f ( "PADRE: Ha terminado mi h i j o % d\n" , w a i t (NULL) ) ; }

else if else

p r i n t f ( "Ha habido a l g n e r r o r a l l l a m a r por 2 a vez a l f o r k \n" ) ; habido a l g n e r r o r a l l l a m a r a f o r k \n" ) ;

else p r i n t f ( "Ha return 0 ;

2.2. runcom.c
2 4 6 8 10 12 14 16 18 20

#include

" s m a l l s h . h"

/ E j e c u t a una orden . " c l i n e " e s una a r r a y de p a l a b r a s que c o n t i e n e e l nombre de l a orden y l o s parmetros de d i c h a orden . " where " i n d i c a s i d i c h a orden s e debe e j e c u t a r en primer o segundo p l a n o . /
runcommand (

int

char c l i n e , int where ) int pid , e x i t s t a t , r e t ; if ( ( p i d = f o r k ( ) ) < 0 ) { perror (" smallsh ") ; return ( 1) ; if

( p i d == 0 ) { execvp ( c l i n e , c l i n e ) ; perror ( c l i n e ) ;

22 24 26 28 30 32 34 36 38 40

exit (127) ;

/ Estamos en e l / Ejecutamos l a / Se l l e g a a q u e j e c u t a r . Por producido un e r r o r . /

h i j o . / orden . / s i no s e ha p o d i d o t a n t o , s e ha

/ Estamos en e l padre . S i l a orden s e e j e c u t a en segundo plano , no debemos e s p e r a r por l o que mostramos e l p i d d e l nuevo p r o c e s o y regresamos . / ( where == BACKGROUND) { p r i n t f ( " [ I d e n t i f i c a d o r de p r o c e s o : % ] \ n" , p i d ) ; d (0) ; }

if

return

while
}

/ S i l a orden s e e j e c u t a en primer plano , debemos e s p e r a r a que t e r m i n e . / ( ( r e t = w a i t (& e x i t s t a t ) ) != p i d && r e t != 1) ;


== 1 ? 1 : e x i t s t a t ) ;

return ( r e t

/ $Id : runcom . c 1399 2007 12 20 0 9 : 4 5 : 0 7 Z p e d r o e $ /

2.3. signal.c
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39

El s i g u i e n t e programa muestra cmo t r a b a j a n l a s s e a l e s . E s t e programa c a p t u r a l a s e a l SIGINT ( s e a l de i n t e r r u p c i n generada con CTRL C) . Probar e l programa r e p e t i d a s v e c e s . En una de e l l a s , no p u l s a r CTRL C, en o t r a p u l s a r "una v e z " CTRL C a n t e s de que t e r m i n e l a e j e c u c i n y o t r a p u l s a r "ms de una v e z " CTRL C a n t e s de que t e r m i n e l a e j e c u c i n . /

#include <s i g n a l . h> #include <s t d i o . h> void t r a t a _ s i g ( int ) ; int main ( void ) {
/ E s t e e s e l p r o t o t i p o de l a f u n c i n que va a t r a t a r l a s e a l . /

/ Hasta que no s e e j e c u t e l a s i g u i e n t e orden , l a s e a l SIGINT p r o v o c a r l a t e r m i n a c i n d e l p r o c e s o ( a c c i n por d e f e c t o ) . /


s i g n a l ( SIGINT , t r a t a _ s i g ) ;

/ Tras l a e j e c u c i n d e l " s i g n a l " a n t e r i o r , e l c o n t r o l p a s a r a l a f u n c i n " t r a t a _ s i g " s i s e r e c i b e l a s e a l SIGINT .


p r i n t f (" Sleep sleep (1) ; p r i n t f (" Sleep sleep (1) ; p r i n t f (" Sleep sleep (1) ; p r i n t f (" Sleep sleep (1) ; numero 1 . \ n" ) ; numero 2 . \ n" ) ; numero 3 . \ n" ) ; numero 4 . \ n" ) ;

return

p r i n t f ( " Se ha terminado l a e j e c u c i n . \ n" ) ; 0;

void
}

trata_sig ( num_sig ) { p r i n t f ( " \ nSe ha c a p t u r a d o l a s e a l nmero % d\n" , num_sig ) ; p r i n t f ( " S a l i m o s de l a r u t i n a de a t e n c i n a l a i n t e r r u p c i n \n\n" ) ;

int

2.4. sigaction.c
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52

El s i g u i e n t e programa muestra e l uso de l a f u n c i n s i g a c t i o n . E s t e programa c a p t u r a l a s e a l SIGINT ( s e a l de i n t e r r u p c i n generada con CTRL C) una v e z . Probar e l programa r e p e t i d a s v e c e s . En una de e l l a s , no p u l s a r CTRL C, en o t r a p u l s a r "una v e z " CTRL C a n t e s de que t e r m i n e l a e j e c u c i n y o t r a p u l s a r "ms de una v e z " CTRL C a n t e s de que t e r m i n e l a e j e c u c i n . /

#include <s i g n a l . h> #include <s t d i o . h> #include < s t d l i b . h> void t r a t a _ s i g ( int ) ; int main ( void ) { struct s i g a c t i o n a c c i o n ;
sigset_t conjunto ;

/ E s t e e s e l p r o t o t i p o de l a f u n c i n que va a t r a t a r l a s e a l . /

/ E s t a b l e c e m o s e l comportamiento d e l programa a n t e l a s e a l SIGINT . La f u n c i n s i g e m p t y s e t p e r m i t e c o n s t r u i r un con j u n t o de s e a l e s a b l o q u e a r . No vamos a b l o q u e a r ninguna . / s i g e m p t y s e t (& c o n j u n t o ) ; a c c i o n . sa_handler=t r a t a _ s i g ; a c c i o n . sa_mask=c o n j u n t o ; a c c i o n . s a _ f l a g s=SA_ONESHOT; a c c i o n . s a _ r e s t o r e r=NULL; / Hasta que no s e e j e c u t e l a s i g u i e n t e orden , l a s e a l SIGINT p r o v o c a r l a t e r m i n a c i n d e l p r o c e s o ( a c c i n por d e f e c t o ) . /
s i g a c t i o n ( SIGINT,& a c c i o n ,NULL) ;

/ Tras l a e j e c u c i n d e l " s i g n a l " a n t e r i o r , e l c o n t r o l p a s a r a l a f u n c i n " t r a t a _ s i g " s i s e r e c i b e l a s e a l SIGINT .


p r i n t f (" Sleep sleep (1) ; p r i n t f (" Sleep sleep (1) ; p r i n t f (" Sleep sleep (1) ; p r i n t f (" Sleep sleep (1) ; numero 1 . \ n" ) ; numero 2 . \ n" ) ; numero 3 . \ n" ) ; numero 4 . \ n" ) ;

return

p r i n t f ( " Se ha terminado l a e j e c u c i n . \ n" ) ; 0;

void
}

trata_sig ( num_sig ) { p r i n t f ( " \ nSe ha c a p t u r a d o l a s e a l nmero % d\n" , num_sig ) ; p r i n t f ( " S a l i m o s de l a r u t i n a de a t e n c i n a l a i n t e r r u p c i n \n\n" ) ;

int

2.5. sigaction_chld.c
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54

#include #include #include

El s i g u i e n t e programa muestra e l uso de l a f u n c i n s i g a c t i o n con l a s e a l SIGCHLD. La r u t i n a de t r a t a m i e n t o o b t i e n e un parmetro a d i c i o n a l l l a m a d o " i n f o " con i n f o r m a c i n a d i c i o n a l , e n t r e o t r a s , e l PID d e l programa que acaba de t e r m i n a r y que h i z o que s e l a n z a r a l a s e a l SIGCHLD. El h i j o termina t r a s imprimir un mensaje , y e l padre r e c i b e l a s e a l en cuanto e s t e termina . / <s i g n a l . h> <s t d i o . h> < s t d l i b . h>

void t r a t a m i e n t o ( int n s i g , s i g i n f o _ t int main ( void ) { struct s i g a c t i o n a c c i o n ; sigset_t conjunto ; int p i d ;

/ E s t e e s e l p r o t o t i p o de l a f u n c i n que va a t r a t a r l a s e a l . / info , nada ) ;

void

/ E s t a b l e c e m o s e l comportamiento d e l programa a n t e l a s e a l SIGCHLD. La f u n c i n s i g e m p t y s e t p e r m i t e c o n s t r u i r un con j u n t o de s e a l e s a b l o q u e a r m i e n t r a s s e t r a t a SIGCHLD. / s i g e m p t y s e t (& c o n j u n t o ) ; s i g a d d s e t (& c on ju nt o , SIGCHLD) ; a c c i o n . s a _ s i g a c t i o n=t r a t a m i e n t o ; a c c i o n . sa_mask=c o n j u n t o ; a c c i o n . s a _ f l a g s=SA_RESTART | SA_SIGINFO ; a c c i o n . s a _ r e s t o r e r=NULL; / A c t i v a e l t r a t a m i e n t o de SIGCHLD / s i g a c t i o n (SIGCHLD,& a c c i o n , ( )NULL) ;

void

/ Tras l a e j e c u c i n d e l " s i g n a l " a n t e r i o r , e l c o n t r o l p a s a r a l a f u n c i n " t r a t a m i e n t o " s i s e r e c i b e l a s e a l SIGCHLD ( cuando t e r m i n e c u a l q u i e r h i j o ) /


p r i n t f ( " I n i c i o : Llamando a f o r k . \ n" ) ;

/ Creamos un nuevo p r o c e s o . / pid = f o r k ( ) ;

if

return else if

( p i d == 0 ) { p r i n t f ( "HIJO : Hola , yo soy e l p r i m e r h i j o . . . \ n" ) ; p r i n t f ( "HIJO : Tras 5 s e g u n d o s voy a t e r m i n a r para que " " e l padre r e c i b a mi s e a l . \ n" ) ; sleep (5) ; 0; ( pid > 0) { p r i n t f ( "PADRE: Hola , soy e l padre . El p i d de mi h i j o e s : % d\n" , p i d ) ; p r i n t f ( "PADRE: R e a l i z a n d o c u a l q u i e r o t r a o p e r a c i n . . . \ n" ) ; sleep (10) ;

return

p r i n t f ( "PADRE: Se ha terminado l a e j e c u c i n . \ n" ) ; 0;

10

}
56 58 60 62 64 66 68 70 72 74

} {

return

0; nsig , siginfo_t info ,

void t r a t a m i e n t o ( int int e x i t s t a t ;

void nada )

p r i n t f ( " \nPADRE: Se ha c a p t u r a d o l a s e a l nmero % d\n" , n s i g ) ;

/ Acceso a i n f o >si_pid , i n f o >s i _ s i g n o , e t c . / / ( s i _ p i d e s e l p i d d e l p r o c e s o que e n v a l a s e a l / p r i n t f ( "PADRE: El h i j o que ha terminado t i e n e e l p i d % d\n" , i n f o >s i _ p i d ) ; / Esperar a l p r o c e s o h i j o ( o b l i g a t o r i o para que no quede Zombie ) / w a i t (& e x i t s t a t ) ;
} p r i n t f ( "PADRE: El h i j o r e t o r n % . \ n" , e x i t s t a t ) ; d

11

2.6. envia.c
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50

/ El s i g u i e n t e programa muestra e l uso de k i l l para e n v i a r s e a l e s de un p r o c e s o a o t r o . /

#include <s i g n a l . h> #include <s t d i o . h> int n t i m e s =0; int main ( int argc , char argv [ ] ) { int pid , ppid ; void p_action ( int ) , c _ a c t i o n ( int ) ;
/ E s t a b l e c e m o s l a a c c i o n de l a s e a l SIGUSR1 para e l padre . / s i g n a l ( SIGUSR1 , p_action ) ;

switch ( p i d = f o r k ( ) ) case 1: p e r r o r ( argv [ 0 ] ) ; return 1 ; case 0 :

/ Error . / / H i j o . /

/ E s t a b l e c e m o s l a a c c i n para e l h i j o . / s i g n a l ( SIGUSR1 , c _ a c t i o n ) ; / Obtenemos e l p i d d e l padre . / ppid=g e t p p i d ( ) ; (;;) { sleep (1) ; k i l l ( ppid , SIGUSR1 ) ; pause ( ) ; } : / Padre . / (;;) { pause ( ) ; sleep (1) ; k i l l ( pid , SIGUSR1 ) ; }

for

default for
} }

return

0;

/ El s i g u i e n t e p r o c e d i m i e n t o s e e j e c u t a cuando s e e n v a l a s e a l SIGUSR1 a l padre . / p_action ( sig ) { p r i n t f ( " El padre ha c a p t u r a d o l a s e a l n o % d\n",++n t i m e s ) ; }

void

int

/ Idem a l a n t e r i o r pero para e l h i j o . / c_action ( sig ) { p r i n t f ( " El h i j o ha c a p t u r a d o l a s e a l # % d\n",++n t i m e s ) ; }

void

int

12

2.7. alarma.c
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54

/ El s i g u i e n t e programa me p e r m i t e e s t a b l e c e r una alarma para que imprima un mensaje cuando t r a n s c u r r a n l o s minutos que s e l e dan como parmetro . /

#include <s t d i o . h> #include <s i g n a l . h> #include < s t d l i b . h> #define TRUE 1 #define FALSE 0 #define BELLS " \007\007\007 " int a l a r m _ f l a g = FALSE ;
/ E s t e p r o c e d i m i e n t o maneja l a s e a l SIGALRM. / setflag ( nada ) { a l a r m _ f l a g = TRUE; }

void int

int

main ( int argc , char int n s e c s , p i d ; int j ; if ( a r g c <= 2 ) { }

argv [ ] ) {

f p r i n t f ( s t d e r r , "Uso : % #minutos mensaje \n" , argv [ 0 ] ) ; s exit (1) ;

if
}

( ( n s e c s = a t o i ( argv [ 1 ] ) 6 0 ) <= 0 ) { f p r i n t f ( s t d e r r , " % : nmero i n v l i d o de minutos " , argv [ 0 ] ) ; s exit (2) ;

/ Aqu creamos un p r o c e s o en segundo p l a n o . / = fork () ) { / Error . / p e r r o r ( argv [ 0 ] ) ; exit (1) ; 0: / H i j o . Es e l p r o c e s o que s e queda en segundo p l a n o . / ; : / Padre . Muestra p i d d e l p r o c e s o h i j o y termina . / p r i n t f ( " % > I d e n t i f i c a d o r de p r o c e s o : % s d\n" , argv [ 0 ] , p i d ) ; 0; }

switch ( p i d case 1: case break default return

/ Fijamos l a a c c i n para l a alarma . / s i g n a l (SIGALRM, s e t f l a g ) ; / Activamos l a alarma . / alarm ( n s e c s ) ; / Esperamos h a s t a que r e c i b a m o s una s e a l . . . / pause ( ) ;

13

56 58 60 62 64 66

/ S i l a s e a l r e c i b i d a e s SIGALRM, mostramos e l mensaje . / ( a l a r m _ f l a g == TRUE) { p r i n t f (BELLS) ; p u t c h a r ( ' \n ' ) ; ( j = 2 ; j < a r g c ; j ++) p r i n t f ( " % " , argv [ j ] ) ; s p r i n t f ( " \n" ) ; }

if

for

return

0;

14

2.8. pipe3men.c
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52

El s i g u i e n t e programa muestra e l uso de t u b e r a s para p a s a r i n f o r m a c i n de un p r o c e s o a uno de s u s d e s c e n d i e n t e s o v i c e v e r s a . En n u e s t r o ejemplo , un padre e n v a t r e s mensajes a un h i j o que s e encarga de l e e r l o s . /

#include <s t d i o . h> #define MSGSIZE 17

/ Tamao d e l mensaje . /
no 1 " ; no 2 " ; no 3 " ;

char msg1 = " Hola , mundo char msg2 = " Hola , mundo char msg3 = " Hola , mundo int main ( void ) { char i n b u f [ MSGSIZE ] ; int p [ 2 ] , j , p i d ; if return

/ Mensajes a e n v i a r . /

/ Abrimos l a t u b e r a . / ( pipe (p) < 0) { p e r r o r ( " llamada a p i p e " ) ; 1; } / Creamos e l p r o c e s o h i j o . Dicho p r o c e s o h e r e d a l o s d e s c r i p t o r e s de l o s dos e x tr e mo s de l a t u b e r a . / ( ( pid = f o r k ( ) ) < 0) { p e r r o r ( " llamada a l f o r k " ) ; 2; }

if

return

/ S i e s e l padre , e n t o n c e s c i e r r a e l d e s c r i p t o r d e l f i c h e r o de l e c t u r a y e s c r i b e en l a t u b e r a l o s t r e s mensajes . / ( pid > 0) { close (p [ 0 ] ) ; w r i t e ( p [ 1 ] , msg1 , MSGSIZE) ; w r i t e ( p [ 1 ] , msg2 , MSGSIZE) ; w r i t e ( p [ 1 ] , msg3 , MSGSIZE) ; w a i t (NULL) ; }

if

/ S i e s e l h i j o , e n t o n c e s c i e r r a e l d e s c r i p t o r d e l f i c h e r o de e s c r i t u r a y l e e de l a t u b e r a / ( p i d == 0 ) { close (p [ 1 ] ) ; ( j = 0 ; j < 3 ; j ++) { r e a d ( p [ 0 ] , i n b u f , MSGSIZE) ; p r i n t f ( " % \n" , i n b u f ) ; s } } 0;

if

for

return

15

2.9. pipecapa.c
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42

/ El s i g u i e n t e programa e s c r i b e d a t o s en una t u b e r a h a s t a que s t a s e b l o q u e a . E s t e hecho e s u t i l i z a d o para d e t e r m i n a r l a c a p a c i d a d de una t u b e r a . En n u e s t r o caso , s a l e un tamao de 4096 b y t e s . /

#include <s i g n a l . h> #include <s t d i o . h> #include < s t d l i b . h> int count ; void alrm_action ( int ) ; int main ( void ) { int p [ 2 ] ; char c= ' x ' ; if ( p i p e ( p ) <0) { for

} s i g n a l (SIGALRM, alrm_action ) ; ( count = 0 ; ; ) { / Activamos l a alarma . / alarm ( 2 0 ) ; w r i t e ( p [ 1 ] , &c , 1 ) ;

p e r r o r ( " llamada a p i p e " ) ; exit (1) ;

/ Desactivamos l a alarma . S i no l l e g a m o s aqu , e s por que l a orden w r i t e a n t e r i o r s e ha quedado b l o q u e a d a a l e s t a r l l e n a l a t u b e r a . Al no d e s a c t i v a r l a alarma , s e d i s p a r a y s e e j e c u t a e l p r o c e d i m i e n t o " alrm_action " que muestra un mensaje y termina l a e j e c u c i n d e l p r o c e s o . / alarm ( 0 ) ;

if
} }

((++ count % 1 0 2 4 ) == 0 ) p r i n t f ( " % c a r a c t e r e s en l a t u b e r a \n" , count ) ; d 0;

return

/ Se e j e c u t a cuando s e r e c i b e l a s e a l SIGALRM. / alrm_action ( nada ) { p r i n t f ( " E s c r i t u r a bloqueada d e s p u s de % c a r a c t e r e s \n" , count ) ; d exit (0) ; }

void

int

16

2.10. pipe2com.c
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53

El s i g u i e n t e programa muestra e l uso de l a s t u b e r a s y l a l l a m a d a a l s i s t e m a " e x e c " . En c o n c r e t o , s e ve cmo s e puede c o n e c t a r l a s a l i d a e s t n d a r de un programa a l a e n t r a d a e s t n d a r de o t r o ( e s t e meca nismo s e c o n s i g u e en e l s h e l l con e l s m b o l o ' | ' ) . /

#include <s t d i o . h> #include < s t d l i b . h> void f a t a l ( char s ) {


} perror ( s ) ; exit (1) ;

/ Une dos r d e n e s mediante una t u b e r a . Como parmetros r e c i b e dos a r r a y s de cadenas , cada uno con e l nombre de l a orden y parmetros c o r r e s p o n d i e n t e s . / join ( com1 [ ] , com2 [ ] ) {

int

int

char

char

p [2] , status ;

switch ( f o r k ( ) ) { case 1: / Error . / f a t a l ( " Primera llamada a f o r k en j o i n " ) ; case 0 : / H i j o . / break ; default : / Padre . Espera a que su h i j o t e r m i n e w a i t (& s t a t u s ) ; return ( s t a t u s ) ;
/ E s t e e s e l c d i g o d e l primer h i j o c r e a d o . / / Creamos l a t u b e r a . / ( pipe (p) < 0) f a t a l ( " Llamada a p i p e en j o i n " ) ;

/ Creamos un p r o c e s o h i j o para e j e c u t a r l a s r d e n e s . /

y r e g r e s a . /

if

switch ( f o r k ( ) ) { case 1: / Error . / f a t a l ( " Segunda llamada case 0 : / Cdigo d e l


close (1) ; dup ( p [ 1 ] ) ; close (p [ 0 ] ) ; close (p [ 1 ] ) ;

/ Creamos un nuevo proceso , h i j o d e l a n t e r i o r h i j o . /


a f o r k en j o i n " ) ; segundo h i j o . /

/ / /

Cerramos l a s a l i d a e s t n d a r a c t u a l . / Creamos un nuevo d e s c r i p t o r para e l d e s c r i p t o r de e s c r i t u r a de l a t u b e r a . / Cerramos l o s d e s c r i p t o r e s de l a t u b e r a . /

/ S i s e r e g r e s a de " e x e c v p " e s porque ha f a l l a d o . / execvp ( com1 [ 0 ] , com1 ) ; f a t a l ( " Primera llamada a execvp en j o i n " ) ;

default :

/ Cdigo d e l primer h i j o . /

17

55 57 59 61 63 65 67 69 71 73 75 77 79 81 83

close (0) ; dup ( p [ 0 ] ) ; close (p [ 0 ] ) ; close (p [ 1 ] ) ;

/ / /

Cerramos l a e n t r a d a e s t n d a r a c t u a l . / Creamos un nuevo d e s c r i p t o r de f i c h e r o para e l d e s c r i p t o r de l e c t u r a de l a t u b e r a . / Cerramos l o s d e s c r i p t o r e s de l a t u b e r a . /

/ S i s e r e g r e s a de " e x e c v p " e s porque ha f a l l a d o . / execvp ( com2 [ 0 ] , com2 ) ; f a t a l ( " Segunda llamada a execvp en j o i n " ) ;

char char int

/ Primera orden y s u s parmetros . / one [ ] = { " l s " , " l " , " / u s r / l i b " ,NULL };

/ Segunda orden y s u s parmetros . / two [ ] = { " g r e p " , "^d" ,NULL };

int

main ( ret ;

void )

return

r e t = j o i n ( one , two ) ; printf (" join devolvi % d\n" , r e t ) ; ret ;

18

2.11. fo_esc.c
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54

El s i g u i e n t e programa muestra e l uso de una "FIFO " . E s t e programa e s c r i b e en l a FIFO l o s mensajes que r e c i b e como parmetros . Antes de e j e c u t a r e s t e programa debemos c r e a r l a FIFO ( con " m k f i f o t u b o ") y e j e c u t a r en segundo p l a n o e l programa que l e e l o s mensajes de l a FIFO (" pag160 &") .

#include < f c n t l . h> #include <s t d i o . h> #include <e r r n o . h> #include < s t d l i b . h> #include <s t r i n g . h> #define MSGSIZ 63 / extern int e r r n o ; char f i f o = " tubo " ; void
} fatal ( perror ( s ) ; exit (1) ; main (

Tamao mximo d e l mensaje . / / Nombre de l a FIFO . /

char

s ) {

int

int fd , j , n w r i t e ; char msgbuf [ MSGSIZ+ 1 ] ; if ( a r g c < 2 ) {


}

int

argc ,

char

argv [ ] ) {

f p r i n t f ( s t d e r r , "Uso : % mensaje . . . . \ n" , argv [ 0 ] ) ; s exit (1) ;

/ Abrimos l a FIFO para s l o e s c r i t u r a y con e s c r i t u r a s no b l o q u e a n t e s cuando l a FIFO e s t l l e n a (O_NDELAY) . / ( ( f d = open ( f i f o , O_WRONLY | O_NDELAY) ) < 0 ) f a t a l ( " f a l l l a a p e r t u r a de l a FIFO" ) ;

if

/ Enviamos mensajes . / ( j = 1 ; j < a r g c ; j ++) {

for

if ( s t r l e n ( argv [ j ] ) f p r i n t f ( stderr , continue ; if

> MSGSIZ) { " mensaje demasiado l a r g o % \n" , argv [ j ] ) ; s

s t r c p y ( msgbuf , argv [ j ] ) ;

/ E s c r i b i m o s e l mensaje en l a FIFO . / ( ( n w r i t e = w r i t e ( fd , msgbuf , MSGSIZ + 1 ) ) <= 0 ) { / S i f a l l a l a e s c r i t u r a en l a FIFO por e s t a r l l e n a , mostramos

19

56 58 60 62 64 66 68

} }

e l c o r r e s p o n d i e n t e mensaje de e r r o r . / ( n w r i t e == 0 ) e r r n o = EAGAIN; f a t a l ( "Ha f a l l a d o l a e s c r i t u r a d e l mensaje " ) ;

if

return

0;

Nota . El s i g n i f i c a d o de EAGAIN e s : " Recurso temporalmente no d i s p o n i b l e , i n t e n t a r o t r a v e z ms t a r d e " . Esto s i g n i f i c a normalmente que una t a b l a p a r t i c u l a r de s i s t e m a e s t l l e n a . Por ejemplo , e s t e e r r o r puede s e r generado por una l l a m a d a a f o r k cuando hay dema s i a d o s p r o c e s o s . /

20

2.12. fo_lee.c
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38

E s t e programa l e e l o s mensajes e s c r i t o s en una FIFO y l o s muestra por p a n t a l l a . Funciona j u n t o con e l programa que e s c r i b e l o s mensajes en l a FIFO . Se debe e j e c u t a r en segundo p l a n o a n t e s que e l programa que e n v a l o s mensajes , siempre que a n t e s s e c r e e l a FIFO que s e u t i l i z a (" m k f i f o t u b o ") . /

#include < f c n t l . h> #include <s t d i o . h> #include < s t d l i b . h> #define MSGSIZ 63 char f i f o = " tubo " ; void f a t a l ( char s ) {
} perror ( s ) ; exit (1) ; main (

/ Nombre de l a FIFO que s e u t i l i z a . /

int

int f d ; char msgbuf [ MSGSIZ+ 1 ] ;


/ Abrimos l a FIFO para l e c t u r a y e s c r i t u r a . / ( ( f d = open ( f i f o , O_RDWR) ) < 0 ) f a t a l ( "Ha f a l l a d o l a a p e r t u r a de l a f i f o " ) ;

int

argc ,

char

argv [ ] ) {

if

for ( ; ; ) { if ( r e a d ( fd ,
} }

msgbuf , MSGSIZ+1) < 0 ) f a t a l ( "Ha f a l l a d o l a l e c t u r a d e l mensaje " ) ;

/ E s c r i b i m o s l o s mensajes conforme s e van r e c i b i e n d o . / p r i n t f ( " mensaje r e c i b i d o : % \n" , msgbuf ) ; s


0;

return

21

3.

PROCESOS

Proceso = programa en ejecucin.


Un proceso puede crear otros procesos rbol de procesos. Su raz la ocupa el proceso init, que es el segundo proceso que se ejecuta (el primero es el planicador o scheduler).

int pid = fork(). Crea un nuevo proceso (hijo del que hace la llamada a fork). Padre e hijo continan la ejecucin en la instruccin inmediatamente posterior al fork (VER FIGURA). pid = 0 en el hijo, >0 en el padre (y contiene el pid del hijo) y <0 si error exec. Se ejecuta en el espacio del proceso llamador (VER FIGURA). 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[]);

argv es similar al que aparece en main(int argc, char *argv[]);

Herencia en fork: el hijo hereda todas las variables del padre con los mismos valores (excepto
el valor que devuelve el fork), pero son independientes. Los cheros abiertos en el padre, lo estn en el hijo tambin se comparten (y, por tanto, el puntero del chero,....). No obstante, cerrar un chero en el padre no afecta a los del hijo, y viceversa.

defecto a o) con fcntl, para que se cierren automticamente tras al hacer el exec. Por ejemplo:
fcntl(fd,f_setfd,1);

Herencia en exec: deja los cheros abiertos. Se debe activar el ag close_on_exec (por

hace que el chero representado por FD se cierre en un exec.

void exit(int estado). Para terminar un proceso. Tambin se termina al llegar al nal del

cdigo o con un return desde main. Se suele colocar exit(0) si ha habido xito o exit(!=0) si ha habido algn tipo de error. Los 8 bits bajos de un exit estn disponibles en el padre en los 8 bits altos (ver wait).

int resultado = wait(int *estado). Se utiliza en el padre para esperar a que terminen los
hijos.
Si como puntero se pasa NULL, se ignora el valor de estado. La funcin devuelve el pid del hijo que termina o -1 si ha habido error (no hay hijos,....). Si los 8 bits menos signicativos del estado tienen un valor distinto de 0 signica que el

hijo termin por una seal (y el valor es el nmero de seal).

22

Si son 0, en los 8 bits ms signicativos tenemos el valor que se coloc como parmetro

en el exit.

Zombie: hijo que hizo exit pero cuyo padre no ha hecho un wait. Hurfano: un padre puede terminar sin wait hijos adoptados por el proceso de inicializacin del sistema (init). int pid = getpid(). Devuelve el pid del proceso que la ejecuta. int pid_padre = getppid(). Devuelve el pid del padre.
Variables de entorno.
void main(int argc, char *argv[], char *envp[]);

Por ejemplo, envp[0] puede tener unvalor como HOME=/home/usuario.


4. COMUNICACIONES ENTRE PROCESOS. SEALES

void (*was) () = signal(int sig, void (*fun) ()). Captura la seal sig mediante la
funcin fun. Devuelve un puntero a la funcin que previamente capturaba sig. Tipos de seales:

SIGINT: Interrupcin. Generada por el ncleo al pulsar la tecla de interrupcin (CTRLC).

SIGQUIT: Terminar. Muy similar a SIGINT. Enviada por el ncleo cuando se pulsa

la tecla de terminacin (CTRL-\). A diferencia de SIGINT, provoca una terminacin anormal (toda terminacin anormal provoca un core dump, es decir, un vaciado de memoria). SIGILL: Instruccin ilegal Terminacin anormal. SIGFPE: Error de punto otante Terminacin anormal. SIGKILL: Enviada por un proceso o por el ncleo a otro proceso para que termine forzosamente ste ltimo. No se puede capturar. SIGPIPE: Enviada por el ncleo cuando se escribe en una tubera que no tiene un proceso que lea. SIGALRM: Alarma. Enviada por el ncleo a un proceso transcurrido un cierto tiempo (ver la funcin ALARM). SIGTERM: Seal de terminacin software. Se utiliza para solicitar a un proceso que termine. No la enva el ncleo (ver KILL). SIGUSR1 y SIGUSR2: No las enva el ncleo y se pueden utilizar para lo que se quieran.

Hay algunos tipos ms de seales.

Funciones especiales. Como segundo parmetro de la funcin signal se puede pasar

una funcin normal o las funciones SIG_IGN (simplemente hace que la seal se ignore) y SIG_DFL (que indica que se realice la accin por defecto asociada a la seal).

23

Si una seal no se captura Terminacin (normal o anormal, segn el tipo de seal) del proceso receptor. Se pueden tratar varios tipos de seales a la misma vez. Las seales ignoradas por un proceso (SIG_IGN) siguen ignoradas tras un exec. Qu pasa si un proceso en segundo plano no quiere que se ignoren? Hay llamadas al sistema que, excepcionalmente, son interrumpidas por una seal, como read, write,..... La funcin sigaction y otras funciones asociadas permiten un control total sobre las seales. Entre otras cosas, permite bloquear seales mientras se tratan otras, y si la rutina de tratamiento de una seal permanece instalada indenidamente o se desinstala tras recibir la seal. En el caso concreto de tratar la seal sigchld el parmetro sa_ags debe ser SA_RESTART | SA_SIGINFO, y la funcin callback tendr la forma:
void tratamiento(int nsig, siginfo_t* info, void*nada) { /* Acceso a info->si_pid, info->si_signo, etc.*/ /* (si_pid es el pid del proceso que enva la seal */ }

int kill(int pid, int sig). Permite enviar una seal de un proceso a otro, siempre que coincidan

sus UID (identicador de usuario) reales o efectivos. Los procesos de superusuario pueden enviar seales a cualquier otro. KILL devuelve -1 si:
No coinciden los UID's reales o efectivos. No existe el proceso. No existe ese tipo de seal.

Hay valores de pid que se le pasan a KILL con signicados especiales.

unsigned int alarm(unsigned int seg). Hace que se enve una seal SIGALRM al proceso,

despus de seg segundos. Una alarma se desactiva con alarm(0). Devuelve los segundos que quedaban para que se cumpliera la anterior alarma. Una alarma permanece activa tras un exec pero no en un hijo, tras un fork.

int pause(void). Detiene temporalmente un proceso hasta que ste reciba una seal (siempre que no la ignore porque, entonces, pause tambin la ignorar). Devuelve -1 cuando la seal se captura. Un proceso suspendido temporalmente no consume recursos del sistema.
5. COMUNICACIONES ENTRE PROCESOS. TUBERAS

Es una generalizacin del concepto de chero ya que se utilizan las mismas rdenes read, write y close que se utilizan con cheros.

Una tubera (pipe) es un canal de comunicaciones unidireccional que conecta dos procesos. int pipe(int ledes[2]). Para crear la tubera. ledes[0] es el descriptor de chero de lectura

de la tubera y ledes[1] es el descriptor para la escritura en la tubera. lseek no funciona en una tubera. Los buers de lectura y escritura en la tubera pueden tener distinto tamao.

24

Tras un fork, el hijo tiene dos descriptores propios para la tubera. Conviene que cada uno cierre (close) el que no vaya a utilizar.

Bloqueos. Un write en una tubera se bloquea si est llena y un read se bloquea si est vaca
(aunque se puede hacer que tanto el write como el read sean no bloqueantes). Cerrar un extremo de una tubera:

Extremo de slo escritura: si hay ms procesos que escriban en la tubera, no pasa nada. Si no es as, a los procesos que lean de la tubera a partir de ese momento reciben del read un 0. Si haba procesos bloqueados porque la tubera estaba vaca, se les despierta del read, que devuelve tambin 0. Extremo de slo lectura: si hay ms procesos que lean de la tubera, no pasa nada. Si no es as, a todos los procesos que estn bloqueados en write o que intenten escribir a partir de ese momento, se les enva una seal SIGPIPE por el ncleo. Si capturan SIGPIPE, los siguientes writes devuelven -1.

6. COMUNICACIONES ENTRE PROCESOS. FIFO's

Problemas de las tuberas:


Comunican procesos que comparten un ancestro (por ejemplo, un proceso padre y uno

de sus hijos). Este problema surge al intentar crear un servidor. No pueden ser permanentes. Diferencias:

Una FIFO o tubera nombrada (named pipe) funciona prcticamente igual que una tubera.
Es permanente. Tiene un nombre de chero, un propietario, un tamao y permisos. Se abre, se cierra y borrar igual que un chero.

Creacin de una FIFO: mkfo <nombre>. Tambin se puede utilizar la orden mknod
<nombre>p.
7. BIBLIOGRAFA

UNIX: programacin avanzada. Mrquez Garca, Fo Manuel. UNIX: sistema y entorno. Fontaine, A.B. UNIX system programing. Haviland, Keith.

25

También podría gustarte