Modelo:Creación e Xestión de Procesos en Linux: Diferenzas entre revisións

De Wiki do Ciclo ASIR do IES de Rodeira
Saltar á navegación Saltar á procura
(Nova páxina: "== Conceptos Xerais. == O Linux é un sistema operativo multitarefa, e como tal proporciona ás linguaxes de programación unha interface que permite a creación e o control de m...")
 
Sen resumo de edición
 
Liña 25: Liña 25:
E posible reasignar os descritores de xeito que referencien dispositivos ou ficheiros distintos da pantalla ou teclado, para facer esto pódese empregar a función:
E posible reasignar os descritores de xeito que referencien dispositivos ou ficheiros distintos da pantalla ou teclado, para facer esto pódese empregar a función:


<source lang='C'>
<c>
int dup(int oldfd);
int dup(int oldfd);


</c>
</source>


Esta función duplica o descritor indicado por '''oldfd''' na primeira entrada da táboa de descritores libre, ou sexa que si pechamos stdout:
Esta función duplica o descritor indicado por '''oldfd''' na primeira entrada da táboa de descritores libre, ou sexa que si pechamos stdout:


<source lang='C'>
<c>
// STDOUT_FILENO é unha constante
// STDOUT_FILENO é unha constante
// definida en unistd.h que indica o descritor da saída estándar
// definida en unistd.h que indica o descritor da saída estándar
Liña 42: Liña 42:
// Agora todo o que sería enviado á pantalla a través de stdout iría
// Agora todo o que sería enviado á pantalla a través de stdout iría
// ó ficheiro representado por '''descritor'''.
// ó ficheiro representado por '''descritor'''.
</c>
</source>


Como xa se comentou, cando un proceso crea un fillo, o fillo hereda unha copia da táboa de descritores do pai poidendo manipular os mesmos obxectos.
Como xa se comentou, cando un proceso crea un fillo, o fillo hereda unha copia da táboa de descritores do pai poidendo manipular os mesmos obxectos.
Liña 50: Liña 50:
As principais funcións de creación e xestion de procesos son as seguintes:
As principais funcións de creación e xestion de procesos son as seguintes:


<source lang='C'>
<c>
#include <stdlib.h>
#include <stdlib.h>


int system(const char *mandato);
int system(const char *mandato);


</c>
</source>


Executa a orde especificada chamando a /bin/sh (ó interprete de comandos). Unha vez executado o comando a execución do proceso continúa. Un exemplo é un borrado de pantalla, que pode facerse como: '''system("clear")'''
Executa a orde especificada chamando a /bin/sh (ó interprete de comandos). Unha vez executado o comando a execución do proceso continúa. Un exemplo é un borrado de pantalla, que pode facerse como: '''system("clear")'''


<source lang='C'>
<c>
#include <unistd.h>
#include <unistd.h>


Liña 69: Liña 69:
int execve (const char *filename, char *const argv[], char *const envp[]);
int execve (const char *filename, char *const argv[], char *const envp[]);


</c>
</source>


As funcións da familia ''exec'' sirven para executar un programa dende un proceso. O programa executado reemplazará ó proceso actual e si funciona correctamente non retornarán ningún valor.
As funcións da familia ''exec'' sirven para executar un programa dende un proceso. O programa executado reemplazará ó proceso actual e si funciona correctamente non retornarán ningún valor.


<source lang='C'>
<c>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/wait.h>
Liña 84: Liña 84:
pid_t getppid (void);
pid_t getppid (void);


</c>
</source>


'''fork''' crea unha copia exacta do proceso en execución, herdando os descritores abertos. No proceso actual chamado proceso '''''pai''''' devolve o ''PID'' do novo proceso creado. E no novo proceso creado chamado '''''fillo''''' devolve un 0. En caso de erro se devolve -1.
'''fork''' crea unha copia exacta do proceso en execución, herdando os descritores abertos. No proceso actual chamado proceso '''''pai''''' devolve o ''PID'' do novo proceso creado. E no novo proceso creado chamado '''''fillo''''' devolve un 0. En caso de erro se devolve -1.
Liña 93: Liña 93:


== Envío e Xestión de Sinais ==
== Envío e Xestión de Sinais ==
<source lang='C'>
<c>
#include <sys/types.h>
#include <sys/types.h>
#include <signal.h>
#include <signal.h>
Liña 99: Liña 99:
int kill(pid_t pid, int sig);
int kill(pid_t pid, int sig);


</c>
</source>


<source lang='C'>
<c>
#include <signal.h>
#include <signal.h>


Liña 112: Liña 112:
int sigsuspend(const sigset_t *mask);
int sigsuspend(const sigset_t *mask);


</c>
</source>
=== O Timer do Sistema ===
=== O Timer do Sistema ===
<source lang='C'>
<c>
#include <sys/time.h>
#include <sys/time.h>


Liña 130: Liña 130:
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);


</c>
</source>


