IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

Crides de sistema Unix

De SergiTurWiki
Share/Save/Bookmark
(S'ha redirigit des de: Crides de sistema)
Dreceres ràpides: navegació, cerca

Crides de sistema

Recursos:

Instal·lació de manuals (man pages)

Per disposar dels manuals de les crides de sistema POSIX podeu instal·lar:

$ sudo apt-get install manpages-posix

La majoria de crides de sistema estan al paquet manpages-dev:

$ sudo apt-get install manpages-dev 

Si teniu dubtes de quin paquet es necessita per tenir cert manual podeu utilitzar la comanda dpkg i el fet de saber que els manuals es troben a:

/usr/share/man/manx

On x és la secció del manual. Sabem (o podeu consultar al manual de man - $ man man) que les crides de sistema estan a la secció 2. Per tant si volem saber qui ens proporciona el manual de fork:

$ dpkg -S /usr/share/man/man2/fork.2.gz 
manpages-dev: /usr/share/man/man2/fork.2.gz

Més sobre manuals de Linux a Manuals de Linux/Unix.

Gestió d’entrades/sortides de fitxers

Conceptes previs

Descriptors de fitxers

Hi han tres descriptors de fitxer per defecte:

  • 0: Canal estàndard d'entrada
  • 1: Canal estàndard de sortida
  • 2: Canal estàndard d'error.

Aquests descriptors de fitxers es troben definits al fitxer unistd.h:

$ cat /usr/include/unistd.h
#define STDIN_FILENO    0       /* Standard input.  */
#define STDOUT_FILENO   1       /* Standard output.  */
#define STDERR_FILENO   2       /* Standard error output.  */

Funció open

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags); 
int open(const char *pathname, int flags, mode_t mode);

Obre el fitxer de nom pathname per lectura, escritura o lectura/escritura (segons flags). Retorna el descriptor de fitxer (enter positiu).

Funció creat

int creat(const char *pathname, mode_t mode); 

Crea un fitxer buït per escriure. mode defineix els drets d’accès.

Funció read

ssize_t read(int fd, void *buf, size_t count);

Intenta llegir count bytes i els posa en la variable buf. Retorna el nombre de bytes llegits.

Funció write

ssize_t write(int fd, const void *buf, size_t count);

Escriu count bytes de la variable buf. Retorna el nombre de bytes escrits.

Exemples:

Exemple 1

#include <unistd.h>    /* biblioteca UNIX estandard   */
 ...
 write(STDERR_FILENO,"fitxer no existent\n",19);

Exemple 2:

#include<stdio.h>
#include<fcntl.h>

 main()
 {
         char *p = \"hello world\\n\";
         int fp;  

         fp = open(\"hello.c\",O_CREAT,0666);
         write(fp,p,11);
 }   

Exemple 3:

/* program to  read a list of floats from a binary file */
/* first byte of file is an integer saying how many  */
/* floats in file. Floats follow after it, File name got from */
/* command line */
 
#include<stdio.h>
#include<fcntl.h>
 
float bigbuff[1000];
  
main(int argc, char **argv) {  
 int fd;
 int bytes_read;
 int file_length;
 if ( (fd = open(argv[1],O_RDONLY)) = -1)  { /* error file not open */....
	perror("Datafile");
	exit(1);
 }
 if ( (bytes_read = read(fd,&file_length,sizeof(int))) == -1) { /* error reading file */...
       exit(1);
 }
 if ( file_length > 999 )  {/* file too big */ ....}
 if ( (bytes_read = read(fd,bigbuff,file_length*sizeof(float))) == -1) { /* error reading open */...
       exit(1);
 }
}


On la constant STDERR_FILENO es refereix a la sortida estàndard d'error (valor 2) definida al fitxer unistd.h:

$ cat /usr/include/unistd.h
...
/* Standard file descriptors.  */
#define STDIN_FILENO    0       /* Standard input.  */
#define STDOUT_FILENO   1       /* Standard output.  */
#define STDERR_FILENO   2       /* Standard error output.  */

Funció close

int close(int fd); 

Tanca el fitxer.

Funció lseek

off_t lseek(int fildes, off_t offset, int whence); 

Mou el posicionament del fitxer a una nova localització resultant d’afegir offset a una base. La base pot ser l’inici del fitxer, la localització actual del fitxer, o la mida del fitxer, sd’acord al que indiqui whence.

Funció unlink

int unlink(const char *pathname); 

Esborra el fitxer.

funció stat

 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 int stat(const char *path, struct stat *buf);
 int fstat(int filedes, struct stat *buf);
 int lstat(const char *path, struct stat *buf);

Exemples

Podeu descarregar tots els exemples d'aquest apartat aquí.

Comanda copiar

Descàrrega: copia.c.

El codi font del programa copiar (que trobareu a la carpeta exempleFitxers) és:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>

#define MIDA_BUFFER 50 

int main (int argc, char **argv) {
 
int f1, f2;
int quants, escrits;
char buf[MIDA_BUFFER];
int estat;

estat = EXIT_SUCCESS;
if (argc==3) {
  f1=open(argv[1],O_RDONLY);
  f2=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0666);
  if (f1==-1) {
    estat=EXIT_FAILURE;
    write(STDERR_FILENO,"fitxer no existent\n",19);
  }
  if (f2==-1) {
    estat=EXIT_FAILURE;
    write(STDERR_FILENO,"Problemes amb el fitxer destí\n",31);
  }
} else { 
  estat=EXIT_FAILURE;
    write(STDERR_FILENO,"Arguments incorrectes\n",22);
}
if (estat==0) {
  quants=read(f1,buf,MIDA_BUFFER);
  while(quants>0){
    escrits=write(f2,buf,quants);
    quants=read(f1,buf,MIDA_BUFFER);
  }
}
close(f1);
close(f2);
return estat;
}

Podem compilar amb:

$ gcc -o copia copia.c

Ara podeu executar la comanda copia de la següent forma:

./copia copia.c copia_de_la_comanda.c

Podeu escollir el nom que vulgueu per al fitxer copia_de_la_comanda.c.

O primer preparant el PATH:

$ PATH=$PATH":."

i aleshores executar:

$ copia copia.c copia_de_la_comanda.c

Interpretació del codi:

Includes:

$ man 2 open

NOTA: Consulteu l'apartat Manuals (man) si no teniu els manuals de les crides de sistema.

Tal com podem veure executant:

$ man man
...........
The table below shows the section numbers of the manual followed by the types of pages they contain.

      1   Executable programs or shell commands
      2   System calls (functions provided by the kernel)
      3   Library calls (functions within program libraries)
      4   Special files (usually found in /dev)
      ......................... 

L'opció 2 ens mostra les crides al sistema.

Tornant al man del open, l'apartat SYNOPSIS:

SINOPSIS
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>

Ens mostra quins han de ser els includes per poder utilitzar aquesta funció. Si tenim curiositat per saber on estan aquests includes en el nostra sistema podem executar les següents comandes:

$ sudo updatedb
$ locate fcntl.h 
..........
/usr/include/fcntl.h 

Si voleu saber quin paquet ens proporciona aquest paquet podeu utilitzar:

$ dpkg -S /usr/include/fcntl.h
libc6-dev: /usr/include/fcntl.h

Com podeu veure el paquet és libc6-dev.

Senyals

Taula de senyals

  • SIGHUP: (1) penjada d’un terminal (modem, etc) o mort d’un procés controlador acaba el procés
  • SIGINT: (2) interrupció des del teclat (ctrl-c) acaba el procés
  • SIGQUIT: (3) abandonament des del teclat (ctrl-\) crea imatge de core
  • SIGILL: (4) instrucció invàlida crea imatge de core.
  • SIGFPE: (8) excepció de coma flotant crea imatge de core
  • SIGKILL: (9) kill -9 acaba el procés
  • SIGSEGV: (11) referència de memòria invàlida. Crea imatge de core
  • SIGPIPE: (13) Escriu en un pipe però no hi ha lector. Acaba procés
  • SIGALARM: (14) alarm(). Acaba el procés
  • SIGTERM: (15) Senyal d’acabament. Acaba el procés.
  • SIGUSR1: (30,10,16). A definir. Acaba el procés.
  • SIGUSR2: (31,12,17). A definir. Acaba el procés.

Podeu trobar informació més exhaustiva de totes les senyals executant:

$ man kill

Consulteu la comanda kill a l'article Processos Linux.

Recursos:

Funció kill

int kill(pid_t pid, int sig); 

Envia el senyal sig al procés pid

Funció raise

int raise(int sig); 

Equivalent a kill(getpid(), sig); envia el senyal sig al propi procés

Funció typedef

typedef void (*sighandler_t)(int);

Funció sighandler

sighandler_t signal(int signum, sighandler_t handler);
                                                                                                                                                           Si el procés rep el senyal signum s’executarà la funció handler. Si ha anat bé retornarà l’apuntador a la funció handler o -1 si hi ha error (errno). La funció handler la pot definir l’usuari. Es disposen de dues predefinides: SID_DFL() (acaba el procés) i SIG_IGN() (ignora el senyal)

Funció sigaction

