System Call per la gestione dei semafori in Linux Semafori: modello

Transcript

System Call per la gestione dei semafori in Linux Semafori: modello
System Call per la gestione dei
semafori in Linux
Domenico Cotroneo
Dipartimento di Informatica e
Sistemistica
Semafori: modello concettuale
Processore
D
C B
(sq)Coda proc.sospesi
void wait(sempahore s) {
s.count--;
if (s.count<0){
sq.insert(Process);
suspend(Process);
}
}
s.count=1
semaforo
A
(sr) Coda proc. pronti
void signal(sempahore s) {
s.count++;
if (s.count<=0){
sq.remove(Process);
suspend(Process);
}
}
Creazione ed inizializzazione di
un semaforo
key_t
key_t chiave_sem=IPC_PRIVATE;
chiave_sem=IPC_PRIVATE;
//richiesta
//richiesta di
di 22 semafori
semafori ed
ed inizializzazione
inizializzazione
sem=semget(chiave_sem,2,IPC_CREAT|0664);
sem=semget(chiave_sem,2,IPC_CREAT|0664);
//Inizializzazione
//Inizializzazione dei
dei due
due semafori
semafori
semctl(sem,0,SETVAL,val1);
semctl(sem,0,SETVAL,val1);
semctl(sem,1,SETVAL,val2);
semctl(sem,1,SETVAL,val2);
1
semop - semaphore operations
int
intsemop(int
semop(intsemid,
semid,struct
structsembuf
sembuf*sops,
*sops,unsigned
unsignednsops);
nsops);
Un semaforo è una struttura dati che comprende tra i suoi campi i seguenti:
unsigned short semval; /* semaphore value */
unsigned short semzcnt; /* # waiting for zero */
unsigned short semncnt; /* # waiting for increase */
pid_t sempid; /* process that did last op */
…è su questi che agisce la primitiva semop (in particolare sulla
struttura indicata da semid)
semop - semaphore operations
Ognuno degli nsops elementi, riferiti dal puntatore sops, specifica
un’operazione da compiere sul semaforo. L’operazione è descritta da
una struttura, struct sembuf, la quale include i seguenti campi:
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
Due sono i valori che puo’ assumere sem_flg : IPC_NOWAIT e
SEM_UNDO. Se si specifica SEM_UNDO, l’operazione sarà annullata
nel momento in cui il processo che la ha eseguita termina.
semop - semaphore operations
L’insieme delle operazioni specificate da sops sono eseguite in maniera
atomica.
Ogni operazione è eseguita sul semaforo individuato da sem_num (in
altre parole sem_num indica su quale semaforo, tra quelli presenti
nell’array, dovrà essere eseguita l’operazione).
Il primo semaforo dell’array ha indice 0.
I valori che può assumere il campo sem_op specificano tre possibili
tipologie di operazioni che si possono compiere sul semaforo:
• sem_op < 0 : wait
• sem_op==0 : wait_for_zero
• sem_op > 0 : signal
2
sem_op > 0: “signal”
Se sem_op è un intero positivo, l’operazione consiste nell’addizionare il
valore di sem_op al valore del semaforo (semval).
semval+=sem_op
Inoltre, nel caso in cui sia specificato il flag SEM_UNDO, il sistema
aggiornerà il contatore “undo count” (semadj) del processo per il
semaforo in questione. E’ utile osservare che quest’ultima operazione
non verrà mai bloccata.
Al fine di eseguire l’operazione di “signal”, il processo chiamante dovrà
sicuramente avere i permessi necessari alla modifica dei valori del
semaforo.
sem_op == 0: “wait_for_zero”
Se sem_op ha valore nullo, l’operazione specificata ( "wait-for-zero“) è
articolata nei seguenti passi:
1. se il valore semval è zero, l’operazione procede immediatamente (il
processo non si sospende)
2. Altrimenti (semval ≠ 0) si procederà come di seguito
i. se è specificato il flag IPC_NOWAIT in sem_flg, la system call
fallisce restituendo il codice di errore EAGAIN a mezzo della
variabile errno (nessuna delle operazioni specificate in sops sarà
eseguita).
ii. altrimenti la variabile semzcnt (che indica il numero di processi sospesi
nell’attesa che il valore del semaforo diventi nullo) è incrementata di
uno, forzando il processo a sopsendersi finché una delle seguenti
condizioni si verificherà:
a) semval diventa 0, (allora il valore di semzcnt è decrementato).
b) Il semaforo è rimosso: la system call fallisce ( errno = EIDRM).
Al fine di eseguire l’operazione di “wai_for_zero”, il processo chiamante dovrà
almeno avere i permessi in lettura dei valori del semaforo.
sem_op <0 0: “wait” (1/2)
Se sem_op ha valore negativo, l’operazione si articolerà come di seguito:
1. se (semval ≥ |sem_op| ) l’operazione procede immediatamente e se
specificato il SEM_UNDO flag il sistema aggiornerà il contatore
“undo count” (semadj) del processo per il semaforo in
questione.
2. se (semval < |sem_op| )
1. se specificato il flag IPC_NOWAIT la system call fallisce
(errno = EAGAIN )
2. altrimenti il valore del campo semcnt (il contatore dei
processi sospesi nell’attesa che il valore del semfaro venga
incrementato) viene incrementato di 1. Il processo si
sospende
Al fine di eseguire l’operazione di “wait”, il processo chiamante dovrà
sicuramente avere i permessi necessari alla modifica dei valori del
semaforo.
3
sem_op <0 0: “wait” (2/2)
Nel caso 2.2 il processo sarà sospeso nell’attesa del verificarsi di una
delle seguenti condizioni:
1 ) (semval ≥ |sem_op| ), quando questa condizione sarà verificata il
valore di semncnt sarà decrementato e il valore del semaforo
modificato come segue
semval-=|sem_op|
Se specificato SEM_UNDO il sistema aggiornerà il contatore “undo
count” (semadj) del processo per il semaforo in questione.
2) Il semaforo è rimosso: la system call fallisce ( errno = EIDRM).
Approfondimenti:
„
„
BUGS
When a process terminates, its set of associated semadj
structures is used to undo the effect of all of the semaphore
operations it performed with the SEM_UNDO flag. This raises a
difficulty: if one (or more) of these semaphore adjustments
would result in an attempt to decrease a semaphore's value
below zero, what should an implementation do? One possible
approach would be to block until all the semaphore adjustments
could be performed. This is however undesirable since it could
force process termination to block for arbitrarily long periods.
Another possibility is that such semaphore adjustments could be
ignored altogether (somewhat analogously to failing when
IPC_NOWAIT is specified for a semaphore operation). Linux
adopts a third approach: decreasing the semaphore value as far
as possible (i.e., to zero) and allowing process termination to
proceed immediately.
Implementazione di una wait
void
{{
void Wait_Sem
Wait_Sem (int
(int id_sem,
id_sem, int
int numsem)
numsem)
struct
struct sembuf
sembuf sem_buf;
sem_buf;
sem_buf.sem_num=numsem;
sem_buf.sem_num=numsem;
sem_buf.sem_flg=0;
sem_buf.sem_flg=0;
sem_buf.sem_op=-1;
sem_buf.sem_op=-1;
semop(id_sem,&sem_buf,1);
semop(id_sem,&sem_buf,1); //semaforo
//semaforo rosso
rosso
}}
4
Implementazione di una signal
void
void Signal_Sem
Signal_Sem (int
(int id_sem,int
id_sem,int numsem)
numsem)
struct
struct sembuf
sembuf sem_buf;
sem_buf;
}}
{{
sem_buf.sem_num=numsem;
sem_buf.sem_num=numsem;
sem_buf.sem_flg=0;
sem_buf.sem_flg=0;
sem_buf.sem_op=1;
sem_buf.sem_op=1;
semop(id_sem,&sem_buf,1);
semop(id_sem,&sem_buf,1); //semaforo
//semaforo verde
verde
5