== Comunicación de Procesos con Tuberías (''Pipes'') ==
== Comunicación de Procesos con Tuberías (''Pipes'') ==
=== Named Pipes (''FIFOS'') ===
=== Named Pipes (''FIFOS'') ===
<source lang='C'>
<c>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stat.h>
Liña 140: Liña 140:
int mkfifo(const char *path, mode_t mode)
int mkfifo(const char *path, mode_t mode)
</c>
</source>


<source lang='C'>
<c>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stat.h>
Liña 150: Liña 150:
int mknod(const char *pathname, mode_t mode, dev_t dev);
int mknod(const char *pathname, mode_t mode, dev_t dev);


</c>
</source>


=== Unnamed Pipes ===
=== Unnamed Pipes ===
<source lang='C'>
<c>
#include <unistd.h>
#include <unistd.h>


int pipe(int descf[2]);
int pipe(int descf[2]);


</c>
</source>


== Comunicación de Procesos IPC System V ==
== Comunicación de Procesos IPC System V ==
Liña 164: Liña 164:
Os mecanismos para comunicar procesos '''que se están a executar no mesmo ordenador''' son dous: A '''''memoria compartida''''' e as '''''colas de mensaxes'''''. Para utilizar calquera dos dous mecanismos é necesario obter en primeiro lugar un identificador único (chave IPC) que se utilizará para nomear a comunicación que se está a crear mediante a función:
Os mecanismos para comunicar procesos '''que se están a executar no mesmo ordenador''' son dous: A '''''memoria compartida''''' e as '''''colas de mensaxes'''''. Para utilizar calquera dos dous mecanismos é necesario obter en primeiro lugar un identificador único (chave IPC) que se utilizará para nomear a comunicación que se está a crear mediante a función:


<source lang='C'>
<c>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ipc.h>


key_t ftok(char *camino,char proy);
key_t ftok(char *camino,char proy);
</c>
</source>


Esta función recibe como parámetros o camiño a un ficheiro sobre o que os procesos a comunicar deben ter permiso ('''camino''') e un byte ('''proy''') para que se poda utilizar o mesmo camiño para crear identificadores distintos. O sistema crea o identificador combinando o ficheiro do camiño indicado co byte indicado en '''''proy''''' e devolve unha chave de comunicación System V. Todos os procesos que se queiran comunicar deben chamar a esta función cos mesmos argumentos. En caso de producirse un erro, devolve -1 colocando o código de erro na variable '''errno'''.
Esta función recibe como parámetros o camiño a un ficheiro sobre o que os procesos a comunicar deben ter permiso ('''camino''') e un byte ('''proy''') para que se poda utilizar o mesmo camiño para crear identificadores distintos. O sistema crea o identificador combinando o ficheiro do camiño indicado co byte indicado en '''''proy''''' e devolve unha chave de comunicación System V. Todos os procesos que se queiran comunicar deben chamar a esta función cos mesmos argumentos. En caso de producirse un erro, devolve -1 colocando o código de erro na variable '''errno'''.
Liña 186: Liña 186:
: Chamando á función:
: Chamando á función:


<source lang='C'>
<c>
#include <sys/ipc.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/shm.h>
Liña 192: Liña 192:
int shmget(key_t key, int size, int shmflg);
int shmget(key_t key, int size, int shmflg);


</c>
</source>


: Esta función recibe como parámetros a chave de comunicación ('''key'''), o tamaño desexado en bytes ('''size''') e os atributos da memoria que se vai a crear ('''shmflg''') e devolve un identificador da área de memoria compartida creada. Si se produce un erro devolve -1 e almacena o código de error en '''errno'''.
: Esta función recibe como parámetros a chave de comunicación ('''key'''), o tamaño desexado en bytes ('''size''') e os atributos da memoria que se vai a crear ('''shmflg''') e devolve un identificador da área de memoria compartida creada. Si se produce un erro devolve -1 e almacena o código de error en '''errno'''.
Liña 217: Liña 217:
: E necesario mapear a memoria compartida creada no espacio de direccións de memoria do proceso, para poder acceder a ela. Unha vez mapeada é posible acceder a ela para leer ou escribir mediante un punteiro. A función necesaria para facer esto é :
: E necesario mapear a memoria compartida creada no espacio de direccións de memoria do proceso, para poder acceder a ela. Unha vez mapeada é posible acceder a ela para leer ou escribir mediante un punteiro. A función necesaria para facer esto é :


<source lang='C'>
<c>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ipc.h>
Liña 224: Liña 224:
char *shmat(int shmid,char *shmaddr,int shmflg);
char *shmat(int shmid,char *shmaddr,int shmflg);


</c>
</source>


: shmat 'pega' o segmento de memoria compartida identificado por '''shmid''' nunha dirección de memoria pertencente ó proceso actual. Si '''shmaddr''' é 0, a dirección en que será situada a memoria compartida calcúlase automáticamente entre o rango que vai dende 1 a 1.5GB empezando por la dirección máis alta. Si o parámetro shmflg é SHM_RDONLY, únicamente se poderá leer do segmento de memoria compartida engadido. Devolve a dirección donde estará situado o segmento de memoria compartida, ou -1 si se produce un erro, poñendo o seu código en '''errno'''.
: shmat 'pega' o segmento de memoria compartida identificado por '''shmid''' nunha dirección de memoria pertencente ó proceso actual. Si '''shmaddr''' é 0, a dirección en que será situada a memoria compartida calcúlase automáticamente entre o rango que vai dende 1 a 1.5GB empezando por la dirección máis alta. Si o parámetro shmflg é SHM_RDONLY, únicamente se poderá leer do segmento de memoria compartida engadido. Devolve a dirección donde estará situado o segmento de memoria compartida, ou -1 si se produce un erro, poñendo o seu código en '''errno'''.
Liña 236: Liña 236:
: Deste xeito a memoria compartida deixa de formar parte do espacio de direccións de memoria do proceso. Para facer esto utilízase a función:
: Deste xeito a memoria compartida deixa de formar parte do espacio de direccións de memoria do proceso. Para facer esto utilízase a función:


<source lang='C'>
<c>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ipc.h>
Liña 243: Liña 243:
int shmdt(char *shmaddr);
int shmdt(char *shmaddr);


</c>
</source>


: shmdt 'despega' un segmento de memoria compartida situado na dirección '''shmaddr'''. Se non se consigue devólvese -1 poñendo o código de erro en '''errno''', no caso contrario devolve 0.
: shmdt 'despega' un segmento de memoria compartida situado na dirección '''shmaddr'''. Se non se consigue devólvese -1 poñendo o código de erro en '''errno''', no caso contrario devolve 0.
Liña 251: Liña 251:
: En realidade o único que se fai é marcar a memoria como liberada, liberándose únicamente cando xa non exista ningún proceso que teña a memoria en uso.
: En realidade o único que se fai é marcar a memoria como liberada, liberándose únicamente cando xa non exista ningún proceso que teña a memoria en uso.


<source lang='C'>
<c>
#include <sys/ipc.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/shm.h>
Liña 257: Liña 257:
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
int shmctl(int shmid,int cmd,struct shmid_ds *buf);


</c>
</source>


: Permite realizar operacións sobre a memoria compartida identificada por shmid. As operacións son:
: Permite realizar operacións sobre a memoria compartida identificada por shmid. As operacións son:
Liña 269: Liña 269:
: O formato de buf es el siguiente:
: O formato de buf es el siguiente:


<source lang='C'>
<c>
struct shmid_ds {
struct shmid_ds {
struct ipc_perm shm_perm; // permisos sobre la memoria compartida
struct ipc_perm shm_perm; // permisos sobre la memoria compartida
Liña 295: Liña 295:
};
};


</c>
</source>


=== Colas de Mensaxes ===
=== Colas de Mensaxes ===
Liña 302: Liña 302:
Para crear unha cola de menxaxes, do mesmo xeito que na memoria compartida, é necesario obter en primeiro lugar un identificador IPC coa función '''ftok''' vista no apartado anterior. O resto de funcións de interese cítanse a continuación:
Para crear unha cola de menxaxes, do mesmo xeito que na memoria compartida, é necesario obter en primeiro lugar un identificador IPC coa función '''ftok''' vista no apartado anterior. O resto de funcións de interese cítanse a continuación:


<source lang='C'>
<c>
# include <sys/types.h>
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/ipc.h>
Liña 309: Liña 309:
int msgget(key_t key,int msgflg);
int msgget(key_t key,int msgflg);


</c>
</source>


:Crea unha cola de mensaxes e devolve o identificador da cola de mensaxes asociada a ''key''. O parámetro msgflg é similar á función ''shmget''. Devolve -1 no caso de erro e almacena o código de erro en '''errno'''.
:Crea unha cola de mensaxes e devolve o identificador da cola de mensaxes asociada a ''key''. O parámetro msgflg é similar á función ''shmget''. Devolve -1 no caso de erro e almacena o código de erro en '''errno'''.


<source lang='C'>
<c>
# include <sys/types.h>
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/ipc.h>
Liña 320: Liña 320:
int msgctl(int msgid,int cmd,struct msqid_ds *buf);
int msgctl(int msgid,int cmd,struct msqid_ds *buf);


</c>
</source>


:Esta función é similar a shmctl. Os únicos campos que poden ser modificados con IPC_SET son ''msg_perm.uid, msg_perm.gid, msg_perm.mode e msg_qbytes''. O formato de msqid_ds é o seguinte.
:Esta función é similar a shmctl. Os únicos campos que poden ser modificados con IPC_SET son ''msg_perm.uid, msg_perm.gid, msg_perm.mode e msg_qbytes''. O formato de msqid_ds é o seguinte.
<source lang='C'>
<c>
/* one msqid structure for each queue on the system */
/* one msqid structure for each queue on the system */
struct msqid_ds {
struct msqid_ds {
Liña 340: Liña 340:
ushort msg_lrpid; /* last receive pid */
ushort msg_lrpid; /* last receive pid */
};
};
</c>
</source>


