You are on page 1of 36

3IS - Systme d'exploitation linux

Signaux et pipes

2010 David Picard


Contributions de : Arnaud Revel, Mickal Maillard
picard@ensea.fr

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Communication entre processus

Entre un pre et son fils

Zone de data aprs fork() (mais sens unique)


Paramtres aprs exec()
Pipe

Entre deux processus sans lien

Pipe nomm
Fichiers

Problme : solutions trs lentes

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Signaux

Moyen simple de communication entre


processus
Gnrs soit

Exception au cours de l'excution du processus


D'origine matrielle : erreur d'adressage, virgule flottante
D'origine logicielle : CTRL-C, SIGCHLD, sur commande

Lorsqu'un processus reoit un signal

Il est dtruit (par dfaut)


Une routine spciale est excute

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Type de signaux
#defineSIGHUP1/*Hangup(POSIX).*/
#defineSIGINT2/*Interrupt(ANSI).*/
#defineSIGQUIT3/*Quit(POSIX).*/
#defineSIGILL4/*Illegalinstruction(ANSI).*/
#defineSIGTRAP5/*Tracetrap(POSIX).*/
#defineSIGABRT6/*Abort(ANSI).*/
#defineSIGIOT6/*IOTtrap(4.2BSD).*/
#defineSIGBUS7/*BUSerror(4.2BSD).*/
#defineSIGFPE8/*Floatingpointexception(ANSI).*/
#defineSIGKILL9/*Kill,unblockable(POSIX).*/
#defineSIGUSR110/*Userdefinedsignal1(POSIX).*/
#defineSIGSEGV11/*Segmentationviolation(ANSI).*/
#defineSIGUSR212/*Userdefinedsignal2(POSIX).*/
#defineSIGPIPE13/*Brokenpipe(POSIX).*/
#defineSIGALRM14/*Alarmclock(POSIX).*/
#defineSIGTERM15/*Termination(ANSI).*/
#defineSIGSTKFLT16/*Stackfault.*/
#defineSIGCLDSIGCHLD/*SameasSIGCHLD(SystemV).*/
#defineSIGCHLD17/*Childstatushaschanged(POSIX).*/
#defineSIGCONT18/*Continue(POSIX).*/
#defineSIGSTOP19/*Stop,unblockable(POSIX).*/
#defineSIGTSTP20/*Keyboardstop(POSIX).*/
#defineSIGTTIN21/*Backgroundreadfromtty(POSIX).*/
#defineSIGTTOU22/*Backgroundwritetotty(POSIX).*/
#defineSIGURG23/*Urgentconditiononsocket(4.2BSD).*/
#defineSIGXCPU24/*CPUlimitexceeded(4.2BSD).*/
#defineSIGXFSZ25/*Filesizelimitexceeded(4.2BSD).*/
#defineSIGVTALRM26/*Virtualalarmclock(4.2BSD).*/
#defineSIGPROF27/*Profilingalarmclock(4.2BSD).*/
#defineSIGWINCH28/*Windowsizechange(4.3BSD,Sun).*/
#defineSIGPOLLSIGIO/*Pollableeventoccurred(SystemV).*/
#defineSIGIO29/*I/Onowpossible(4.2BSD).*/
#defineSIGPWR30/*Powerfailurerestart(SystemV).*/
#defineSIGSYS31/*Badsystemcall.*/

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Les signaux ne sont pas des


interruptions !

Lors d'une interruption, la routine associe est


excute immdiatement
Lors de la rception d'un signal, le code
associ sera excut lorsque le processus aura
du temps d'excution disponible sur un CPU
Les signaux ne sont pas temps rels !

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Fonctionnement par dfaut

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Mise en place d'un handler


Programme

Handler

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Signal

signal()
#include<signal.h>
voidspint(intsig)
{
printf("Recusignald'interruption%d\n",sig);
}
intmain()
{
signal(SIGINT,spint);
pause();
exit(0);
}

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

