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