As funcións para ler mensaxes da cola e para poñer mensaxes na cola son as seguintes:
As funcións para ler mensaxes da cola e para poñer mensaxes na cola son as seguintes:


<source lang='C'>
<c>
# include <sys/types.h>
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/ipc.h>
Liña 352: Liña 352:
int msgrcv(int msgid, struct msgbuf *msgp, int msgsz,int msgtyp, int msgflg);
int msgrcv(int msgid, struct msgbuf *msgp, int msgsz,int msgtyp, int msgflg);


</c>
</source>


:msgsnd pon unha mensaxe contida en msgp cun tamano msgsz na cola de mensaxes identificada por msgid, e msgrcv lé e quita da cola de mensaxes a mensaxe de tipo msgtype copiándoo en msgp.
:msgsnd pon unha mensaxe contida en msgp cun tamano msgsz na cola de mensaxes identificada por msgid, e msgrcv lé e quita da cola de mensaxes a mensaxe de tipo msgtype copiándoo en msgp.


<source lang='C'>
<c>
struct msgbuf {
struct msgbuf {


Liña 363: Liña 363:
}
}


</c>
</source>


:O campo ''mtype'' da estructura identifica o tipo de mensaxe que se está a enviar. Esto é importante, xa que cando se reciba a mensaxe coa función ''msgrcv'' se especificará no parámetro ''msgtyp'' o tipo de mensaxe que se quere ler do seguinte xeito:
:O campo ''mtype'' da estructura identifica o tipo de mensaxe que se está a enviar. Esto é importante, xa que cando se reciba a mensaxe coa función ''msgrcv'' se especificará no parámetro ''msgtyp'' o tipo de mensaxe que se quere ler do seguinte xeito:
Liña 381: Liña 381:
Os semáforos sirven para o control do acceso a recursos compartidos entre moitos procesos. Os semáforos proporcionados polos mecanismos IPC System V se manexan coas seguintes funcións:
Os semáforos sirven para o control do acceso a recursos compartidos entre moitos procesos. Os semáforos proporcionados polos mecanismos IPC System V se manexan coas seguintes funcións:


<source lang='C'>
<c>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ipc.h>
Liña 388: Liña 388:
int semget(key_t key, int nsems, int semflg)
int semget(key_t key, int nsems, int semflg)


</c>
</source>


Esta función crea un conxunto de ''nsems'' semáforos. Os flags (''semflg'') son similares ós flags dos outros mecanismos IPC System V (memoria compartida e colas de mensaxes). Devolve -1 en caso de erro.
Esta función crea un conxunto de ''nsems'' semáforos. Os flags (''semflg'') son similares ós flags dos outros mecanismos IPC System V (memoria compartida e colas de mensaxes). Devolve -1 en caso de erro.
Os semáforos creados estarán sen inicializar, e será preciso facelo mediante a función '''semctl''' e as operacións ''SETALL'' ou ''SETVAL'' si é oportuno.
Os semáforos creados estarán sen inicializar, e será preciso facelo mediante a función '''semctl''' e as operacións ''SETALL'' ou ''SETVAL'' si é oportuno.
<source lang='C'>
<c>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ipc.h>
Liña 409: Liña 409:
};
};


</c>
</source>
A función ''semop'' permite operar cun conxunto de semáforos. As operacións indícanse nunha táboa de estructuras de tipo ''struct sembuf'', que conteñen o número de semáforo do conxunto co que se vai a operar (''sem_num''), a operación a realizar sobre o semáforo (''sem_op'') e unha serie de indicadores (''sem_flg'').
A función ''semop'' permite operar cun conxunto de semáforos. As operacións indícanse nunha táboa de estructuras de tipo ''struct sembuf'', que conteñen o número de semáforo do conxunto co que se vai a operar (''sem_num''), a operación a realizar sobre o semáforo (''sem_op'') e unha serie de indicadores (''sem_flg'').


Liña 423: Liña 423:
'''''semtimedop''''' é igual que semop, pero permite especificar un tempo máximo de espera, tras o que a función voltaría un código de erro.
'''''semtimedop''''' é igual que semop, pero permite especificar un tempo máximo de espera, tras o que a función voltaría un código de erro.


<source lang='C'>
<c>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ipc.h>
Liña 437: Liña 437:
int semctl(int semid, int semnum, int cmd, union semun arg);
int semctl(int semid, int semnum, int cmd, union semun arg);


</c>
</source>
A función '''semctl''' sirve para controlar o semáforo realizando operacións como a eliminación do semáforo ('''IPC_RMID''') ou a ''inicialización do semáforo'' ('''SETALLL''', '''SETVAL''').
A función '''semctl''' sirve para controlar o semáforo realizando operacións como a eliminación do semáforo ('''IPC_RMID''') ou a ''inicialización do semáforo'' ('''SETALLL''', '''SETVAL''').



Revisión actual feita o 6 de agosto de 2014 ás 13:30

Conceptos Xerais.

O Linux é un sistema operativo multitarefa, e como tal proporciona ás linguaxes de programación unha interface que permite a creación e o control de múltiples procesos. Un proceso é unha instancia dun programa en execución.

Nun instante determiñado hai moitos procesos executándose á vez. Un programa en execución pode crear un novo proceso, nese caso, o proceso resultante recibe o nome de fillo mentras que o proceso creador chámase pai.

Para optimizar o rendimento do sistema, os procesos créanse seguindo un esquema de creación en escritura, que consiste en crear a copia da páxina á que se accede únicamente cando se modifica o seu contido. Deste xeito o sistema traballa cunha única copia das páxinas de memoria que non cambian e aforra todo o proceso de duplicación no momento da creación do novo proceso.

O sistema Linux ten unha estructura de procesos xerárquica na que todos os procesos descenden do proceso init que é o primeiro que lanza o sistema. Todos os procesos descenden de init. Cando lanzamos un proceso dende a liña de comandos, ese proceso será fillo do intérprete que utilicemos, normalmente o Bash.

O sistema identifica os procesos cun número que recibe o nome de PID (Process IDentification), tendo cada proceso en execución no sistema un PID único. As funcións proporcionadas polo sistema pra crear e controlar os procesos tamén traballarán cos números de proceso (PID), non co seu nome.

Os procesos, identificados polo seu PID, teñen a capacidade de comunicarse con outros procesos e co exterior mediante ordes de entrada/saída que permiten acceder a ficheiros e dispositivos ou mediante operacións de comunicación de procesos (IPC).

En todos os casos, o elemento clave da comunicación é o descritor do obxecto de comunicación como poden ser ficheiros, pipes, sockets ... Cando un proceso precisa comunicarse utiliza unha chamada o sistema para crear un obxecto de comunicación, ou si xa existe para abrilo. Estas chamadas proporcionarán un descritor que servirá para referenciar a estructura de datos necesaria pra acceder ó dispositivo.

Cada proceso ten unha táboa cos descritores dos obxectos que pode manipular, sendo os descritores o índice que sinala a posición dos datos do obxecto na táboa de descritores (e dicir, un número enteiro). A manipulación dos obxectos de comunicación mediante chamadas o sistema consistirá en:

  • Apertura ou creación do obxecto de comunicación pra obter o descritor.
  • Realización de operacións de lectura ou escritura no obxecto mediante o descritor.
  • Obtención de información do obxecto ou modificación das súas características.
  • Peche do obxecto indicado polo descritor, liberando así os recursos ocupados.

Todos os procesos nos sistamas Unix teñen como mínimo tres descritores abertos: 0, que é o descritor do dispositivo de entrada estándar (stdin, normalmente o teclado), 1 ou saída estándar (stdout, normalmente a pantalla) e 2 que identifica o dispositivo de saída para informar dos erros (stderr, tamén a pantalla). E posible reasignar os descritores de xeito que referencien dispositivos ou ficheiros distintos da pantalla ou teclado, para facer esto pódese empregar a función:

  int dup(int oldfd);

Esta función duplica o descritor indicado por oldfd na primeira entrada da táboa de descritores libre, ou sexa que si pechamos stdout:

 // STDOUT_FILENO é unha constante
 // definida en unistd.h que indica o descritor da saída estándar
 close (STDOUT_FILENO);

 //logo duplicamos calqueira descritor....
 dup(descritor);

 // Agora todo o que sería enviado á pantalla a través de stdout iría 
 // ó ficheiro representado por '''descritor'''.

Como xa se comentou, cando un proceso crea un fillo, o fillo hereda unha copia da táboa de descritores do pai poidendo manipular os mesmos obxectos.

Creación e Xestión de Procesos.

As principais funcións de creación e xestion de procesos son as seguintes:

   #include <stdlib.h>

   int system(const char *mandato);

Executa a orde especificada chamando a /bin/sh (ó interprete de comandos). Unha vez executado o comando a execución do proceso continúa. Un exemplo é un borrado de pantalla, que pode facerse como: system("clear")

   #include <unistd.h>

   int execl (const char *path, const char *arg, ...);
   int execlp (const char *file, const char *arg, ...);
   int execle (const char *path, const char *arg, ..., char *const envp[]);
   int execv (const char *path, char *const argv[]);
   int execvp (const char *file, char *const argv[]);
   int execve (const char *filename, char *const argv[], char *const envp[]);

As funcións da familia exec sirven para executar un programa dende un proceso. O programa executado reemplazará ó proceso actual e si funciona correctamente non retornarán ningún valor.

   #include <sys/types.h>
   #include <sys/wait.h>

   #include <unistd.h>

   pid_t fork (void);
   pid_t wait (int *status);
   pid_t getpid (void);
   pid_t getppid (void);

fork crea unha copia exacta do proceso en execución, herdando os descritores abertos. No proceso actual chamado proceso pai devolve o PID do novo proceso creado. E no novo proceso creado chamado fillo devolve un 0. En caso de erro se devolve -1.

wait fai que o proceso espere a recibir unha sinal de finalización dun dos seus fillos, recibe como parámetro a dirección dun enteiro (status) donde se almacenará o valor devolto pola función main do proceso fillo. Os procesos que creen outros (pais) deben esperar a que rematen os fillos antes de finalizar a súa execución.

getpid devolve o PID do proceso actual e getppid devolve o PID do proceso pai do actual.

Envío e Xestión de Sinais

#include <sys/types.h>
#include <signal.h>
 
int kill(pid_t pid, int sig);
#include <signal.h>

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
                                                                          
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int sigpending(sigset_t *set);
int sigsuspend(const sigset_t *mask);

O Timer do Sistema

#include <sys/time.h>

struct itimerval {
  struct timeval it_interval; /* valor próximo */
  struct timeval it_value;    /* valor actual */
};

struct timeval {
  long tv_sec;                /* segundos */
  long tv_usec;               /* microsegundos */
};

int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);

Comunicación de Procesos con Tuberías (Pipes)

Named Pipes (FIFOS)

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

int mkfifo(const char *path, mode_t mode)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int mknod(const char *pathname, mode_t mode, dev_t dev);

Unnamed Pipes

#include <unistd.h>

int pipe(int descf[2]);

Comunicación de Procesos IPC System V

Os mecanismos para comunicar procesos que se están a executar no mesmo ordenador son dous: A memoria compartida e as colas de mensaxes. Para utilizar calquera dos dous mecanismos é necesario obter en primeiro lugar un identificador único (chave IPC) que se utilizará para nomear a comunicación que se está a crear mediante a función:

#include <sys/types.h>
#include <sys/ipc.h>

key_t  ftok(char *camino,char proy);

Esta función recibe como parámetros o camiño a un ficheiro sobre o que os procesos a comunicar deben ter permiso (camino) e un byte (proy) para que se poda utilizar o mesmo camiño para crear identificadores distintos. O sistema crea o identificador combinando o ficheiro do camiño indicado co byte indicado en proy e devolve unha chave de comunicación System V. Todos os procesos que se queiran comunicar deben chamar a esta función cos mesmos argumentos. En caso de producirse un erro, devolve -1 colocando o código de erro na variable errno.

Memoria Compartida

A memoria compartida consiste en crear un espacio na memoria que pode ser utilizado de xeito simultáneo por varios procesos. Para que un proceso poda utilizar memoria compartida son necesarios os seguintes pasos:

1. Creación da chave de comunicación IPC

Chamando á función ftok como se explicou no apartado anterior.

2. Creación da área de memoria compartida

Chamando á función:
#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, int size, int shmflg);
Esta función recibe como parámetros a chave de comunicación (key), o tamaño desexado en bytes (size) e os atributos da memoria que se vai a crear (shmflg) e devolve un identificador da área de memoria compartida creada. Si se produce un erro devolve -1 e almacena o código de error en errno.
O tamaño reservado realmente será sempre un múltiplo do tamaño de páxina do sistema (nos compatibles i386, 4K), e os atributos poden ser unha combinación dos seguintes:
  • IPC_CREAT : Para crear o segmento de memoria.
  • IPC_EXCL : Si cando intentamos crear o segmento de memoria este xa existe, saír con un erro.
  • Permisos : permisos para o usuario, grupo e resto de usuarios sobre a memoria creada.
A combinación dos atributos faise mediante un 'or', por exemplo: IPC_CREAT|0640
Despois de chamar a:
fork() - Herédanse os segmentos de memoria compartida.
exec() - 'desenganchase' a memoria compartida (non se hereda).
exit() - 'desenganchase' a memoria.


3. 'Enganchar' a memoria creada ó espacio de direccións de memoria do proceso

E necesario mapear a memoria compartida creada no espacio de direccións de memoria do proceso, para poder acceder a ela. Unha vez mapeada é posible acceder a ela para leer ou escribir mediante un punteiro. A función necesaria para facer esto é :
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

char *shmat(int shmid,char *shmaddr,int shmflg);
shmat 'pega' o segmento de memoria compartida identificado por shmid nunha dirección de memoria pertencente ó proceso actual. Si shmaddr é 0, a dirección en que será situada a memoria compartida calcúlase automáticamente entre o rango que vai dende 1 a 1.5GB empezando por la dirección máis alta. Si o parámetro shmflg é SHM_RDONLY, únicamente se poderá leer do segmento de memoria compartida engadido. Devolve a dirección donde estará situado o segmento de memoria compartida, ou -1 si se produce un erro, poñendo o seu código en errno.