kill()
#include<stdio.h>
voidspsig(intsig)
{printf("Signal%drecu\n",sig);}
intmain()
{
intidfils,status;
if(idfils=fork()){/*pere*/
sleep(5);
kill(idfils,SIGUSR1);
wait(&status);
exit(0);
}
else{/*fils*/
signal(SIGUSR1,spig);
pause();
exit(1);
}
}

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Signaux temps rel

La norme posix 1.b impose au moins 8 signaux dits


temps-rels
Linux en supporte 32 numrots de 32 (SIGRTMIN)
63 (SIGRTMAX)
Les signaux temps-rel n'ont pas de signification
prdfinie
L'action par dfaut est de terminer le processus
si des signaux standards et des signaux temps-rel
sont simultanment en attente pour un processus Linux
donne la priorit aux signaux temps-rel

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Faux temps rel !!!

Le qualificatif ``temps-rel'' est trompeur !


Aucune contrainte temporelle n'est impose au
niveau de l'ordonnanceur
Comme pour les signaux standards le signal
sere dlivr un processus uniquement quand
celui-ci sera ordonnanc

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Proprits

Plusieurs instances d'un signal peuvent tre empiles


(/proc/sys/kernel/rtsigmax) un signal temps-rel
peut tre envoy par sigqueue() et accompagn d'un
paramtre.
Un gestionnaire utilisant l'appel sigaction() peut
accder cette valeur
si plusieurs signaux temps-rel sont envoys ils sont
dlivrs en commenant par le signal de numro le moins
lev (le signal de plus fort numro est celui de priorit la
plus faible).
Les signaux temps-rel du mme type sont dlivrs dans
l'ordre o ils ont t mis.
COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Exemple de gestionnaire
#include<stdio.h><stdlib.h><sys/types.h><unistd.h><signal.h><sys/wait.h>
voidgestionnaire(intsig,siginfo_t*info,void*inutile)
{
char*origine;
printf("Receptiondusignaln%d",sig);
switch(info>si_code){
caseSI_USER:
printf("envoyaumoyendekill()ouraise()parleprocessus%ld\n",info>si_pid);
break;
caseSI_QUEUE:
printf("envoyaumoyendesigqueue()parleprocessus%ldaveclavaleur%d\n",
(long)info>si_pid,info>si_value.sival_int);
break;
default:
printf("\n");
break;
}
}

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Exemple d'utilisation
intmain()
{
pid_tpid_fils;
switch(pid_fils=(long)fork()){
case1:perror("Erreurlorsdefork");returnEXIT_FAILURE;
case0:
{sigset_tmasque;structsigactionaction;
sigemptyset(&masque);
sigaddset(&masque,SIGUSR1);
sigprocmask(SIG_BLOCK,&masque,NULL);
action.sa_sigaction=gestionnaire;
action.sa_mask=masque;
action.sa_flags=SA_SIGINFO;
sigaction(SIGUSR1,&action,NULL);
sigprocmask(SIG_UNBLOCK,&masque,NULL);
while(1);
}
default:
{unionsigvalval;
val.sival_int=123;
sigqueue(pid_fils,SIGUSR1,val);
wait(NULL);
}}
returnEXIT_SUCCESS;
}

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Pipes

Un pipe est un fichier virtuel (pas stock sur un


disque)
Il possde deux descripteurs : un en lecture et
un en criture
Les descripteurs de fichiers tant partags par
un processus pre et son fils, le pipe permet la
communication de donnes entre processus
Il fonctionne avec un tampon circulaire

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

pipe()

fd1
fd2

r_pos
w_pos
ref=2

iptr

ref=1

text

w_position

task_struct

iptr

data

ref=1

r_position

stack

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

pipe()

Le pre crit dans le pipe

Le fils lit depuis le pipe