int sigaction(int s, const struct sigaction *act, struct sigaction *oldact);

Funció sigpending

int sigpending(sigset_t *set); retorna el conjunt de senyals pendents. (Les bloquejades).

Canvia l’acció a fer (act) en el cas de rebre el senyal s

Funció sigprocmask

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 

Canvia el conjunt de senyals bloquejades. how indica el comportament de l’acció: SIG_BLOCK unió del conjunt actual amb set, SIG_UNBLOCK els senyals en set s’eliminen del conjunt actual, SIG_SETMASK el conjunt de senyals a bloquejar és l’argument set.

Funció unsigned

int unsigned int alarm(unsigned int seconds); Útil per implementar timers.

Exemples

Exemples amb bash

Si creem un script bash com el següent:

$ gedit prova.sh
function accio1 {
 echo "Senyal 1 rebut (SIGHUP)"
}
trap accio1 1
while true
 do
  sleep 5
  echo "."
 done

I l'executem amb

$ bash prova.sh & 
[1] 13429

El nombre que ens torna és l'identificador del procés o PID (podrieu consultar el PID també amb ps aux). Aquest bash com veureu, mostra per la sortida estàndard un punt cada 5 segons.

$ kill -1 13429
Senyal 1 rebut (SIGHUP)

Fixeu-vos que kill no sempre mata un procés. En aquest cas el procés captura un senyal i mostra el missatge. Aquest senyal (el senyal 1) com hem vist a la taula de senyals no acaba el procés.

Si volem que el procés finalitzi pode utilitzar un script bash com el següent:

function accio1 {
 echo "Senyal 1 rebut (SIGHUP)"
 echo "Tanquem els fitxers si en tenim."
 exit
}
trap accio1 1
 while true
  do
   sleep 5
   echo "."
  done

Si executem:

$ bash prova &
[1] 13452
kill -1 13452

Si que finalitzarà el procés per que li diem explícitament amb la comanda exit.

En canvi si utilitzem el senyal 9 en un script com el següent:

function accio9 {
 echo "Senyal 1 rebut (SIGHUP)"
 echo "Tanquem els fitxers si en tenim."
 exit
}
trap accio9 9
 while true
  do
   sleep 5
   echo "."
  done 

I executem

$ bash prova &
[1] 13455
kill -9 13455

Matarà el procés.

Exemple suïcida

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

int main( int argc, char∗ argv [ ] ) {
         printf( "Hola\n" ) ;
         pid_t my_pid = getpid ( ) ; / ∗ Obtinc el meu identificador de procés ∗ /
         kill(my_pid, SIGSTOP) ; / ∗ Em suicido ∗ /
         printf( "Segueixo existint?\n" ) ;
       } 

Podeu descarregar l'exemple aquí.

Exemple copsa-crtlc.c

#include <stdio.h>     /* biblioteca d'E/S estandard  */
#include <unistd.h>    /* biblioteca UNIX estandard   */
#include <signal.h>    /* biblioteca d'ús de senyals  */
/* gestor del senyal INT (Interrupció des del terminal)*/
void copsaINT(int sig_num) {
    signal(SIGINT, copsaINT);/* refem l'associació del senyal al gestor. 
                                Si no es fa, el següent cop que
                                es faci ctrl-c, no passarà per aquí  */
    printf("Ei! No facis això!!!\n");
    fflush(stdout);
}

int main(int argc, char* argv[]) {
    signal(SIGINT, copsaINT);/* Associació el senyal INT al gestor
                                copsa_int */ 
    while (1) {pause();}     /* Iteració de durada infinita */
}

Podeu descarregar l'exemple aquí

Exemple usa-alarmes.c

#include <stdio.h>  
#include <unistd.h> 
#include <signal.h> 
char usuari[40];               /* buffer per guardar el nom d'usuari */
void copsaAlarma(int sig_num) { /* definim un gestor pel senyal d'alarma. */
    printf("Temps esgotat. Sortint...\n\n");
    exit(0);
} 
int main(int argc, char* argv[]) {
    signal(SIGALRM, copsaAlarma);/* associa el gestor per senyals ALRM */
    printf("Nom usuari: ");      /* demanem l'usuari  */
    fflush(stdout);
    alarm(10);                   /* Comen   a una alarma de 10 segons */
    gets(usuari);                /* Obtenim usuari */
    alarm(0);                    /* Eliminem el timer */
    printf("Nom usuari: '%s'\n", usuari);
    return 0;
} 

Podeu descarregar l'exemple aquí

Exemple parlo

Fitxer parlo.c :

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> 

struct my_msgbuf {
    long mtype;
    char mtext[200];
};  