4. Uso da memoria compartida.

Unha vez que temos a dirección de memoria donde está "enganchada" a memoria compartida é posible almacenar información nela ou leer a información que xa ten. Cando xa non necesitemos a memoria compartida, teremos que liberala para o que seguiremos os pasos 5 e 6.

5. 'Desenganchar' a memoria compartida

Deste xeito a memoria compartida deixa de formar parte do espacio de direccións de memoria do proceso. Para facer esto utilízase a función:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmdt(char *shmaddr);
shmdt 'despega' un segmento de memoria compartida situado na dirección shmaddr. Se non se consigue devólvese -1 poñendo o código de erro en errno, no caso contrario devolve 0.

6. Liberar a memoria compartida

En realidade o único que se fai é marcar a memoria como liberada, liberándose únicamente cando xa non exista ningún proceso que teña a memoria en uso.
#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid,int cmd,struct shmid_ds *buf);
Permite realizar operacións sobre a memoria compartida identificada por shmid. As operacións son:
  • IPC_STAT : Devolve información sobre a memoria compartida no buffer buf.
  • IPC_SET : Aplica os atributos situados en buf á memoria compartida. Únicamente pódense cambiar os atributos de uid, gid e os permisos de acceso.
  • IPC_RMID :Marca o segmento de memoria compartida para ser eliminado. O segmento será eliminado cando ningún proceso o teña 'pegado'.
En caso de éxito devolve 0, e se non -1 poñendo en errno o código de erro.
O formato de buf es el siguiente:
  struct shmid_ds {
    struct  ipc_perm shm_perm;	  // permisos sobre la memoria compartida
    int 	     shm_segsz;	  // tamaño del segmento en bytes
    time_t           shm_atime;	  // hora de la última union
    time_t           shm_dtime;	  // hora de la última separación
    time_t           shm_ctime;	  // hora del último cambio
    unsigned short   shm_cpid;	  // pid del proceso que creó el segmento
    unsigned short   shm_lpid;	  // pid del último proceso que usó el segmento
    short            shm_nattch;  // número de procesos utilizando el segmento
    unsigned short   shm_npages;  // tamaño del segmento en páginas
    unsigned long   *shm_pages;
    struct shm_desc *attaches;
  };

  struct   ipc_perm
  {
    key_t	key;
    ushort 	uid;	// UID y GID del dueño
    ushort	gid;
    ushort	cuid;	// UID y GID del creador
    ushort	cgid;
    ushort 	mode;	// Permisos de acceso
    ushort	seq;
  };

Colas de Mensaxes

As colas de mensaxes son un mecanismo de comunicación no que dous procesos poden comunicarse introducindo mensaxes nunha cola (FIFO, First Input First Output). Nesta cola poderán poñerse e quitarse mensaxes de distintos tipos.

Para crear unha cola de menxaxes, do mesmo xeito que na memoria compartida, é necesario obter en primeiro lugar un identificador IPC coa función ftok vista no apartado anterior. O resto de funcións de interese cítanse a continuación:

# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg.h>

int msgget(key_t key,int msgflg);
Crea unha cola de mensaxes e devolve o identificador da cola de mensaxes asociada a key. O parámetro msgflg é similar á función shmget. Devolve -1 no caso de erro e almacena o código de erro en errno.
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg.h>

int msgctl(int msgid,int cmd,struct msqid_ds *buf);
Esta función é similar a shmctl. Os únicos campos que poden ser modificados con IPC_SET son msg_perm.uid, msg_perm.gid, msg_perm.mode e msg_qbytes. O formato de msqid_ds é o seguinte.
/* one msqid structure for each queue on the system */
struct msqid_ds {
    struct ipc_perm msg_perm;
    struct msg *msg_first;  /* first message on queue */
    struct msg *msg_last;   /* last message in queue */
    time_t msg_stime;       /* last msgsnd time */
    time_t msg_rtime;       /* last msgrcv time */
    time_t msg_ctime;       /* last change time */
    struct wait_queue *wwait;
    struct wait_queue *rwait;
    ushort msg_cbytes;    
    ushort msg_qnum;     
    ushort msg_qbytes;      /* max number of bytes on queue */
    ushort msg_lspid;       /* pid of last msgsnd */
    ushort msg_lrpid;       /* last receive pid */
};

As funcións para ler mensaxes da cola e para poñer mensaxes na cola son as seguintes:

# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg.h>

int msgsnd(int msgid, struct msgbuf *msgp,int msgsz, int msgflg); 
int msgrcv(int msgid, struct msgbuf *msgp, int msgsz,int msgtyp, int msgflg);
msgsnd pon unha mensaxe contida en msgp cun tamano msgsz na cola de mensaxes identificada por msgid, e msgrcv lé e quita da cola de mensaxes a mensaxe de tipo msgtype copiándoo en msgp.
struct msgbuf {

 	long 	mtype;		// Tipo de mensaxe, debe ser maior que 0
 	char 	mtext[1]	// Información (dirección de la información)
}
O campo mtype da estructura identifica o tipo de mensaxe que se está a enviar. Esto é importante, xa que cando se reciba a mensaxe coa función msgrcv se especificará no parámetro msgtyp o tipo de mensaxe que se quere ler do seguinte xeito:
  • En msgtyp 0: Se lé a primeira mensaxe da cola.
  • En msgtyp un valor > 0: Se lé a primeira mensaxe de tipo msgtyp.
  • En msgtyp un valor < 0: Se lé a primeira mensaxe cun tipo <= ó valor absoluto de msgtyp.
msgflg pode ter os seguintes valores:
IPC_NOWAIT O recibir unha mensaxe, se non hai ningún dispoñible devolve o erro ENOMSG. O enviar unha mensaxe, si non cabe na cola devolve EAGAIN. Se non especificamos IPC_NOWAIT, as funcións de envío e recepción son bloqueantes: Esperan a recibir unha mensaxe, ou esperan a poder enviala.
MSG_EXCEPT Lé a primeira mensaxe de tipo distinto a msgtype.
MSG_NOERROR Si a mensaxe é maior que msgsz, o trunca. Se non se pon este indicador, nese caso a función falla co erro E2BIG
Ambas devolven -1 poñendo o código de erro en errno no caso de fallo. msgsnd devolve 0 no caso de execución correcta e msgrcv devuelve el número de bytes leídos.

Semáforos

Os semáforos sirven para o control do acceso a recursos compartidos entre moitos procesos. Os semáforos proporcionados polos mecanismos IPC System V se manexan coas seguintes funcións:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
 
int semget(key_t key, int nsems, int semflg)

Esta función crea un conxunto de nsems semáforos. Os flags (semflg) son similares ós flags dos outros mecanismos IPC System V (memoria compartida e colas de mensaxes). Devolve -1 en caso de erro. Os semáforos creados estarán sen inicializar, e será preciso facelo mediante a función semctl e as operacións SETALL ou SETVAL si é oportuno.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
 
int semop(int semid, struct sembuf *sops, unsigned nsops);
 
int  semtimedop(int semid, struct sembuf *sops, unsigned nsops, 
                struct timespec *timeout);

struct sembuf
{
  unsigned short int sem_num;   /* semaphore number */
  short int sem_op;             /* semaphore operation */
  short int sem_flg;            /* operation flag */
};

A función semop permite operar cun conxunto de semáforos. As operacións indícanse nunha táboa de estructuras de tipo struct sembuf, que conteñen o número de semáforo do conxunto co que se vai a operar (sem_num), a operación a realizar sobre o semáforo (sem_op) e unha serie de indicadores (sem_flg).

As operacións poden ser:

  • sem_op > 0. O valor indicado en sem_op se suma ó valor do semáforo e o proceso continúa a súa execución. É necesario permiso de escritura sobre o semáforo.
  • sem_op == 0. O proceso queda bloqueado mentras o valor do semáforo sexa maior que 0, a non ser que se indique IPC_NOWAIT en sem_flg que voltaría un código de erro. Si se recibe unha sinal ou outro proceso elimina o semáforo, tamén continúa devolvendo un código de erro. É necesario permiso de lectura.
  • sem_op < 0. Si o valor do semáforo é >= que abs(sem_op) se lle resta abs(sem_op) ó valor do semáforo e a execución do proceso continúa. Noutro caso, o proceso queda á espera de que o valor do semáforo sexa >= abs(sem_op) ou que se de unha das condicións indicadas para sem_op==0.

Si algunha operación falla, non se realizará ningunha.

En sem_flg ademáis de IPC_NOWAIT pode especificarse SEM_UNDO que causaría que ó finalizar o proceso se desfixera automáticamente a operación realizada sobre o semáforo.

semtimedop é igual que semop, pero permite especificar un tempo máximo de espera, tras o que a función voltaría un código de erro.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
 
union semun {
    int val;                    /* valor para SETVAL */
    struct semid_ds *buf;       /* buffer para IPC_STAT, IPC_SET */
    unsigned short int *array;  /* array para GETALL, SETALL */
    struct seminfo *__buf;      /* buffer para IPC_INFO */
};

int semctl(int semid, int semnum, int cmd, union semun arg);

A función semctl sirve para controlar o semáforo realizando operacións como a eliminación do semáforo (IPC_RMID) ou a inicialización do semáforo (SETALLL, SETVAL).

  • Con SETALL se poñen todos os semáforos creados semid ó valor indicado en arg.
  • con SETVAL é posible poñer un semáforo do grupo semid ó valor indicado pasado na unión arg:

Comandos de Xestión de IPC

Existen dous comandos da shell para examinar os recursos IPC que están sendo utilizados nun momento dado e para eliminar os mesmos:

  • ipcs
  • ipcrm