Inter-Process Communication (IPC)
IPCS
1
1. Code di messaggi 2. Semafori 3. Memoria condivisa
2
?
send
receive
3 p1 p3 p2
CODE DI MESSAGGI
1
Modello di Comunicazione Code di Messaggi Il processo ricevente può sospendersi in attesa di un messaggio oppure no MECCANISMO ASINCRONO
Receive(mesg)
Send(mesg)
L’invio avviene quando il messaggio è pronto; il ricevente si accorge del messaggio solo se va a controllare la coda (non viene avvisato)
P3
P1 P2
P4
P5 Più processi possono leggere/scrivere messaggi dalla/nella stessa coda; Mailbox = caso particolare
Operazioni relative a una coda di messaggi 1. 2. 3. 4.
Creazione coda Invio di un messaggio Recezione di un messaggio Eliminazione coda
Se più processi ricevono messaggi in una stessa coda come posso distinguere il destinatario di un particolare messaggio?
Una coda è una struttura dati condivisa da più processi: un processo è il creatore, gli altri come possono accedere alla coda???
Chi può inviare messaggi? Chi può leggere messagi da una coda? Quale formato devono avere i messaggi?
Code di Messaggi Strutture dati key msqid 123 4652
msqid_ds Tabella di Descrittori
…
0 1 …
mode
Key: numero che ha senso per il processo
ipc_perm
msqid: identificatore interno assegnato dal sistema
2
Che differenza c’è fra KEY e MSQID ??? Identificatore esterno scelto dall’utente Identificatore interno generato e restituito dal sistema
key msqid 0 1 …
123 4652
È usato dalle system call per inviare e ricevere messaggi
Una coda di messaggi è identificata da un numero intero (msqid) al quale è associata una struttura dati (msqid_ds) così costituita: msqid_ds: struct ipc_perm msg_perm; struct msg * msg_first; struct msg * msg_last; ulong_t msg_cbytes; ulong_t msg_qnum; ulong_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; time_t msg_stime; time_t msg_rtime; time_t msg_ctime;
- - - prossimo lucido puntatore al primo messaggio in coda puntatore all’ultimo messaggio in coda dimensione attuale della coda (in byte) numero dei msg attualmente in coda max num. di byte ammesso per la coda PID dell’ultimo processo che ha eseguito una send PID dell’ultimo processo che ha eseguito una receive ora di esecuz. dell’ultima send ora di esecuz. dell’ultima receive ora di esecuzione dell’ultima msgctl
msg_perm: uid_t cuid; gid_t cgid; … mode_t mode; … key_t key;
1. 2. 3. 4.
UID del creatore della coda GID del creatore della coda diritti di accesso chiave
Se l’effective user id del processo è ROOT l’accesso è sempre garantito Se cuid corrisponde all’effective user id del processo ed è settato il valore 0600 l’accesso è garantito Se il processo ha GID corrispondente a cgid e 0060 è settato l’accesso è garantito Negli altri casi se 0006 è settato l’accesso è garantito
00400 00200 00040 00020 00004 00002
READ proprietario WRITE proprietario READ gruppo WRITE gruppo READ altri WRITE altri
3
#include int msgget(key_t key, int msgflg); int msgctl(int msqid, int cmd, struct msqid_ds *buf); int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
MSGGET
(1)
int msgget(key_t key, int msgflg);
key_t rinomina del tipo intero
Effetti di msgget: 1. Restituisce l’identificatore della coda di messaggi associata alla chiave key, se esiste 2. Crea una nuova coda di messaggi se: • key = IPC_PRIVATE (costante predefinita) • key non ha associata una coda di messaggi e msgflag&IPC_CREAT vale true 3. - 1 in caso di errore
4
Esempio di utilizzo di
int msgget(key_t key, int msgflg)
int msqid; msqid = msgget(1234, IPC_CREAT | 666); … Lettura e scrittura sulla coda abilitate per tutti i processi
Numero che ha un senso all’interno del mio programma
OR bit a bit Costante che indica l’intenzione di creare una coda se la chiave non ne ha associate
Esempio di utilizzo di
int msgget(key_t key, int msgflg)
int msqid; msqid = msgget(1234, 0); …
Se so che un altro processo deve avere già creato la coda a cui voglio accedere posso passare come msgflg il valore ZERO
Inizializzazione della struttura 1.
A cuid e a cgid vengono assegnati l’effective user id e l’effective group id del processo creante
2.
Ai 9 bit inferiori di mode.msg_perm vengono assegnati i 9 bit inferiori di msg_flg
3.
A qnum, lspid, lrpid, stime ed rtime viene assegnato 0
4.
A ctime l’ora corrente
5.
A qbytes il limite fissato da sistema
5
Primo modo per far sì che più processi conoscano l’id di una stessa coda
1 coda.h #define ID_CODA
789
proc1.c
proc2.c
#include “coda.h” …
#include “coda.h” …
…
Secondo modo per far sì che più processi conoscano l’id di una stessa coda
2 padre.c int ID_CODA = msgget(789, IPC_CREAT | 666); padre = fork(); if (padre) { <> }
Padre e figlio possono comunicare attraverso la coda di messaggi
else { << il figlio eredita una copia di ID_CODA >> }
Terzo modo per far sì che più processi conoscano l’id di una stessa coda
3 proc1.c int ID_CODA = msgget(getppid(), IPC_CREAT | 666); Viene usata come chiave un’informazione comune (es. due processi con lo sesso padre possono usare il PID del padre
proc1.c int ID_CODA = msgget(getppid(), IPC_CREAT | 666);
6
MSGSND MSGSRCV
Ci aspettiamo Send(coda, messaggio) Invece abbiamo a disposizione una system call molto più complessa e a basso livello: Send(coda, messaggio, dimensione, azione) int msgsnd(int msqid, id della coda const void *msgp, buffer tipo definito dall’utente -- fra due lucidi --
size_t int
msgsz, msgflg);
è relativo a msgp azione specifica cosa fare se la coda è piena
Analogamente ci aspettiamo Receive(coda, &messaggio) Anche in questo caso abbiamo a disposizione una system call molto più complessa e a basso livello Receive(coda, &messaggio, dimensione, tipo, azione) int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
id della coda buffer che conterrà un msg dimensione di msgp tipo di msg da accettare azione da eseguire se non c’è un msg del tipo atteso
7
Non esiste un tipo di dato predefinito per i messaggi, il programmatore può creare una propria struttura a patto che questa contenga i due campi: long mesg_type; Mio_tipo *mesg_data;
In una coda possono essere inseriti msg di diverso tipo per destinatari diversi, mesg_type consente di distinguerli
È il messaggio vero e proprio: ad es. una stringa di caratteri
Es. typedef struct { int mesg_len; long mesg_type; char mesg_data[MAXMESGDATA]; } mio_messaggio;
msgsnd copia i dati spediti nella coda indicata ma NON copia l’intera struttura definita dal programmatore! Copia solo mesg_type e gli msgsz byte che seguono mesg_type Es. typedef struct { int mesg_len;
Questa parte contiene informazioni di servizio che servono a costruire il messaggio senza farne parte
long mesg_type; char mesg_data[MAXMESGDATA];
Parte copiata
} mio_messaggio; msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
mio_messaggio da_spedire; Suppongo che dato venga passato dall’utente sprintf(da_spedire.msg_data, “val%d”, dato); da_spedire.mesg_len = strlen(da_spedire.msg_data); da_spedire.mesg_type = 1; msgsnd(id_coda, (char *)&(da_spedire->mesg_type), da_spedire.mesg_len, 0);
5 1 val32
Indirizzo di mesg_type
len type data
Solo questo pezzo viene spedito!
da_spedire
Vengono copiati solo mesg_type e i “mesg_len” byte successivi a mesg_type
8
Tramite msgsnd e msgrcv possono essere implementate molte Send e Receive diverse
Se non c’è spazio aspetta Se non c’è spazio termina
Bloccante Non bloccante Accetta qualsiasi msg Accetta solo msg di un tipo …
Le azioni sono codificate in msgflg …
msgflg può valere (nelle varie system call IPC): 1. IPC_CREAT: se non è associato un oggetto alla chiave, lo crea 2. IPC_EXCL: se non è associato alcun oggetto alla chiave produce un errore
3. IPC_PRIVATE: crea un oggetto privato per il processo 4. IPC_NOWAIT : regola il comportamento in caso di accesso • msgsnd: se non c’è spazio suff per il messaggio fallisce • msgrcv: se non c’è un msg del tipo desiderato termina subito
MSGCTL
9
Questa system call consente di eseguire una varietà di operazioni di controllo su di una coda di messaggi: 1. IPC_STAT :: restituisce i valori contenuti nella struttura dati associata a msqid :: assegna valori ai campi della struttura dati associata a msqid 3. IPC_RMID :: disallocazione della coda di messaggi
2. IPC_SET
int msgctl(int msqid, id coda su cui eseguire un comando int cmd, comando da eseguire struct msqid_ds *buf); struttura di supporto Restituisce 0 se tutto ok, - 1 in caso di errore
10