int main(void)
{
    struct my_msgbuf buf;
    int msqid;
    key_t key;  

    if ((key = ftok("recull", 'B')) == -1) {
        perror("ftok");
       exit(1);
    }

   if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1) {
       perror("msgget");
       exit(1);
   }
    
   printf("Entra linees de text, ^D per sortir:\n");

   buf.mtype = 1; /* no cal en aquest cas */
   fgets(buf.mtext,200,stdin);
   while( !feof(stdin)) {
       if (msgsnd(msqid, (struct msgbuf *)&buf, sizeof(buf), 0) == -1)
           perror("msgsnd");
           fgets(buf.mtext,200,stdin);
   }  

   if (msgctl(msqid, IPC_RMID, NULL) == -1) {
       perror("msgctl");
       exit(1);
   } 
    return 0;
}

Fitxer escolto.c:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> 

struct my_msgbuf {
    long mtype;
    char mtext[200];
};

int main(void) 
{
    struct my_msgbuf buf;
    int msqid;
    key_t key;   

   if ((key = ftok("recull", 'B')) == -1) {  
       perror("ftok");
       exit(1);
   }
   if ((msqid = msgget(key, 0644)) == -1) { /* connecta a la cua */
       perror("msgget");
       exit(1);
   }
   printf("escolto: preparat per rebre missatges, capità.\n");  

   while (true) { /* escolto mai s'atura! */
       if (msgrcv(msqid, (struct msgbuf *)&buf, sizeof(buf), 0, 0) == -1) {
           perror("msgrcv");
           exit(1);
       }
       printf("escolto: \"%s\"\n", buf.mtext);
   }
   return 0;
}  


Comunicació entre Processos

Funció fork

pid_t fork(void);
  • El procés fill és una còpia del pare amb els mateixos atributs: usuari, grup, entorn, directori de treball, taula de descriptors de fitxers (taula d’E/S).
  • El programa haurà de tenir el codi tant del pare com el del fill.
  • Inmediatament després del fork, els dos processos tindran la mateixa taula d’E/S.
Fork.png

ForkGraphic.png


Recursos:

Fork Bomb

Fork bomb és una tipus d'atac de denegació de serveis que permet saturar una màquina a base de crear il·limitats processos fills amb la comada fork. Veieu la comanda ulimit.

Funció dup

int dup(int oldfd);
int dup2(int oldfd, int newfd);

Duplica un descriptor de fitxer. Permet crear descriptors de fitxers a partir de descriptors ja existents. Exemple:

int main(int argc, char argv[]) {
int f1, f2, f3; ...
f1=open("fitxer1", O_RDONLY);
f2=open("fitxer2", O_RDONLY);
f3=dup(f1);

DupGraphic1.png

Recursos:


Pipes

  • Cues circulars (primer en entrar/primer en sortir).
  • Els processos han d’estar a la mateixa màquina.
  • Un procés crea un altre procés.
  • Utilitzat normalment per filtres.
SYNOPSIS
       #include <unistd.h>

       int pipe(int filedes[2]);

DESCRIPTION
      pipe()  creates  a pair of file descriptors, pointing to a pipe inode, and places them in the array pointed to by filedes.  filedes[0] is
      for reading, filedes[1] is for writing.

La crida pipe crea un vector amb dos descriptors de fitxer: un de lectura i un d'escriptura.


Recursos:

Cues de missatges System V

Funció msgctl

int msgctl(int msqid, int cmd, struct msqid_ds ∗buf);


Funció key_t ftok

key_t ftok(const char ∗pathname, int proj_id); 

Genera una clau a partir d’un nom de fitxer existent i un enter de 8 bits. Aquesta clau serveix com a identificador per elements del sistema V.

Funció msgget

int msgget(key_t key, int msgflg); 

Connecta a una cua existent (msgflg només conté les proteccions) o crea una cua (IPC_CREAT | proteccions). Retorna l’identificador de cua a usar.

Funció msgsnd

int msgsnd(int msqid, const void ∗msgp, size_t msgsz, int msgflg); 

Envia el missatge que hi ha a msgp a la cua msqid.

Funció ssize_t

ssize_t msgrcv(int msqid, void ∗msgp, size_t msgsz, long msgtyp, int msgflg); 

Elimina el primer missatge de cua msqid i el posa a msgp.

Semàfors

Funció sem_init

sem_init(sem_t ∗sem, int pshared, unsigned int value); 

Sem apunta a un semàform pshared indica si serà o no serà compartit amb altres processos i, value és el valor inicial del semàfor.

Funció sem_wait

sem_wait(sem_t ∗sem); 

Si sem és < 0, el procés que l’ha cridat es bloqueja fins que un altre procés cridi sem_post.

Funció sem_post

sem_post(sem_t ∗sem); 

Incrementa el semàfor i desperta, si n’hi ha, qualsevol procés que esperi el semàfor.

Funció sem_getvalue

sem_getvalue(sem_t ∗sem, int ∗valp); 

Valor del semàfor.

Funció sem_destroy

sem_destroy(sem_t ∗sem); Destrucció del semàfor

Exemples

filsuma

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>

#define NITER 1000000 

int comptador = 0; 

sem_t mutex; 

void * filSuma(void * a) {
  int i, tmp;
    for(i = 0; i < NITER; i++)
    {
        sem_wait (&mutex);
        tmp = comptador;  /* copia el comptador global a un de local */
        tmp = tmp+1;      /* incrementa la copia local */
        comptador = tmp;  /* guarda el valor local al comptador global*/ 
        sem_post (&mutex); 
    }
}

int main(int argc, char * argv[]) {
    pthread_t tid1, tid2;  

    sem_init(&mutex, 0, 1);

    if(pthread_create(&tid1, NULL, filSuma, NULL))
        {printf("\n ERROR creant fil 1"); exit(1);}
    if(pthread_create(&tid2, NULL, filSuma, NULL))
        {printf("\n ERROR creant fil 2"); exit(1);}  

    if(pthread_join(tid1, NULL))  /* espera finalitzacio del fil 1  */
        {printf("\n ERROR join fil 1");exit(1);}
    if(pthread_join(tid2, NULL))  /* espera finalitzacio del fil 1  */
        {printf("\n ERROR join fil 2"); exit(1);}  

    if (comptador < 2 * NITER) 
        printf("\nEI! el comptador es [%d], i hauria de ser %d\n", 
              comptador, 2*NITER);
    else printf("\n D'acord! el comptador es [%d]\n", comptador);
  
    pthread_exit(NULL);
}

Es pot compilar aquest codi amb:

$ gcc -o filsuma2 filsuma2.c -lpthread

Important utilitzar -lpthread per evitar els errors undefined reference:

filsuma2.c:(.text+0x29): undefined reference to `sem_init'

Exemple productors consumidors

semaphore fillCount = 0
semaphore emptyCount = BUFFER_SIZE

procedure producer() {
    while (true) {
        item = produceItem()
        down(emptyCount)
        putItemIntoBuffer(item)
        up(fillCount)
    }
 }

procedure consumer() {
    while (true) {
        down(fillCount)
        item = removeItemFromBuffer()
        up(emptyCount)
        consumeItem(item)
    }
}

Recursos:

Memòria compartida

Aquest mètode permet l'intercanvi de dades entre processos utilitzant un zona de memòria. La zona de memòria és independent de les zones de memòria de cada procés (per les raons de seguretat comentades anteriorment). Un procés crea la zona de memòria de forma que la reta de processos i puguin accedir.

És un mètode molt ràpid de comunicació (respecte a altres mètodes com les Pipes o els sockets). Una limitació clara és que els processos s'han d'executar a la mateixa màquina.

IPC per memòria compartida s'utilitza bàsicament en sistemes Unix o sistemes operatius que compleixen amb l'estàndard POSIX. POSIX proveïx d'una API anomenada POSIX Shared Memory:

Crida de sistema:

# include sys/mman.h
shm_open() 

Recursos:


Exemples

Exemple de fork

int main(int argc, char argv[]) {
 int idProc;
 ...
 idProc =fork(); /* Després de la crida hauran 2 processo                               
              que son el mateix programa amb l’estat de la crida*/
 if (idProc == -1) { /* El valor de retorn -1 és un error */ 
                                                                                                                                                                  
perror("Error al crear procés fill");
 } else if (idProc == 0) { /* El 0 indica que es tracta del procés fill */
  /* codi fill */
 } else if (idProc != 0) { /* qualsevol altre valor indica que es el procés pare */
  /* codi pare */
       ...
}


Exemple 1. Enllaçar un pare amb el seu fill mitjançant una Pipe

El següent programa:

#define  entradaStandard  0 
#define  sortidaStandard  1  

#define  entradaTaulaTub  0 
#define  sortidaTaulaTub  1 

int main( int argc, char* argv[] ) {
   int   tub[2];       /* taula de descriptors del tub o pipe */
   int   idProces;     /* identificaci� del proc�s fill       */
   char  *fargv[3];    /* arguments de les comandes a executar*/
   
   if (argc != 3) {printf( "Us: %s filter1 filter2\n", argv[0] ); exit(-1);}
   pipe( tub ); 
   idProces = fork();
   if ( idProces == 0 ) {
      close(sortidaStandard);     dup  ( tub[sortidaTaulaTub] );
      close(tub[entradaTaulaTub]); close(tub[sortidaTaulaTub] );
      fargv[0] = argv[1]; fargv[1] = 0; execve( argv[1], fargv, 0 );
      perror( "filtre 1 ha fallat" );
   }
   else  {
      close(entradaStandard);     dup  ( tub[entradaTaulaTub]  );
      close( tub[entradaTaulaTub]  ); close( tub[sortidaTaulaTub] );
      fargv[0] = argv[2]; fargv[1] = 0;  execve( argv[2], fargv, 0 );
      perror( "filtre 2 ha fallat" );
   }
}

Aquest programa emula una pipe (|). Per exemple si executeu:

$ ./tub /bin/ls /usr/bin/wc

Tindrà el mateix efecte que:

$ ls | wc

O per exemple:

$ ./tub /bin/ls /bin/more

serà idèntic a:

$ ls | more

Exemple 2. Ordenació per selecció

Exemple 3.

#define  entradaStandard  0 
#define  sortidaStandard  1 
#define  entradaTaulaTub  0 
#define  sortidaTaulaTub  1 
  
int main( int argc, char* argv[] ) {  

  int   tub[2];       /* taula de descriptors del tub o pipe */
  int   idProces;     /* identificació del procés fill       */
  char  *fargv[3];    /* arguments de les comandes a executar*/ 

  /* Pas 0:  assegurem que la comanda s'ha escrit correctament:
              Us: tub filtre1 filtre2 */ 

  if (argc != 3) {
     printf( "Us: %s filter1 filter2\n", argv[0] );
     exit(-1);
  }  

  /* taula E/S     0           1          2         3          4             
              +----------+----------+----------+----------+----------+
              |-> teclat |->pantalla|->pantalla|          |          |
              +----------+----------+----------+----------+----------+
                  stdin     stdout     stderr
                       +----+                   
              teclat-->|    |-->pantalla        
                       |pare|-->pantalla          
                       |    |                   
                       +----+                                          */  

  /* Pas 1:  crea un pipe */   

  pipe( tub );   

   /* taula E/S     0           1          2         3          4             
              +----------+----------+----------+----------+----------+
              |-> teclat |->pantalla|->pantalla|->ent. tub|->sor. tub|
              +----------+----------+----------+----------+----------+
                  stdin     stdout     stderr    tub[0]=3   tub[1]=4 
                       +----+                   
              teclat-->|    |-->pantalla        
                       |pare|-->pantalla          
                    +->|    |--+                
                    |  +----+  |
            tub[0]=3|  +----+  |tub[1]=4
                    +--|tub |<-+
                       +----+                                            */ 

  /* Pas 2:  bifurca un procés fill */ 
 
  idProces = fork();
  if ( idProces == 0 ) {
     /* es tracta del procés fill */
  /* taula E/S     0           1          2         3          4             
              +----------+----------+----------+----------+----------+
              |-> teclat |->pantalla|->pantalla|->ent. tub|->sor. tub|
              +----------+----------+----------+----------+----------+
                   stdin     stdout     stderr    tub[0]=3   tub[1]=4 
                       +----+                         +----+            
              teclat-->|    |-->pantalla     teclat-->|    |-->pantalla
                       |pare|-->pantalla              |fill|-->pantalla
                    +->|    |--+                   +->|    |--+
                    |  +----+  |                   |  +----+  |
                    |          +-------------+     |          |
                    +-------------+ +--------+-----+          |
                          tub[0]=3| |+----+  |tub[1]=4        |
              		           +-+|tub |<-+----------------+
                                    +----+                   */
     /* Pas 2a:  tanquem la sortida standard original, 
                 dupliquem a la taula d'E/S del procés
                 el descriptor de sortida del tub com
                 sortida standard. Tancant els descriptors
                 del tub, desapareixeran de la taula d'E/S
                 en les posicions 3 i 4.                   */

     close(sortidaStandard);

  /* taula E/S     0           1          2         3          4              

              +----------+----------+----------+----------+----------+
              |-> teclat |   ---    |->pantalla|->ent. tub|->sor. tub|
              +----------+----------+----------+----------+----------+
                  stdin     stdout     stderr    tub[0]=3   tub[1]=4 
                       +----+                         +----+            
              teclat-->|    |                teclat-->|    |
                       |pare|-->pantalla              |fill|-->pantalla
                    +->|    |--+                   +->|    |--+
                    |  +----+  |                   |  +----+  |
                    |          +-------------+     |          |
                    +-------------+ +--------+-----+          |
                          tub[0]=3| |+----+  |tub[1]=4        |
             		           +-+|tub |<-+----------------+
                                     +----+                   */
      dup  ( tub[sortidaTaulaTub] );
   /* taula E/S     0           1          2         3          4             
              +----------+----------+----------+----------+----------+
              |-> teclat |->sor. tub|->pantalla|->ent. tub|->sor. tub|
              +----------+----------+----------+----------+----------+
                  stdin     stdout     stderr    tub[0]=3   tub[1]=4 
                       +----+                         +----+            
              teclat-->|    |                teclat-->|    |->pantalla(stderr)
                       |pare|-->pantalla              |fill|--+(stdout)
                    +->|    |--+                   +->|    |--+
                    |  +----+  |                   |  +----+  |
                    |          +-------------+     |          |
                    +-------------+ +--------+-----+          |
                          tub[0]=3| |+----+  |tub[1]=4        |
            		           +-+|tub |<-+----------------+
                                     +----+                   */
     close(tub[entradaTaulaTub]);
     close(tub[sortidaTaulaTub] );
  /* taula E/S     0           1          2         3          4             
              +----------+----------+----------+----------+----------+
              |-> teclat |->sor. tub|->pantalla|   ---    |   ---    |
              +----------+----------+----------+----------+----------+
                  stdin     stdout     stderr    tub[0]=3   tub[1]=4 
                       +----+                         +----+            
              teclat-->|    |                teclat-->|    |->pantalla(stderr)
                       |pare|-->pantalla              |fill|--+(stdout)
                    +->|    |--+                      |    |  |
                    |  +----+  |                      +----+  |
                    |          +-------------+                |
                    +-------------+          |                |
                          tub[0]=3|  +----+  |tub[1]=4        |
           		           +-+|tub |<-+----------------+
                                     +----+                   */  
     /* Pas 2b:  ara solapem amb filtre 1 */
  

     fargv[0] = argv[1];
     fargv[1] = 0;
     execve( argv[1], fargv, 0 );
     perror( "filtre 1 ha fallat" );
  }
  else  {
     /* procés pare */
  /* taula E/S     0           1          2         3          4             
              +----------+----------+----------+----------+----------+
              |-> teclat |->sor. tub|->pantalla|->ent. tub|->sor. tub|
              +----------+----------+----------+----------+----------+
                  stdin     stdout     stderr    tub[0]=3   tub[1]=4 
                       +----+                         +----+            
             teclat-->|    |                teclat-->|    |->pantalla(stderr)
                       |pare|-->pantalla              |fill|--+(stdout)
                    +->|    |--+                      |    |  |
                    |  +----+  |                      +----+  |
                    |          +-------------+                |
                    +-------------+          |                |
                          tub[0]=3|  +----+  |tub[1]=4        |
            		           +-+|tub |<-+----------------+
                                     +----+                   */

     /* Pas 2c:  tanquem l'entrada standard original, 
                 dupliquem a la taula d'E/S del procés
                 el descriptor d'entrada del tub com
                 entrada standard. Tancant els descriptors
                 del tub, desapareixeran de la taula d'E/S
                 en les posicions 3 i 4.                   */ 

     close(entradaStandard);  

  /* taula E/S     0           1          2         3          4             
              +----------+----------+----------+----------+----------+
              |   ---    |->sor. tub|->pantalla|->ent. tub|->sor. tub|
              +----------+----------+----------+----------+----------+
                  stdin     stdout     stderr    tub[0]=3   tub[1]=4 
                       +----+                         +----+            
              teclat-->|    |                teclat-->|    |->pantalla(stderr)
                       |pare|-->pantalla              |fill|--+(stdout)
                    +->|    |--+                      |    |  |
                    |  +----+  |                      +----+  |
                    |          +-------------+                |
                    +-------------+          |                |
                          tub[0]=3|  +----+  |tub[1]=4        |
            		           +-+|tub |<-+----------------+
                                     +----+                   */
   dup  ( tub[entradaTaulaTub]  );  

  /* taula E/S     0           1          2         3          4             
              +----------+----------+----------+----------+----------+
              |->ent. tub|->sor. tub|->pantalla|->ent. tub|->sor. tub|
              +----------+----------+----------+----------+----------+
                  stdin     stdout     stderr    tub[0]=3   tub[1]=4 
                       +----+                         +----+            
             (stdin)+->|    |                teclat-->|    |->pantalla(stderr)
                    |  |pare|-->pantalla     (stdin)  |fill|--+(stdout)
                    +->|    |--+                      |    |  |
                    |  +----+  |                      +----+  |
                    |          +-------------+                |
                    +-------------+          |                |
                          tub[0]=3|  +----+  |tub[1]=4        |
            		           +-+|tub |<-+----------------+
                                     +----+                   */

     close( tub[entradaTaulaTub]  );
     close( tub[sortidaTaulaTub] );  

  /* taula E/S     0           1          2         3          4             
              +----------+----------+----------+----------+----------+
              |->ent. tub|->sor. tub|->pantalla|    ---   |   ---    |
              +----------+----------+----------+----------+----------+
                  stdin     stdout     stderr    tub[0]=3   tub[1]=4 
                       +----+                         +----+            
             (stdin)+->|    |                teclat-->|    |->pantalla(stderr)
                    |  |pare|-->pantalla     (stdin)  |fill|--+(stdout)
                    |  |    |                         |    |  |
                    |  +----+                         +----+  |
                    |                +----+                   |
            	     +----------------|tub |<-+----------------+
                                     +----+                   */  
  

    /* Pas 2d:  ara solapem amb filtre 2 */
    
     fargv[0] = argv[2];
     fargv[1] = 0;  

     execve( argv[2], fargv, 0 );
     perror( "filtre 2 ha fallat" );
  }
}

Exemple de semàfors

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
 
#define NITER 1000000  

int comptador = 0;
sem_t mutex;  

void * filSuma(void * a) {
  int i, tmp;
    for(i = 0; i < NITER; i++)
     {
        tmp = comptador;  /* copia el comptador global a un de local */
        tmp = tmp+1;      /* incrementa la copia local */
        comptador = tmp;  /* guarda el valor local al comptador global*/ 
    }
}

int main(int argc, char * argv[]) {
    pthread_t tid1, tid2;   

    sem_init(&mutex, 0, 1);
    if(pthread_create(&tid1, NULL, filSuma, NULL))
        {printf("\n ERROR creant fil 1"); exit(1);}
    if(pthread_create(&tid2, NULL, filSuma, NULL))
        {printf("\n ERROR creant fil 2"); exit(1);}
    if(pthread_join(tid1, NULL))  /* espera finalitzacio del fil 1  */
        {printf("\n ERROR join fil 1");exit(1);}
    if(pthread_join(tid2, NULL))  /* espera finalitzacio del fil 1  */
        {printf("\n ERROR join fil 2"); exit(1);}
    if (comptador < 2 * NITER) 
        printf("\nEI! el comptador es [%d], i hauria de ser %d\n", 
              comptador, 2*NITER);
    else printf("\n D'acord! el comptador es [%d]\n", comptador);
    pthread_exit(NULL);
}

Execució de programes. Exec

Consulteu Execució_de_comandes_i_aplicacions_en_C.

Implementació de comandes de shell amb crides de sistema

Consulteu Implementació de comandes de shell amb crides de sistema.

Manuals (man)

En el cas que no trobem alguna crida al sistema en el manual haurem d'instal·lar els següents paquets:

$ sudo apt-get install manpages-dev

També pot ser útil disposar dels manuals en castellà:

$ sudo apt-get install manpages-es

Atenció: No tots els manuals estan tradüits. A més si esteu treballant en català i voleu veure els manuals en castellà, heu d'afegir el següent al fitxer .bashrc de la vostre HOME:

alias man='man -L es'

O simplement recordar-vos de posar els paràmetres -L es després de la comanda man.

En tot cas si encara i així no trobem alguna crida al sistema o comanda a man podem seguir el següent procés per mirar de veure quin paquet ens falta. Primer anem a la carpeta on es troben els manuals:

$ cd /usr/share/man

Si us fixeu en aquesta carpeta hi ha una carpeta per cada secció de man (man1, man2, man3 ,etc). Com ja hem comentat les crides a sistema es troben al nivell 2:

$ cd man2

Imagineu que volem veure si tenim el manual de open. Executaríem:

$ ls -la | grep open 
lrwxrwxrwx   1 root root    9 2005-07-20 20:47 creat.2.gz -> open.2.gz
-rw-r--r--   1 root root 5588 2004-11-02 10:43 open.2.gz 

Vom podeu veure el fitxer open.gz ens proporciona el manual. Per tant per saber quin paquet ens proporciona aquest fitxerr podem executar:

$ dpkg -S open.2.gz 
manpages-es: /usr/share/man/es/man2/open.2.gz
manpages-dev: /usr/share/man/man2/open.2.gz

Com podeu veure els paquet que proporciona aquest fitxer és manpages-dev.

Recursos:

Enllaços externs