Ou l'inverse...

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Exemple de code
intmain()
{
intstatus,pipedes[2];
charbuf[100];
intlen;
char*msg="SalutFred!";
structstatpipestat;
if(pipe(pipedes))exit(1);
if(fork()){/*Codedupere*/
write(pipedes[1],msg,strlen(msg));
wait(&status);
return;
}
else{/*Codedufils*/
while(len==0)/*Attendquelepipesoitrempli*/
{
if(fstat(pipedes[0],&pipestat))exit(3);
len=(int)pipestat.st_size;
}
read(pipedes[0],buf,len);
printf("Monpereadorel'artdedecalerlessons:%s\n",buf);
return;
}
}

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Exemple 2 pipes
intpipdes1[2],pipdes2[2];
voidfils()
{
charbuff[21];

/*Fermeturedupipe1en
ecritureet0enlecture*/
close(pipdes1[1]);
close(pipdes2[0]);
read(pipdes1[0],buff,21);
printf("fils:%s\n",buff);
write(pipdes2[1],"Message
recu",13);
return;
}

intmain()
{
intstatus;
charbufp[13];
if(pipe(pipdes1))exit(1);
if(pipe(pipdes2))exit(1);
if(fork())
{
/*Fermeturedupipe0en
ecritureet1enlecture*/
close(pipdes1[0]);
close(pipdes2[1]);
write(pipdes1[1],"Salutlesprocess...",21);
read(pipdes2[0],bufp,13);
printf("Pere:%s\n",bufp);
wait(&status);
exit(0);
}
else
{
fils();
}
}

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Pipes nomms

Un fichier spcial est cr (p)

Une inode est rserve

N'est pas utilis comme un fichier mais comme


un pipe

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Exemple cration et criture


#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#defineNAME_PIPE"./my_pipe"
intmain(intac,char**av)
{
charDATA[32];
intfd;
intpid;
mkfifo(NAME_PIPE,0666);
fd=open(NAME_PIPE,O_WRONLY);
if(fd==1)
exit(1);
pid=getpid();
sprintf(DATA,"%idithello",pid);
write(fd,DATA,strlen(DATA)+1);
sleep(5);
return0;
}

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Exemple ouverture et lecture


#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#defineNAME_PIPE"./my_pipe"
#defineBUFFSIZE1024
intmain(intac,char**av)
{
charsbBuf[BUFFSIZE];
intfd;
intpid;
fd=open(NAME_PIPE,"r");
pid=getpid();
read(fd,sbBuf,BUFFSIZE);
printf("[%i]%s\n",pid,sbBuf);
return0;
}

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Sockets

Extension des pipes nomms des processus


se trouvant sur des machines diffrentes

Apparues en 1983 dans 4.2BSD

Fonctionnent comme des fichiers, mais

tape d'initialisation afin de spcifier les


protocoles rseaux
Prise (lectrique) en bon franais, mais tout le
monde utilise le terme socket

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Cration d'une socket

int socket(int domaine, int type, int protocole)

Domaine de communicartion (IP : AF_INET,


IPv6 : AF_INET6, Unix : AF_UNIX, etc)
Type de socket
SOCK_STREAM (connect)
SOCL_DGRAM (non connect)
SOCK_RAW (brute)
Protocole (TCP : IPPROTO_TCP, etc peuttre NULL et devin par l'OS)

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Exemple
#include <sys/socket.h>
int main() {
int sock;
if(( sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf( error socket\n );
return -1;
}
return 0;
}

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Ct serveur

Attachement de la socket une adresse+port :


bind(int sock, struct sockaddr *a, socklen_t len)

Attente de connexion (coute) :


listen(int sock, int nb_file_attente)

Lancement de la routine excuter en cas de


connexion
accept(int sock, struct sockaddr *a, socklen_t *len)

En gnral, on fork()
Le pre retourne l'coute
Le fils effectue le traitement

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Exemple

int main(int argc, char *argv[])


{
int sfd, cfd; struct sockaddr_un my_addr, peer_addr; socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
while(1) {
peer_addr_size = sizeof(struct sockaddr_un);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (cfd == -1) handle_error("accept");
if(fork()) { /* pere
close(cfd); continue;
} else { /* fils */
close(sfd); /* code du traitement des donnes */
}
}
}
COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Cration

int main(int argc, char *argv[])


{
int sfd, cfd; struct sockaddr_un my_addr, peer_addr; socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
while(1) {
peer_addr_size = sizeof(struct sockaddr_un);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (cfd == -1) handle_error("accept");
if(fork()) { /* pere
close(cfd); continue;
} else { /* fils */
close(sfd); /* code du traitement des donnes */
}
}
}
COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Init de la struct addr

int main(int argc, char *argv[])


{
int sfd, cfd; struct sockaddr_un my_addr, peer_addr; socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
while(1) {
peer_addr_size = sizeof(struct sockaddr_un);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (cfd == -1) handle_error("accept");
if(fork()) { /* pere
close(cfd); continue;
} else { /* fils */
close(sfd); /* code du traitement des donnes */
}
}
}
COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Attachement

int main(int argc, char *argv[])


{
int sfd, cfd; struct sockaddr_un my_addr, peer_addr; socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
while(1) {
peer_addr_size = sizeof(struct sockaddr_un);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (cfd == -1) handle_error("accept");
if(fork()) { /* pere
close(cfd); continue;
} else { /* fils */
close(sfd); /* code du traitement des donnes */
}
}
}
COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Attente

int main(int argc, char *argv[])


{
int sfd, cfd; struct sockaddr_un my_addr, peer_addr; socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
while(1) {
peer_addr_size = sizeof(struct sockaddr_un);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (cfd == -1) handle_error("accept");
if(fork()) { /* pere
close(cfd); continue;
} else { /* fils */
close(sfd); /* code du traitement des donnes */
}
}
}
COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Nouvelle connection

int main(int argc, char *argv[])


{
int sfd, cfd; struct sockaddr_un my_addr, peer_addr; socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
while(1) {
peer_addr_size = sizeof(struct sockaddr_un);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (cfd == -1) handle_error("accept");
if(fork()) { /* pere
close(cfd); continue;
} else { /* fils */
close(sfd); /* code du traitement des donnes */
}
}
}
COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Retour en attente

int main(int argc, char *argv[])


{
int sfd, cfd; struct sockaddr_un my_addr, peer_addr; socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
while(1) {
peer_addr_size = sizeof(struct sockaddr_un);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (cfd == -1) handle_error("accept");
if(fork()) { /* pere
close(cfd); continue;
} else { /* fils */
close(sfd); /* code du traitement des donnes */
}
}
}
COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Traitement

int main(int argc, char *argv[])


{
int sfd, cfd; struct sockaddr_un my_addr, peer_addr; socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
while(1) {
peer_addr_size = sizeof(struct sockaddr_un);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (cfd == -1) handle_error("accept");
if(fork()) { /* pere
close(cfd); continue;
} else { /* fils */
close(sfd); /* code du traitement des donnes */
}
}
}
COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Ct client
int connect(int sock, struct sockaddr *a, int len)

Crer la socket avec socket()

Ouvrir la connection une adresse + port

Pas besoin de bind()

COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

Exemple
#define MY_SOCK_PATH /tmp/mysock
int main(int argc, char *argv[])
{
int cfd; struct sockaddr_un my_addr;
char buffer[64];
cfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1) handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path)
1);
if(connect(cdf, &my_addr, sizeof(struct sock_addr_un)) < 0) }
handle_error( connect );
}
read(cdf, buffer, 64);
printf( lu : %s\n , buffer);
return 0;
}
COLE NATIONALE SUPRIEURE DE L'LECTRONIQUE ET DE SES APPLICATIONS

You might also like