Il kernel mantiene una tabella dei processi attivi, la cosiddetta
\textit{process table}; per ciascun processo viene mantenuta una voce nella
-tabella dei processi costituita da una struttura \type{task\_struct}, che
+tabella dei processi costituita da una struttura \struct{task\_struct}, che
contiene tutte le informazioni rilevanti per quel processo. Tutte le strutture
usate a questo scopo sono dichiarate nell'header file \file{linux/sched.h}, ed
uno schema semplificato, che riporta la struttura delle principali informazioni
-contenute nella \type{task\_struct} (che in seguito incontreremo a più
+contenute nella \struct{task\_struct} (che in seguito incontreremo a più
riprese), è mostrato in \figref{fig:proc_task_struct}.
\begin{figure}[htb]
Tutti i processi inoltre memorizzano anche il \acr{pid} del genitore da cui
sono stati creati, questo viene chiamato in genere \acr{ppid} (da
\textit{parent process id}). Questi due identificativi possono essere
-ottenuti da programma usando le funzioni:
+ottenuti usando le due funzioni \funcd{getpid} e \funcd{getppid}, i cui
+prototipi sono:
\begin{functions}
- \headdecl{sys/types.h} \headdecl{unistd.h} \funcdecl{pid\_t getpid(void)}
- Restituisce il \acr{pid} del processo corrente. \funcdecl{pid\_t
- getppid(void)} Restituisce il \acr{pid} del padre del processo corrente.
+ \headdecl{sys/types.h}
+ \headdecl{unistd.h}
+ \funcdecl{pid\_t getpid(void)}
+
+ Restituisce il \acr{pid} del processo corrente.
+
+ \funcdecl{pid\_t getppid(void)}
+
+ Restituisce il \acr{pid} del padre del processo corrente.
\bodydesc{Entrambe le funzioni non riportano condizioni di errore.}
\end{functions}
\subsection{La funzione \func{fork}}
\label{sec:proc_fork}
-La funzione \func{fork} è la funzione fondamentale della gestione dei
+La funzione \funcd{fork} è la funzione fondamentale della gestione dei
processi: come si è detto l'unico modo di creare un nuovo processo è
attraverso l'uso di questa funzione, essa quindi riveste un ruolo centrale
tutte le volte che si devono scrivere programmi che usano il multitasking. Il
\item il \acr{pid} (\textit{process id}).
\item il \acr{ppid} (\textit{parent process id}), quello del figlio viene
impostato al \acr{pid} del padre.
-\item i valori dei tempi di esecuzione della struttura \var{tms} (vedi
+\item i valori dei tempi di esecuzione della struttura \struct{tms} (vedi
\secref{sec:sys_cpu_times}) che nel figlio sono posti a zero.
-\item i \textit{file lock} (vedi \secref{sec:file_locking}), che non
+\item i \textit{lock} sui file (vedi \secref{sec:file_locking}), che non
vengono ereditati dal figlio.
\item gli allarmi ed i segnali pendenti (vedi \secref{sec:sig_gen_beha}), che
per il figlio vengono cancellati.
Dato che Linux supporta il \textit{copy on write}\index{copy on write} la
perdita di prestazioni è assolutamente trascurabile, e l'uso di questa
-funzione (che resta un caso speciale della funzione \func{clone}), è
+funzione (che resta un caso speciale della system call \func{\_\_clone}), è
deprecato; per questo eviteremo di trattarla ulteriormente.
571 pts/0 Z 0:00 [forktest <defunct>]
572 pts/0 R 0:00 ps T
\end{verbatim} %$
-\normalsize
-e come si vede, dato che non si è fatto nulla per riceverne lo stato di
-terminazione, i tre processi figli sono ancora presenti pur essendosi
-conclusi, con lo stato di zombie e l'indicazione che sono stati terminati.
-
-La possibilità di avere degli zombie deve essere tenuta sempre presente quando
-si scrive un programma che deve essere mantenuto in esecuzione a lungo e
-creare molti figli. In questo caso si deve sempre avere cura di far leggere
-l'eventuale stato di uscita di tutti i figli (in genere questo si fa
+\normalsize e come si vede, dato che non si è fatto nulla per riceverne lo
+stato di terminazione, i tre processi figli sono ancora presenti pur essendosi
+conclusi, con lo stato di zombie\index{zombie} e l'indicazione che sono stati
+terminati.
+
+La possibilità di avere degli zombie\index{zombie} deve essere tenuta sempre
+presente quando si scrive un programma che deve essere mantenuto in esecuzione
+a lungo e creare molti figli. In questo caso si deve sempre avere cura di far
+leggere l'eventuale stato di uscita di tutti i figli (in genere questo si fa
attraverso un apposito \textit{signal handler}, che chiama la funzione
\func{wait}, vedi \secref{sec:sig_sigchld} e \secref{sec:proc_wait}). Questa
-operazione è necessaria perché anche se gli \textit{zombie} non consumano
-risorse di memoria o processore, occupano comunque una voce nella tabella dei
-processi, che a lungo andare potrebbe esaurirsi.
+operazione è necessaria perché anche se gli \textit{zombie}\index{zombie} non
+consumano risorse di memoria o processore, occupano comunque una voce nella
+tabella dei processi, che a lungo andare potrebbe esaurirsi.
Si noti che quando un processo adottato da \cmd{init} termina, esso non
-diviene uno \textit{zombie}; questo perché una delle funzioni di \cmd{init} è
-appunto quella di chiamare la funzione \func{wait} per i processi cui fa da
-padre, completandone la terminazione. Questo è quanto avviene anche quando,
-come nel caso del precedente esempio con \cmd{forktest}, il padre termina con
-dei figli in stato di zombie: alla sua terminazione infatti tutti i suoi figli
-(compresi gli zombie) verranno adottati da \cmd{init}, il quale provvederà a
-completarne la terminazione.
+diviene uno \textit{zombie}\index{zombie}; questo perché una delle funzioni di
+\cmd{init} è appunto quella di chiamare la funzione \func{wait} per i processi
+cui fa da padre, completandone la terminazione. Questo è quanto avviene anche
+quando, come nel caso del precedente esempio con \cmd{forktest}, il padre
+termina con dei figli in stato di zombie\index{zombie}: alla sua terminazione
+infatti tutti i suoi figli (compresi gli zombie\index{zombie}) verranno
+adottati da \cmd{init}, il quale provvederà a completarne la terminazione.
-Si tenga presente infine che siccome gli zombie sono processi già usciti, non
-c'è modo di eliminarli con il comando \cmd{kill}; l'unica possibilità di
-cancellarli dalla tabella dei processi è quella di terminare il processo che
-li ha generati, in modo che \cmd{init} possa adottarli e provvedere a
-concluderne la terminazione.
+Si tenga presente infine che siccome gli zombie\index{zombie} sono processi
+già usciti, non c'è modo di eliminarli con il comando \cmd{kill}; l'unica
+possibilità di cancellarli dalla tabella dei processi è quella di terminare il
+processo che li ha generati, in modo che \cmd{init} possa adottarli e
+provvedere a concluderne la terminazione.
\subsection{Le funzioni \func{wait} e \func{waitpid}}
principale attende le richieste che vengono poi soddisfatte da una serie di
processi figli. Si è già sottolineato al paragrafo precedente come in questo
caso diventi necessario gestire esplicitamente la conclusione dei figli onde
-evitare di riempire di \textit{zombie} la tabella dei processi; le funzioni
-deputate a questo compito sono sostanzialmente due, \func{wait} e
+evitare di riempire di \textit{zombie}\index{zombie} la tabella dei processi;
+le funzioni deputate a questo compito sono sostanzialmente due, \funcd{wait} e
\func{waitpid}. La prima, il cui prototipo è:
\begin{functions}
\headdecl{sys/types.h}
più volte se si vuole recuperare lo stato di terminazione di tutti quanti.
Al ritorno della funzione lo stato di terminazione del figlio viene salvato
-nella variabile puntata da \var{status} e tutte le risorse del kernel relative
-al processo (vedi \secref{sec:proc_termination}) vengono rilasciate. Nel caso
-un processo abbia più figli il valore di ritorno (il \acr{pid} del figlio)
-permette di identificare qual'è quello che è uscito.
+nella variabile puntata da \param{status} e tutte le risorse del kernel
+relative al processo (vedi \secref{sec:proc_termination}) vengono rilasciate.
+Nel caso un processo abbia più figli il valore di ritorno (il \acr{pid} del
+figlio) permette di identificare qual'è quello che è uscito.
Questa funzione ha il difetto di essere poco flessibile, in quanto ritorna
all'uscita di un qualunque processo figlio. Nelle occasioni in cui è
provvedere a ripetere la chiamata alla funzione nel caso il processo cercato
sia ancora attivo.
-Per questo motivo lo standard POSIX.1 ha introdotto la funzione \func{waitpid}
-che effettua lo stesso servizio, ma dispone di una serie di funzionalità più
-ampie, legate anche al controllo di sessione (si veda
+Per questo motivo lo standard POSIX.1 ha introdotto la funzione
+\funcd{waitpid} che effettua lo stesso servizio, ma dispone di una serie di
+funzionalità più ampie, legate anche al controllo di sessione (si veda
\secref{sec:sess_job_control}). Dato che è possibile ottenere lo stesso
comportamento di \func{wait} si consiglia di utilizzare sempre questa
funzione, il cui prototipo è:
\hline
$<-1$& -- & attende per un figlio il cui \textit{process group} (vedi
\secref{sec:sess_proc_group}) è uguale al
- valore assoluto di \var{pid}. \\
+ valore assoluto di \param{pid}. \\
$-1$ & \const{WAIT\_ANY} & attende per un figlio qualsiasi, usata in
questa maniera è equivalente a \func{wait}.\\
$0$ & \const{WAIT\_MYPGRP} & attende per un figlio il cui \textit{process
group} è uguale a quello del processo chiamante. \\
$>0$ & -- &attende per un figlio il cui \acr{pid} è uguale al
- valore di \var{pid}.\\
+ valore di \param{pid}.\\
\hline
\end{tabular}
- \caption{Significato dei valori del parametro \var{pid} della funzione
+ \caption{Significato dei valori dell'argomento \param{pid} della funzione
\func{waitpid}.}
\label{tab:proc_waidpid_pid}
\end{table}
In genere in un programma non si vuole essere forzati ad attendere la
conclusione di un processo per proseguire, specie se tutto questo serve solo
-per leggerne lo stato di chiusura (ed evitare la presenza di \textit{zombie}),
-per questo la modalità più usata per chiamare queste funzioni è quella di
-utilizzarle all'interno di un \textit{signal handler} (vedremo un esempio di
-come gestire \const{SIGCHLD} con i segnali in \secref{sec:sig_example}). In
-questo caso infatti, dato che il segnale è generato dalla terminazione di un
-figlio, avremo la certezza che la chiamata a \func{wait} non si bloccherà.
+per leggerne lo stato di chiusura (ed evitare la presenza di
+\textit{zombie}\index{zombie}), per questo la modalità più usata per chiamare
+queste funzioni è quella di utilizzarle all'interno di un \textit{signal
+ handler} (vedremo un esempio di come gestire \const{SIGCHLD} con i segnali
+in \secref{sec:sig_example}). In questo caso infatti, dato che il segnale è
+generato dalla terminazione di un figlio, avremo la certezza che la chiamata a
+\func{wait} non si bloccherà.
\begin{table}[!htb]
\centering
analizzare lo stato di uscita. Esse sono definite sempre in
\file{<sys/wait.h>} ed elencate in \tabref{tab:proc_status_macro} (si tenga
presente che queste macro prendono come parametro la variabile di tipo
-\ctyp{int} puntata da \var{status}).
+\ctyp{int} puntata da \param{status}).
Si tenga conto che nel caso di conclusione anomala il valore restituito da
\val{WTERMSIG} può essere confrontato con le costanti definite in
\label{sec:proc_wait4}
Linux, seguendo un'estensione di BSD, supporta altre due funzioni per la
-lettura dello stato di terminazione di un processo \func{wait3} e
-\func{wait4}, analoghe alle precedenti ma che prevedono un ulteriore
-parametro attraverso il quale il kernel può restituire al padre informazioni
-sulle risorse usate dal processo terminato e dai vari figli. I prototipi di
-queste funzioni, che diventano accessibili definendo la costante
-\macro{\_USE\_BSD}, sono:
+lettura dello stato di terminazione di un processo, analoghe alle precedenti
+ma che prevedono un ulteriore parametro attraverso il quale il kernel può
+restituire al padre informazioni sulle risorse usate dal processo terminato e
+dai vari figli. Le due funzioni sono \funcd{wait3} e \funcd{wait4}, che
+diventano accessibili definendo la macro \macro{\_USE\_BSD}; i loro prototipi
+sono:
\begin{functions}
\headdecl{sys/times.h} \headdecl{sys/types.h} \headdecl{sys/wait.h}
\headdecl{sys/resource.h}
ormai deprecata in favore di \func{wait4}.
\end{functions}
\noindent
-la struttura \type{rusage} è definita in \file{sys/resource.h}, e viene
+la struttura \struct{rusage} è definita in \file{sys/resource.h}, e viene
utilizzata anche dalla funzione \func{getrusage} (vedi
\secref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un
processo; la sua definizione è riportata in \figref{fig:sys_rusage_struct}.
Ci sono sei diverse versioni di \func{exec} (per questo la si è chiamata
famiglia di funzioni) che possono essere usate per questo compito, in realtà
(come mostrato in \figref{fig:proc_exec_relat}), sono tutte un front-end a
-\func{execve}. Il prototipo di quest'ultima è:
+\funcd{execve}. Il prototipo di quest'ultima è:
\begin{prototype}{unistd.h}
{int execve(const char *filename, char *const argv[], char *const envp[])}
Esegue il programma contenuto nel file \param{filename}.
interprete.
\item[\errcode{ELIBBAD}] Un interprete ELF non è in un formato
riconoscibile.
+ \item[\errcode{E2BIG}] La lista degli argomenti è troppo grande.
\end{errlist}
ed inoltre anche \errval{EFAULT}, \errval{ENOMEM}, \errval{EIO},
- \errval{ENAMETOOLONG}, \errval{E2BIG}, \errval{ELOOP}, \errval{ENOTDIR},
- \errval{ENFILE}, \errval{EMFILE}.}
+ \errval{ENAMETOOLONG}, \errval{ELOOP}, \errval{ENOTDIR}, \errval{ENFILE},
+ \errval{EMFILE}.}
\end{prototype}
La funzione \func{exec} esegue il file o lo script indicato da
-\var{filename}, passandogli la lista di argomenti indicata da \var{argv}
-e come ambiente la lista di stringhe indicata da \var{envp}; entrambe le
+\param{filename}, passandogli la lista di argomenti indicata da \param{argv}
+e come ambiente la lista di stringhe indicata da \param{envp}; entrambe le
liste devono essere terminate da un puntatore nullo. I vettori degli
argomenti e dell'ambiente possono essere acceduti dal nuovo programma
quando la sua funzione \func{main} è dichiarata nella forma
riferimento allo specchietto riportato in \tabref{tab:proc_exec_scheme}. La
prima differenza riguarda le modalità di passaggio dei parametri che poi
andranno a costituire gli argomenti a linea di comando (cioè i valori di
-\var{argv} e \var{argc} visti dalla funzione \func{main} del programma
+\param{argv} e \param{argc} visti dalla funzione \func{main} del programma
chiamato).
Queste modalità sono due e sono riassunte dagli mnemonici \code{v} e \code{l}
La seconda differenza fra le funzioni riguarda le modalità con cui si
specifica il programma che si vuole eseguire. Con lo mnemonico \code{p} si
indicano le due funzioni che replicano il comportamento della shell nello
-specificare il comando da eseguire; quando il parametro \var{file} non
+specificare il comando da eseguire; quando il parametro \param{file} non
contiene una \file{/} esso viene considerato come un nome di programma, e
viene eseguita automaticamente una ricerca fra i file presenti nella lista di
directory specificate dalla variabile di ambiente \var{PATH}. Il file che
\errcode{EACCES}.
Le altre quattro funzioni si limitano invece a cercare di eseguire il file
-indicato dal parametro \var{path}, che viene interpretato come il
+indicato dall'argomento \param{path}, che viene interpretato come il
\textit{pathname} del programma.
\begin{figure}[htb]
programmi in cui ci sia necessità, di dare a qualunque utente normale
privilegi o permessi di un'altro (o dell'amministratore).
-Come nel caso del \acr{pid} e del \acr{ppid} tutti questi identificatori
-possono essere letti dal processo attraverso delle opportune funzioni, i cui
-prototipi sono i seguenti:
+Come nel caso del \acr{pid} e del \acr{ppid}, anche tutti questi
+identificatori possono essere letti attraverso le rispettive funzioni:
+\funcd{getuid}, \funcd{geteuid}, \funcd{getgid} e \funcd{getegid}, i loro
+prototipi sono:
\begin{functions}
\headdecl{unistd.h}
\headdecl{sys/types.h}
\label{sec:proc_setuid}
Le due funzioni che vengono usate per cambiare identità (cioè utente e gruppo
-di appartenenza) ad un processo sono rispettivamente \func{setuid} e
-\func{setgid}; come accennato in \secref{sec:proc_access_id} in Linux esse
+di appartenenza) ad un processo sono rispettivamente \funcd{setuid} e
+\funcd{setgid}; come accennato in \secref{sec:proc_access_id} in Linux esse
seguono la semantica POSIX che prevede l'esistenza dell'\textit{userid
salvato} e del \textit{groupid salvato}; i loro prototipi sono:
\begin{functions}
L'effetto della chiamata è diverso a seconda dei privilegi del processo; se
l'\textsl{userid effettivo} è zero (cioè è quello dell'amministratore di
sistema) allora tutti gli identificatori (\textit{real}, \textit{effective} e
-\textit{saved}) vengono impostati al valore specificato da \var{uid},
+\textit{saved}) vengono impostati al valore specificato da \param{uid},
altrimenti viene impostato solo l'\textsl{userid effettivo}, e soltanto se il
valore specificato corrisponde o all'\textsl{userid reale} o
all'\textsl{userid salvato}. Negli altri casi viene segnalato un errore (con
\funcdecl{int setreuid(uid\_t ruid, uid\_t euid)} Imposta l'\textsl{userid
reale} e l'\textsl{userid effettivo} del processo corrente ai valori
-specificati da \var{ruid} e \var{euid}.
+specificati da \param{ruid} e \param{euid}.
\funcdecl{int setregid(gid\_t rgid, gid\_t egid)} Imposta il \textsl{groupid
reale} ed il \textsl{groupid effettivo} del processo corrente ai valori
-specificati da \var{rgid} e \var{egid}.
+specificati da \param{rgid} e \param{egid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
di fallimento: l'unico errore possibile è \errval{EPERM}.}
dell'userid effettivo.
-\subsection{Le funzioni \func{seteuid} e \func{setegid}}
+\subsection{Le funzioni \funcd{seteuid} e \funcd{setegid}}
\label{sec:proc_seteuid}
Queste funzioni sono un'estensione allo standard POSIX.1 (ma sono comunque
\headdecl{sys/types.h}
\funcdecl{int seteuid(uid\_t uid)} Imposta l'userid effettivo del processo
-corrente a \var{uid}.
+corrente a \param{uid}.
\funcdecl{int setegid(gid\_t gid)} Imposta il groupid effettivo del processo
-corrente a \var{gid}.
+corrente a \param{gid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
di fallimento: l'unico errore è \errval{EPERM}.}
normale di \func{setuid} comporta l'impostazione di tutti gli identificatori.
-\subsection{Le funzioni \func{setresuid} e \func{setresgid}}
+\subsection{Le funzioni \funcd{setresuid} e \funcd{setresgid}}
\label{sec:proc_setresuid}
Queste due funzioni sono un'estensione introdotta in Linux dal kernel 2.1.44,
\headdecl{sys/types.h}
\funcdecl{int setresuid(uid\_t ruid, uid\_t euid, uid\_t suid)} Imposta
-l'userid reale, l'userid effettivo e l'userid salvato del processo corrente
-ai valori specificati rispettivamente da \var{ruid}, \var{euid} e \var{suid}.
+l'userid reale, l'userid effettivo e l'userid salvato del processo corrente ai
+valori specificati rispettivamente da \param{ruid}, \param{euid} e
+\param{suid}.
\funcdecl{int setresgid(gid\_t rgid, gid\_t egid, gid\_t sgid)} Imposta il
groupid reale, il groupid effettivo ed il groupid salvato del processo
-corrente ai valori specificati rispettivamente da \var{rgid}, \var{egid} e
-\var{sgid}.
+corrente ai valori specificati rispettivamente da \param{rgid}, \param{egid} e
+\param{sgid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
di fallimento: l'unico errore è \errval{EPERM}.}
lascia inalterato l'identificatore corrispondente.
Per queste funzioni esistono anche due controparti che permettono di leggere
-in blocco i vari identificatori: \func{getresuid} e \func{getresgid}; i loro
+in blocco i vari identificatori: \funcd{getresuid} e \funcd{getresgid}; i loro
prototipi sono:
\begin{functions}
\headdecl{unistd.h}
controlli di accesso, così che l'utente non possa inviare segnali al server
NFS.
-Le due funzioni usate per cambiare questi identificatori sono \func{setfsuid}
-e \func{setfsgid}, ovviamente sono specifiche di Linux e non devono essere
+Le due funzioni usate per cambiare questi identificatori sono \funcd{setfsuid}
+e \funcd{setfsgid}, ovviamente sono specifiche di Linux e non devono essere
usate se si intendono scrivere programmi portabili; i loro prototipi sono:
\begin{functions}
\headdecl{sys/fsuid.h}
\funcdecl{int setfsuid(uid\_t fsuid)} Imposta l'userid di filesystem del
-processo corrente a \var{fsuid}.
+processo corrente a \param{fsuid}.
\funcdecl{int setfsgid(gid\_t fsgid)} Imposta il groupid di filesystem del
-processo corrente a \var{fsgid}.
+processo corrente a \param{fsgid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
di fallimento: l'unico errore possibile è \errval{EPERM}.}
gruppi supplementari in aggiunta al gruppo primario, questi vengono ereditati
dal processo padre e possono essere cambiati con queste funzioni.
-La funzione che permette di leggere i gruppi supplementari è \func{getgroups};
-questa funzione è definita nello standard POSIX ed il suo prototipo è:
+La funzione che permette di leggere i gruppi supplementari è
+\funcd{getgroups}; questa funzione è definita nello standard POSIX ed il suo
+prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{unistd.h}
- \funcdecl{int getgroups(int size, gid\_t list[])} Legge gli identificatori
- dei gruppi supplementari del processo sul vettore \param{list} di dimensione
- \param{size}.
+ \funcdecl{int getgroups(int size, gid\_t list[])}
+
+ Legge gli identificatori dei gruppi supplementari.
\bodydesc{La funzione restituisce il numero di gruppi letti in caso di
successo e -1 in caso di fallimento, nel qual caso \var{errno} assumerà
minore del numero di gruppi supplementari del processo.
\end{errlist}}
\end{functions}
-\noindent non è specificato se la funzione inserisca o meno nella lista
-il groupid effettivo del processo. Se si specifica un valore di \param{size}
-uguale a 0 \param{list} non viene modificato, ma si ottiene il numero di
-gruppi supplementari.
-Una seconda funzione, \func{getgrouplist}, può invece essere usata per
+La funzione legge gli identificatori dei gruppi supplementari del processo sul
+vettore \param{list} di dimensione \param{size}. Non è specificato se la
+funzione inserisca o meno nella lista il groupid effettivo del processo. Se si
+specifica un valore di \param{size} uguale a 0 \param{list} non viene
+modificato, ma si ottiene il numero di gruppi supplementari.
+
+Una seconda funzione, \funcd{getgrouplist}, può invece essere usata per
ottenere tutti i gruppi a cui appartiene un utente; il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{grp.h}
\funcdecl{int getgrouplist(const char *user, gid\_t group, gid\_t *groups,
- int *ngroups)} Legge i gruppi supplementari dell'utente \param{user}.
+ int *ngroups)} Legge i gruppi supplementari.
\bodydesc{La funzione legge fino ad un massimo di \param{ngroups} valori,
restituisce 0 in caso di successo e -1 in caso di fallimento.}
\end{functions}
-\noindent la funzione esegue una scansione del database dei gruppi (si veda
-\secref{sec:sys_user_group}) e ritorna in \param{groups} la lista di quelli a
-cui l'utente appartiene. Si noti che \param{ngroups} è passato come puntatore
-perché qualora il valore specificato sia troppo piccolo la funzione ritorna
--1, passando indietro il numero dei gruppi trovati.
+
+La funzione legge i gruppi supplementari dell'utente \param{user} eseguendo
+una scansione del database dei gruppi (si veda \secref{sec:sys_user_group}) e
+ritorna in \param{groups} la lista di quelli a cui l'utente appartiene. Si
+noti che \param{ngroups} è passato come puntatore perché qualora il valore
+specificato sia troppo piccolo la funzione ritorna -1, passando indietro il
+numero dei gruppi trovati.
Per impostare i gruppi supplementari di un processo ci sono due funzioni, che
possono essere usate solo se si hanno i privilegi di amministratore. La prima
-delle due è \func{setgroups}, ed il suo prototipo è:
+delle due è \funcd{setgroups}, ed il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{grp.h}
- \funcdecl{int setgroups(size\_t size, gid\_t *list)} Imposta i gruppi
- supplementari del processo ai valori specificati in \param{list}.
+ \funcdecl{int setgroups(size\_t size, gid\_t *list)}
+
+ Imposta i gruppi supplementari del processo.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
fallimento, nel qual caso \var{errno} assumerà i valori:
\item[\errcode{EFAULT}] \param{list} non ha un indirizzo valido.
\item[\errcode{EPERM}] il processo non ha i privilegi di amministratore.
\item[\errcode{EINVAL}] il valore di \param{size} è maggiore del valore
- massimo (\const{NGROUPS}, che per Linux è 32).
+ massimo consentito.
\end{errlist}}
\end{functions}
+La funzione imposta i gruppi supplementari del processo corrente ai valori
+specificati nel vettore passato con l'argomento \param{list}, di dimensioni
+date dall'argomento \param{size}. Il numero massimo di gruppi supplementari è
+un parametro di sistema, che può essere ricavato con le modalità spiegate in
+\secref{sec:sys_characteristics}.
+
Se invece si vogliono impostare i gruppi supplementari del processo a quelli di
-un utente specifico, si può usare \func{initgroups} il cui prototipo è:
+un utente specifico, si può usare \funcd{initgroups} il cui prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{grp.h}
- \funcdecl{int initgroups(const char *user, gid\_t group)} Imposta i gruppi
- supplementari del processo a quelli di cui è membro l'utente \param{user},
- aggiungendo il gruppo addizionale \param{group}.
+ \funcdecl{int initgroups(const char *user, gid\_t group)}
+
+ Inizializza la lista dei gruppi supplementari.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
fallimento, nel qual caso \var{errno} assumerà gli stessi valori di
\end{functions}
La funzione esegue la scansione del database dei gruppi (usualmente
-\file{/etc/groups}) cercando i gruppi di cui è membro \param{user} e
-costruendo una lista di gruppi supplementari a cui aggiunge \param{group}, che
-poi imposta usando \func{setgroups}.
-Si tenga presente che sia \func{setgroups} che \func{initgroups} non sono
-definite nello standard POSIX.1 e che pertanto non è possibile utilizzarle
-quando si definisce \macro{\_POSIX\_SOURCE} o si compila con il flag
-\cmd{-ansi}.
+\file{/etc/groups}) cercando i gruppi di cui è membro l'utente \param{user}
+con cui costruisce una lista di gruppi supplementari, a cui aggiunge anche
+\param{group}, infine imposta questa lista per il processo corrente usando
+\func{setgroups}. Si tenga presente che sia \func{setgroups} che
+\func{initgroups} non sono definite nello standard POSIX.1 e che pertanto non
+è possibile utilizzarle quando si definisce \macro{\_POSIX\_SOURCE} o si
+compila con il flag \cmd{-ansi}.
\section{La gestione della priorità di esecuzione}
\textbf{Stato} & \texttt{STAT} & \textbf{Descrizione} \\
\hline
\hline
- \textbf{Runnable} & \texttt{R} & Il processo è in esecuzione o è pronto ad
- essere eseguito (cioè è in attesa che gli venga assegnata la CPU). \\
- \textbf{Sleep} & \texttt{S} & Il processo processo è in attesa di un
- risposta dal sistema, ma può essere interrotto da un segnale. \\
- \textbf{Uninterrutible Sleep} & \texttt{D} & Il processo è in
- attesa di un risposta dal sistema (in genere per I/O), e non può essere
- interrotto in nessuna circostanza. \\
+ \textbf{Runnable}& \texttt{R} & Il processo è in esecuzione o è pronto ad
+ essere eseguito (cioè è in attesa che gli
+ venga assegnata la CPU). \\
+ \textbf{Sleep} & \texttt{S} & Il processo processo è in attesa di un
+ risposta dal sistema, ma può essere
+ interrotto da un segnale. \\
+ \textbf{Uninterrutible Sleep}& \texttt{D} & Il processo è in
+ attesa di un risposta dal sistema (in
+ genere per I/O), e non può essere
+ interrotto in nessuna circostanza. \\
\textbf{Stopped} & \texttt{T} & Il processo è stato fermato con un
- \const{SIGSTOP}, o è tracciato.\\
- \textbf{Zombie} & \texttt{Z} & Il processo è terminato ma il suo stato di
- terminazione non è ancora stato letto dal padre. \\
+ \const{SIGSTOP}, o è tracciato.\\
+ \textbf{Zombie}\index{zombie} & \texttt{Z} & Il processo è terminato ma il
+ suo stato di terminazione non è ancora
+ stato letto dal padre. \\
\hline
\end{tabular}
\caption{Elenco dei possibili stati di un processo in Linux, nella colonna
una fetta) per il quale esso deve essere eseguito. Il valore della
\textit{time-slice} è controllato dalla cosiddetta \textit{nice} (o
\textit{niceness}) del processo. Essa è contenuta nel campo \var{nice} di
-\var{task\_struct}; tutti i processi vengono creati con lo stesso valore, ed
-essa specifica il valore della durata iniziale della \textit{time-slice} che
-viene assegnato ad un altro campo della struttura (\var{counter}) quando il
-processo viene eseguito per la prima volta e diminuito progressivamente ad
+\struct{task\_struct}; tutti i processi vengono creati con lo stesso valore,
+ed essa specifica il valore della durata iniziale della \textit{time-slice}
+che viene assegnato ad un altro campo della struttura (\var{counter}) quando
+il processo viene eseguito per la prima volta e diminuito progressivamente ad
ogni interruzione del timer.
Quando lo scheduler\index{scheduler} viene eseguito scandisce la coda dei
processo, come misura di cortesia nei confronti degli altri. I processi
infatti vengono creati dal sistema con lo stesso valore di \var{nice} (nullo)
e nessuno è privilegiato rispetto agli altri; il valore può essere modificato
-solo attraverso la funzione \func{nice}, il cui prototipo è:
+solo attraverso la funzione \funcd{nice}, il cui prototipo è:
\begin{prototype}{unistd.h}
{int nice(int inc)}
Aumenta il valore di \var{nice} per il processo corrente.
In SUSv2 la funzione ritorna il nuovo valore di \var{nice}; Linux non segue
questa convenzione, e per leggere il nuovo valore occorre invece usare la
-funzione \func{getpriority}, derivata da BSD, il cui prototipo è:
+funzione \funcd{getpriority}, derivata da BSD, il cui prototipo è:
\begin{prototype}{sys/resource.h}
{int getpriority(int which, int who)}
prima della chiamata alla funzione, per verificare che essa resti uguale a
zero.
-Analoga a \func{getpriority} la funzione \func{setpriority} permette di
+Analoga a \func{getpriority} la funzione \funcd{setpriority} permette di
impostare la priorità di uno o più processi; il suo prototipo è:
\begin{prototype}{sys/resource.h}
{int setpriority(int which, int who, int prio)}
\end{basedescript}
La funzione per impostare le politiche di scheduling (sia real-time che
-ordinarie) ed i relativi parametri è \func{sched\_setscheduler}; il suo
+ordinarie) ed i relativi parametri è \funcd{sched\_setscheduler}; il suo
prototipo è:
\begin{prototype}{sched.h}
{int sched\_setscheduler(pid\_t pid, int policy, const struct sched\_param *p)}
- Imposta priorità e politica di scheduling per il processo \param{pid}.
-
- \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso di
- errore, nel qual caso \var{errno} può assumere i valori:
+ Imposta priorità e politica di scheduling.
+
+ \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso
+ di errore, nel qual caso \var{errno} può assumere i valori:
\begin{errlist}
\item[\errcode{ESRCH}] il processo \param{pid} non esiste.
- \item[\errcode{EINVAL}] il valore di \param{policy} non esiste o il relativo
- valore di \param{p} non è valido.
+ \item[\errcode{EINVAL}] il valore di \param{policy} non esiste o il
+ relativo valore di \param{p} non è valido.
\item[\errcode{EPERM}] il processo non ha i privilegi per attivare la
politica richiesta (vale solo per \const{SCHED\_FIFO} e
\const{SCHED\_RR}).
\end{errlist}}
\end{prototype}
-La funzione esegue l'impostazione per il processo specificato; un valore nullo
-di \param{pid} esegue l'impostazione per il processo corrente, solo un
-processo con i privilegi di amministratore può impostare delle priorità
-assolute diverse da zero. La politica di scheduling è specificata
+La funzione esegue l'impostazione per il processo specificato dall'argomento
+\param{pid}; un valore nullo esegue l'impostazione per il processo corrente.
+Solo un processo con i privilegi di amministratore può impostare delle
+priorità assolute diverse da zero. La politica di scheduling è specificata
dall'argomento \param{policy} i cui possibili valori sono riportati in
\tabref{tab:proc_sched_policy}; un valore negativo per \param{policy} mantiene
la politica di scheduling corrente.
\label{tab:proc_sched_policy}
\end{table}
-Il valore della priorità è passato attraverso la struttura \var{sched\_param}
-(riportata in \figref{fig:sig_sched_param}), il cui solo campo attualmente
-definito è \var{sched\_priority}, che nel caso delle priorità assolute deve
-essere specificato nell'intervallo fra un valore massimo ed uno minimo, che
-nel caso sono rispettivamente 1 e 99 (il valore zero è legale, ma indica i
-processi normali).
+Il valore della priorità è passato attraverso la struttura
+\struct{sched\_param} (riportata in \figref{fig:sig_sched_param}), il cui solo
+campo attualmente definito è \var{sched\_priority}, che nel caso delle
+priorità assolute deve essere specificato nell'intervallo fra un valore
+massimo ed uno minimo, che nel caso sono rispettivamente 1 e 99 (il valore
+zero è legale, ma indica i processi normali).
\begin{figure}[!htb]
\footnotesize \centering
\end{lstlisting}
\end{minipage}
\normalsize
- \caption{La struttura \var{sched\_param}.}
+ \caption{La struttura \structd{sched\_param}.}
\label{fig:sig_sched_param}
\end{figure}
-
-
Lo standard POSIX.1b prevede comunque che i due valori della massima e minima
priorità statica possano essere ottenuti, per ciascuna delle politiche di
-scheduling realtime, tramite le due funzioni \func{sched\_get\_priority\_max}
-e \func{sched\_get\_priority\_min}, i cui prototipi sono:
+scheduling realtime, tramite le due funzioni \funcd{sched\_get\_priority\_max}
+e \funcd{sched\_get\_priority\_min}, i cui prototipi sono:
\begin{functions}
\headdecl{sched.h}
nel caso che esso sia stato interrotto da un processo a priorità più alta.
La priorità assoluta può essere riletta indietro dalla funzione
-\func{sched\_getscheduler}, il cui prototipo è:
+\funcd{sched\_getscheduler}, il cui prototipo è:
\begin{prototype}{sched.h}
{int sched\_getscheduler(pid\_t pid)}
Legge la politica di scheduling per il processo \param{pid}.
chiamante.
Se si intende operare solo sulla priorità assoluta di un processo si possono
-usare le funzioni \func{sched\_setparam} e \func{sched\_getparam}, i cui
+usare le funzioni \funcd{sched\_setparam} e \funcd{sched\_getparam}, i cui
prototipi sono:
-
\begin{functions}
\headdecl{sched.h}
definita nell'header \file{sched.h}.
L'ultima funzione che permette di leggere le informazioni relative ai processi
-real-time è \func{sched\_rr\_get\_interval}, che permette di ottenere la
+real-time è \funcd{sched\_rr\_get\_interval}, che permette di ottenere la
lunghezza della \textit{time slice} usata dalla politica \textit{round robin};
il suo prototipo è:
\begin{prototype}{sched.h}
\end{prototype}
La funzione restituisce il valore dell'intervallo di tempo usato per la
-politica \textit{round robin} in una struttura \var{timespec}, (la cui
+politica \textit{round robin} in una struttura \struct{timespec}, (la cui
definizione si può trovare in \figref{fig:sys_timeval_struct}).
Come accennato ogni processo che usa lo scheduling real-time può rilasciare
volontariamente la CPU; questo viene fatto attraverso la funzione
-\func{sched\_yield}, il cui prototipo è:
+\funcd{sched\_yield}, il cui prototipo è:
\begin{prototype}{sched.h}
{int sched\_yield(void)}
atomici. Non è affatto detto che lo stesso valga per interi di dimensioni
maggiori (in cui l'accesso può comportare più istruzioni in assembler) o per
le strutture. In tutti questi casi è anche opportuno marcare come
-\ctyp{volatile} le variabili che possono essere interessate ad accesso
+\direct{volatile} le variabili che possono essere interessate ad accesso
condiviso, onde evitare problemi con le ottimizzazioni del codice.
\subsection{Le \textit{race condition}\index{race condition} e i
- \textit{deadlock}}
+ \textit{deadlock}\index{deadlock}}
\label{sec:proc_race_cond}
Si definiscono \textit{race condition} tutte quelle situazioni in cui processi
problematiche di questo tipo in \capref{cha:IPC}).
Un caso particolare di \textit{race condition} sono poi i cosiddetti
-\textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco
-completo di un servizio, e non il fallimento di una singola operazione. Per
-definizione un \textit{deadlock} è una situazione in cui due o più processi
-non sono più in grado di proseguire perché ciascuno aspetta il risultato di
-una operazione che dovrebbe essere eseguita dall'altro.
-
-
-L'esempio tipico di una situazione che può condurre ad un \textit{deadlock} è
-quello in cui un flag di ``occupazione'' viene rilasciato da un evento
-asincrono (come un segnale o un altro processo) fra il momento in cui lo si è
-controllato (trovandolo occupato) e la successiva operazione di attesa per lo
-sblocco. In questo caso, dato che l'evento di sblocco del flag è avvenuto
-senza che ce ne accorgessimo proprio fra il controllo e la messa in attesa,
-quest'ultima diventerà perpetua (da cui il nome di \textit{deadlock}).
+\textit{deadlock}\index{deadlock}, particolarmente gravi in quanto comportano
+spesso il blocco completo di un servizio, e non il fallimento di una singola
+operazione. Per definizione un \textit{deadlock}\index{deadlock} è una
+situazione in cui due o più processi non sono più in grado di proseguire
+perché ciascuno aspetta il risultato di una operazione che dovrebbe essere
+eseguita dall'altro.
+
+
+L'esempio tipico di una situazione che può condurre ad un
+\textit{deadlock}\index{deadlock} è quello in cui un flag di ``occupazione''
+viene rilasciato da un evento asincrono (come un segnale o un altro processo)
+fra il momento in cui lo si è controllato (trovandolo occupato) e la
+successiva operazione di attesa per lo sblocco. In questo caso, dato che
+l'evento di sblocco del flag è avvenuto senza che ce ne accorgessimo proprio
+fra il controllo e la messa in attesa, quest'ultima diventerà perpetua (da cui
+il nome di \textit{deadlock}\index{deadlock}).
In tutti questi casi è di fondamentale importanza il concetto di atomicità
visto in \secref{sec:proc_atom_oper}; questi problemi infatti possono essere
un altro thread di esecuzione senza che questo comporti nessun problema
nell'esecuzione della stessa. La problematica è comune nella programmazione
multi-thread, ma si hanno gli stessi problemi quando si vogliono chiamare
-delle funzioni all'interno dei manipolatori dei segnali.
+delle funzioni all'interno dei gestori dei segnali.
Fintanto che una funzione opera soltanto con le variabili locali è rientrante;
queste infatti vengono allocate nello stack, e un'altra invocazione non fa