gestione.
-\subsection{La gerarchia dei processi}
+\subsection{L'architettura della gestione dei processi}
\label{sec:proc_hierarchy}
A differenza di quanto avviene in altri sistemi (ad esempio nel VMS la
alla cui base c'è \cmd{init} che è progenitore di tutti gli altri processi.
-\subsection{Una panoramica sulle funzioni di gestione}
+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
+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ù
+riprese), è mostrato in \nfig.
+
+\begin{figure}[htb]
+ \centering
+ \includegraphics[width=13cm]{img/task_struct}
+ \caption{Schema semplificato dell'architettura delle strutture usate dal
+ kernel nella gestione dei processi.}
+ \label{fig:proc_task_struct}
+\end{figure}
+
+
+Come accennato in \secref{sec:intro_unix_struct} è lo \textit{scheduler} che
+decide quale processo mettere in esecuzione; esso viene eseguito ad ogni
+system call ed ad ogni interrupt, (ma può essere anche attivato
+esplicitamente). Il timer di sistema provvede comunque a che esso sia invocato
+periodicamente, generando un interrupt periodico secondo la frequenza
+specificata dalla costante \macro{HZ}, definita in \file{asm/param.h} Il
+valore usuale è 100 (è espresso in Hertz), si ha cioè un interrupt dal timer
+ogni centesimo di secondo.
+
+Ogni volta che viene eseguito, lo \textit{scheduler} effettua il calcolo delle
+priorità dei vari processi attivi (torneremo su questo in
+\secref{sec:proc_priority}) e stabilisce quale di essi debba essere posto in
+esecuzione fino alla successiva invocazione.
+
+
+\subsection{Una panoramica sulle funzioni fondamentali}
\label{sec:proc_handling_intro}
I processi vengono creati dalla funzione \func{fork}; in molti unix questa è
-\section{La gestione dei processi}
+\section{Le funzioni di base}% della gestione dei processi}
\label{sec:proc_handling}
In questa sezione tratteremo le problematiche della gestione dei processi
all'interno del sistema, illustrandone tutti i dettagli. Inizieremo con le
funzioni elementari che permettono di leggerne gli identificatori, per poi
-passare alla spiegazione delle funzioni fondamentali che si usano per la
-creazione e la terminazione dei processi, e per la messa in esecuzione degli
-altri programmi.
+passare alla spiegazione delle funzioni base che si usano per la creazione e
+la terminazione dei processi, e per la messa in esecuzione degli altri
+programmi.
\subsection{Gli identificatori dei processi}
\item gli identificatori per il controllo di sessione: il \textit{process
group id} e il \textit{session id} ed il terminale di controllo (vedi
\secref{sec:sess_xxx} e \secref{sec:sess_xxx}).
-\item i flag di \acr{suid} e \acr{sgid} (vedi \secref{sec:file_suid_sgid}).
+\item gli identificatori per il controllo di accesso (vedi
+ \secref{sec:proc_user_group}).
\item la directory di lavoro e la directory radice (vedi
\secref{sec:file_work_dir} e \secref{sec:file_chroot}).
\item la maschera dei permessi di creazione (vedi \secref{sec:file_umask}).
Sospende il processo corrente finché un figlio non è uscito, o finché un
segnale termina il processo o chiama una funzione di gestione.
-\bodydesc{
-La funzione restituisce il \acr{pid} del figlio in caso di successo e -1 in
-caso di errore; \var{errno} può assumere i valori:
+\bodydesc{La funzione restituisce il \acr{pid} del figlio in caso di successo
+ e -1 in caso di errore; \var{errno} può assumere i valori:
\begin{errlist}
\item[\macro{EINTR}] la funzione è stata interrotta da un segnale.
- \end{errlist}
-}
+ \end{errlist}}
\end{functions}
\noindent
è presente fin dalle prime versioni di unix; la funzione ritorna non appena un
\end{functions}
\noindent
la struttura \type{rusage} è definita in \file{sys/resource.h}, e viene
-utilizzata anche dalla funzione \func{getrusage} per ottenere le risorse di
-sistema usate dal processo; la sua definizione è riportata in \nfig.
-\begin{figure}[!htb]
- \footnotesize
- \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
-struct rusage {
- struct timeval ru_utime; /* user time used */
- struct timeval ru_stime; /* system time used */
- long ru_maxrss; /* maximum resident set size */
- long ru_ixrss; /* integral shared memory size */
- long ru_idrss; /* integral unshared data size */
- long ru_isrss; /* integral unshared stack size */
- long ru_minflt; /* page reclaims */
- long ru_majflt; /* page faults */
- long ru_nswap; /* swaps */
- long ru_inblock; /* block input operations */
- long ru_oublock; /* block output operations */
- long ru_msgsnd; /* messages sent */
- long ru_msgrcv; /* messages received */
- long ru_nsignals; ; /* signals received */
- long ru_nvcsw; /* voluntary context switches */
- long ru_nivcsw; /* involuntary context switches */
-};
- \end{lstlisting}
- \end{minipage}
- \normalsize
- \caption{La struttura \var{rusage} per la lettura delle informazioni dei
- delle risorse usate da un processo.}
- \label{fig:proc_rusage_struct}
-\end{figure}
+utilizzata anche dalla funzione \func{getrusage} (vedi \secref{sec:sys_xxx})
+per ottenere le risorse di sistema usate dal processo; la sua definizione è
+riportata in \figref{fig:sys_rusage_struct}.
In genere includere esplicitamente \file{<sys/time.h>} non è più
necessario, ma aumenta la portabilità, e serve in caso si debba accedere
\func{exec} assume anche una serie di altre proprietà del processo chiamante;
la lista completa è la seguente:
\begin{itemize*}
-\item il \textit{process ID} (\acr{pid}) ed il \textit{parent process ID}
+\item il \textit{process id} (\acr{pid}) ed il \textit{parent process id}
(\acr{ppid}).
-\item il \textit{real user ID} ed il \textit{real group ID} (vedi
+\item il \textit{real user id} ed il \textit{real group id} (vedi
\secref{sec:proc_user_group}).
-\item i \textit{supplementary group ID} (vedi \secref{sec:proc_user_group}).
-\item il \textit{session ID} ed il \textit{process group ID} (vedi
+\item i \textit{supplementary group id} (vedi \secref{sec:proc_user_group}).
+\item il \textit{session id} ed il \textit{process group id} (vedi
\secref{sec:sess_xxx}).
\item il terminale di controllo (vedi \secref{sec:sess_xxx}).
\item il tempo restante ad un allarme (vedi \secref{sec:sig_xxx}).
settaggio del flag di \textit{close-on-exec} sulle directory che apre, in
maniera trasparente all'utente.
-Abbiamo detto che il \textit{real user ID} ed il \textit{real group ID}
+Abbiamo detto che il \textit{real user id} ed il \textit{real group id}
restano gli stessi all'esecuzione di \func{exec}; lo stesso vale per
-l'\textit{effective user ID} ed l'\textit{effective group ID}, tranne il caso
+l'\textit{effective user id} ed l'\textit{effective group id}, tranne il caso
in cui il file che si va ad eseguire ha o il \acr{suid} bit o lo \acr{sgid}
-bit settato, nel qual caso \textit{effective user ID} e \textit{effective
- group ID} vengono settati rispettivamente all'utente o al gruppo cui il file
+bit settato, nel qual caso \textit{effective user id} e \textit{effective
+ group id} vengono settati rispettivamente all'utente o al gruppo cui il file
appartiene (per i dettagli vedi \secref{sec:proc_perms}).
Se il file da eseguire è in formato \emph{a.out} e necessita di librerie
\label{tab:proc_uid_gid}
\end{table}
-Al primo gruppo appartengono il \textit{real user ID} e il \textit{real group
- ID}: questi vengono settati al login ai valori corrispondenti all'utente con
+Al primo gruppo appartengono il \textit{real user id} e il \textit{real group
+ id}: questi vengono settati al login ai valori corrispondenti all'utente con
cui si accede al sistema (e relativo gruppo di default). Servono per
l'identificazione dell'utente e normalmente non vengono mai cambiati. In
realtà vedremo (in \secref{sec:proc_setuid}) che è possibile modificarli, ma
procedura di autenticazione lancia una shell per la quale setta questi
identificatori ai valori corrispondenti all'utente che entra nel sistema.
-Al secondo gruppo appartengono l'\textit{effective user ID} e
-l'\textit{effective group ID} (a cui si aggiungono gli eventuali
+Al secondo gruppo appartengono l'\textit{effective user id} e
+l'\textit{effective group id} (a cui si aggiungono gli eventuali
\textit{supplementary group id} dei gruppi dei quale l'utente fa parte).
Questi sono invece gli identificatori usati nella verifiche dei permessi del
processo e per il controllo di accesso ai file (argomento affrontato in
\begin{functions}
\headdecl{unistd.h}
\headdecl{sys/types.h}
- \funcdecl{uid\_t getuid(void)} Restituisce il \textit{real user ID} del
+ \funcdecl{uid\_t getuid(void)} Restituisce il \textit{real user id} del
processo corrente.
- \funcdecl{uid\_t geteuid(void)} Restituisce l'\textit{effective user ID} del
+ \funcdecl{uid\_t geteuid(void)} Restituisce l'\textit{effective user id} del
processo corrente.
- \funcdecl{gid\_t getgid(void)} Restituisce il \textit{real group ID} del
+ \funcdecl{gid\_t getgid(void)} Restituisce il \textit{real group id} del
processo corrente.
- \funcdecl{gid\_t getegid(void)} Restituisce l'\textit{effective group ID} del
+ \funcdecl{gid\_t getegid(void)} Restituisce l'\textit{effective group id} del
processo corrente.
\bodydesc{Queste funzioni non riportano condizioni di errore.}
\headdecl{sys/types.h}
\funcdecl{int setreuid(uid\_t ruid, uid\_t euid)} Setta il \textit{real user
- ID} e l'\textit{effective user ID} del processo corrente ai valori
+ id} e l'\textit{effective user id} del processo corrente ai valori
specificati da \var{ruid} e \var{euid}.
\funcdecl{int setregid(gid\_t rgid, gid\_t egid)} Setta il \textit{real group
- ID} e l'\textit{effective group ID} del processo corrente ai valori
+ id} e l'\textit{effective group id} del processo corrente ai valori
specificati da \var{rgid} e \var{egid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
\textit{saved id} viene sempre settato al valore dell'\textit{effective id}.
+
+\subsection{Le funzioni \func{seteuid} e \func{setegid}}
+\label{sec:proc_seteuid}
+
+Queste funzioni sono un'estensione allo standard POSIX.1 (ma sono comunque
+supportate dalla maggior parte degli Unix) e usate per cambiare gli
+\textit{effective id}; i loro prototipi sono:
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int seteuid(uid\_t uid)} Setta l'\textit{effective user id} del
+processo corrente a \var{uid}.
+
+\funcdecl{int setegid(gid\_t gid)} Setta l'\textit{effective group id} del
+processo corrente a \var{gid}.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+ di fallimento: l'unico errore possibile è \macro{EPERM}.}
+\end{functions}
+
+Gli utenti normali possono settare l'\textit{effective id} solo al valore del
+\textit{real id} o del \textit{saved id}, l'amministratore può specificare
+qualunque valore. Queste funzioni sono usate per permettere a root di settare
+solo l'\textit{effective id}, dato che l'uso normale di \func{setuid} comporta
+il settaggio di tutti gli identificatori.
+
+
\subsection{Le funzioni \func{setresuid} e \func{setresgid}}
\label{sec:proc_setresuid}
\headdecl{sys/types.h}
\funcdecl{int setresuid(uid\_t ruid, uid\_t euid, uid\_t suid)} Setta il
-\textit{real user ID}, l'\textit{effective user ID} e il \textit{saved user
- ID} del processo corrente ai valori specificati rispettivamente da
+\textit{real user id}, l'\textit{effective user id} e il \textit{saved user
+ id} del processo corrente ai valori specificati rispettivamente da
\var{ruid}, \var{euid} e \var{suid}.
\funcdecl{int setresgid(gid\_t rgid, gid\_t egid, gid\_t sgid)} Setta il
-\textit{real group ID}, l'\textit{effective group ID} e il \textit{saved group
- ID} del processo corrente ai valori specificati rispettivamente da
+\textit{real group id}, l'\textit{effective group id} e il \textit{saved group
+ id} del processo corrente ai valori specificati rispettivamente da
\var{rgid}, \var{egid} e \var{sgid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
valori che vuole; un valore di -1 per un qualunque parametro lascia inalterato
l'identificatore corrispondente.
-
-
-\subsection{Le funzioni \func{seteuid} e \func{setegid}}
-\label{sec:proc_seteuid}
-
-Queste funzioni sono un'estensione allo standard POSIX.1 (ma sono comunque
-supportate dalla maggior parte degli Unix) e usate per cambiare gli
-\textit{effective id}; i loro prototipi sono:
+Per queste funzioni esistono anche due controparti che permettono di leggere
+in blocco i vari identificatori: \func{getresuid} e \func{getresgid}; i loro
+prototipi sono:
\begin{functions}
\headdecl{unistd.h}
\headdecl{sys/types.h}
-\funcdecl{int seteuid(uid\_t uid)} Setta l'\textit{effective user ID} del
-processo corrente a \var{uid}.
-
-\funcdecl{int setegid(gid\_t gid)} Setta l'\textit{effective group ID} del
-processo corrente a \var{gid}.
+\funcdecl{int getresuid(uid\_t *ruid, uid\_t *euid, uid\_t *suid)} Legge il
+\textit{real user id}, l'\textit{effective user id} e il \textit{saved user
+ id} del processo corrente.
+
+\funcdecl{int getresgid(gid\_t *rgid, gid\_t *egid, gid\_t *sgid)} Legge il
+\textit{real group id}, l'\textit{effective group id} e il \textit{saved group
+ id} del processo corrente.
-\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
- di fallimento: l'unico errore possibile è \macro{EPERM}.}
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso di
+ fallimento: l'unico errore possibile è \macro{EFAULT} se gli indirizzi delle
+ variabili di ritorno non sono validi.}
\end{functions}
-Gli utenti normali possono settare l'\textit{effective id} solo al valore del
-\textit{real id} o del \textit{saved id}, l'amministratore può specificare
-qualunque valore. Queste funzioni sono usate per permettere a root di settare
-solo l'\textit{effective id}, dato che l'uso normale di \func{setuid} comporta
-il settaggio di tutti gli identificatori.
-
+Anche queste funzioni sono una estensione specifica di Linux, e non richiedono
+nessun privilegio. I valori sono restituiti negli argomenti, che vanno
+specificati come puntatori (è un'altro esempio di \textit{value result
+ argument}). Si noti che queste funzioni sono le uniche in grado di leggere i
+\textit{saved id}.
+
\subsection{Le funzioni \func{setfsuid} e \func{setfsgid}}
\label{sec:proc_setfsuid}
\begin{functions}
\headdecl{sys/fsuid.h}
-\funcdecl{int setfsuid(uid\_t fsuid)} Setta il \textit{filesystem user ID} del
+\funcdecl{int setfsuid(uid\_t fsuid)} Setta il \textit{filesystem user id} del
processo corrente a \var{fsuid}.
-\funcdecl{int setfsgid(gid\_t fsgid)} Setta l'\textit{filesystem group ID} del
+\funcdecl{int setfsgid(gid\_t fsgid)} Setta l'\textit{filesystem group id} del
processo corrente a \var{fsgid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
coincide con uno dei \textit{real}, \textit{effective} o \textit{saved id}.
+\subsection{Le funzioni \func{setgroups} e \func{getgroups}}
+\label{sec:proc_setgroups}
+
+Le ultime funzioni che esamineremo sono quelle sono quelle che permettono di
+operare sui gruppi supplementari. Ogni processo può avere fino a
+\macro{NGROUPS\_MAX} 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 è:
+\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}.
+
+ \bodydesc{La funzione restituisce il numero di gruppi letti in caso di
+ successo e -1 in caso di fallimento, nel qual caso \var{errno} viene
+ settata a:
+ \begin{errlist}
+ \item[\macro{EFAULT}] \param{list} non ha un indirizzo valido.
+ \item[\macro{EINVAL}] il valore di \param{size} è diverso da zero ma
+ minore del numero di gruppi supplementari del processo.
+ \end{errlist}}
+\end{functions}
+\noindent non è specificato se la funzione inserisca o meno nella lista
+l'\textit{effective user id} 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
+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}.
+
+ \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_xxx}) 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
+e passando indietro il numero dei gruppi trovati.
+
+Per settare 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 è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{grp.h}
+
+ \funcdecl{int setgroups(size\_t size, gid\_t *list)} Setta i gruppi
+ supplementari del processo ai valori specificati in \param{list}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ fallimento, nel qual caso \var{errno} viene settata a:
+ \begin{errlist}
+ \item[\macro{EFAULT}] \param{list} non ha un indirizzo valido.
+ \item[\macro{EPERM}] il processo non ha i privilegi di amministratore.
+ \item[\macro{EINVAL}] il valore di \param{size} è maggiore del valore
+ massimo (\macro{NGROUPS}, che per Linux è 32).
+ \end{errlist}}
+\end{functions}
+
+Se invece si vogliono settare i gruppi supplementari del processo a quelli di
+un utente specifico si può usare \func{initgroups} il cui prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{grp.h}
+
+ \funcdecl{int initgroups(const char *user, gid\_t group)} Setta i gruppi
+ supplementari del processo a quelli di cui è membro l'utente \param{user},
+ aggiungendo il gruppo addizionale \param{group}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ fallimento, nel qual caso \var{errno} viene settata agli stessi valori di
+ \func{setgroups} più \macro{ENOMEM} quando non c'è memoria sufficiente per
+ allocare lo spazio per informazioni dei gruppi.}
+\end{functions}
+
+La funzione esegue la scansione del database dei gruppi (usualmente
+\file{/etc/groups}) cercando i gruppi di cui è membro \param{user} costruendo
+una lista di gruppi supplementari a cui aggiunge \param{group}, che poi setta
+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}
+\label{sec:proc_priority}
+
+In questa sezione tratteremo più approfonditamente i meccanismi con il quale
+lo \textit{scheduler} assegna la CPU ai vari processi attivi, illustrando le
+varie funzioni che permettono di leggere e modificare le priorità di
+esecuzione dei programmi.
+
+
+
+
+
\section{Problematiche di programmazione multitasking}
\label{sec:proc_multi_prog}
Benché i processi siano strutturati in modo da apparire il più possibile come
-indipendenti l'uno dall'altro, nella programmazione in un sistema multiutente
-occorre tenere conto di tutta una serie di problematiche che normalmente non
+indipendenti l'uno dall'altro, nella programmazione in un sistema multitasking
+occorre tenere conto di una serie di problematiche che normalmente non
esistono quando si ha a che fare con un sistema in cui viene eseguito un solo
-programma alla volta.
+programma alla volta.
-Pur non essendo tutto questo direttamente legato alla modalità specifica in
-cui il multitasking è implementato in un sistema unix-like, né al solo
-concetto di multitasking (le stesse problematiche si presentano ad esempio
-nella gestione degli interrupt hardware), in questa sezione conclusiva del
-capitolo in cui abbiamo affrontato la gestione dei processi, introdurremo
-sinteticamente queste problematiche, che ritroveremo a più riprese in capitoli
-successivi, con una breve definizione della terminologia e delle loro
-caratteristiche di fondo.
+Pur essendo questo argomento di carattere generale, in questa sezione
+conclusiva del capitolo in cui abbiamo affrontato la gestione dei processi ci
+è parso opportuno introdurre sinteticamente queste problematiche, che
+ritroveremo a più riprese in capitoli successivi, dando una breve descrizione
+delle loro caratteristiche principali e della terminologia relativa.
\subsection{Le operazioni atomiche}
-
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End: