%% prochand.tex
%%
-%% Copyright (C) 2000-2002 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2004 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Prefazione",
processi.
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 \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 \struct{task\_struct} (che in seguito incontreremo a più
-riprese), è mostrato in \figref{fig:proc_task_struct}.
+\textit{process table}; per ciascun processo viene mantenuta una voce,
+costituita da una struttura \struct{task\_struct}, nella tabella dei processi
+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 \struct{task\_struct} (che in
+seguito incontreremo a più riprese), è mostrato in
+\figref{fig:proc_task_struct}.
\begin{figure}[htb]
\centering
\label{fig:proc_task_struct}
\end{figure}
-
Come accennato in \secref{sec:intro_unix_struct} è lo
\textit{scheduler}\index{scheduler} che decide quale processo mettere in
esecuzione; esso viene eseguito ad ogni system call ed ad ogni
\subsection{Una panoramica sulle funzioni fondamentali}
\label{sec:proc_handling_intro}
-I processi vengono creati dalla funzione \func{fork}; in molti unix questa è
-una system call, Linux però usa un'altra nomenclatura, e la funzione
-\func{fork} è basata a sua volta sulla system call \func{\_\_clone}, che viene
-usata anche per generare i \textit{thread}. Il processo figlio creato dalla
-\func{fork} è una copia identica del processo processo padre, ma ha un nuovo
-\acr{pid} e viene eseguito in maniera indipendente (le differenze fra padre e
-figlio sono affrontate in dettaglio in \secref{sec:proc_fork}).
+In un sistema unix-like i processi vengono sempre creati da altri processi
+tramite la funzione \func{fork}; il nuovo processo (che viene chiamato
+\textsl{figlio}) creato dalla \func{fork} è una copia identica del processo
+processo originale (detto \textsl{padre}), ma ha un nuovo \acr{pid} e viene
+eseguito in maniera indipendente (le differenze fra padre e figlio sono
+affrontate in dettaglio in \secref{sec:proc_fork}).
Se si vuole che il processo padre si fermi fino alla conclusione del processo
figlio questo deve essere specificato subito dopo la \func{fork} chiamando la
Il programma che un processo sta eseguendo si chiama immagine del processo (o
\textit{process image}), le funzioni della famiglia \func{exec} permettono di
-caricare un'altro programma da disco sostituendo quest'ultimo all'immagine
+caricare un altro programma da disco sostituendo quest'ultimo all'immagine
corrente; questo fa sì che l'immagine precedente venga completamente
cancellata. Questo significa che quando il nuovo programma termina, anche il
processo termina, e non si può tornare alla precedente immagine.
e direttamente in \file{fork.c}, con il kernel 2.5.x e la nuova interfaccia
per i thread creata da Ingo Molnar anche il meccanismo di allocazione dei
\acr{pid} è stato modificato.} che serve a riservare i \acr{pid} più bassi
-ai processi eseguiti dal direttamente dal kernel. Per questo motivo, come
-visto in \secref{sec:proc_hierarchy}, il processo di avvio (\cmd{init}) ha
-sempre il \acr{pid} uguale a uno.
+ai processi eseguiti direttamente dal kernel. Per questo motivo, come visto
+in \secref{sec:proc_hierarchy}, il processo di avvio (\cmd{init}) ha sempre il
+\acr{pid} uguale a uno.
Tutti i processi inoltre memorizzano anche il \acr{pid} del genitore da cui
sono stati creati, questo viene chiamato in genere \acr{ppid} (da
\bodydesc{Entrambe le funzioni non riportano condizioni di errore.}
\end{functions}
\noindent esempi dell'uso di queste funzioni sono riportati in
-\figref{fig:proc_fork_code}, nel programma di esempio \file{ForkTest.c}.
+\figref{fig:proc_fork_code}, nel programma \file{ForkTest.c}.
Il fatto che il \acr{pid} sia un numero univoco per il sistema lo rende un
candidato per generare ulteriori indicatori associati al processo di cui
diventa possibile garantire l'unicità: ad esempio in alcune implementazioni la
funzione \func{tmpname} (si veda \secref{sec:file_temp_file}) usa il \acr{pid}
-per generare un pathname univoco, che non potrà essere replicato da un'altro
+per generare un pathname univoco, che non potrà essere replicato da un altro
processo che usi la stessa funzione.
Tutti i processi figli dello stesso processo padre sono detti
zero al figlio; ritorna -1 al padre (senza creare il figlio) in caso di
errore; \var{errno} può assumere i valori:
\begin{errlist}
- \item[\errcode{EAGAIN}] non ci sono risorse sufficienti per creare un'altro
+ \item[\errcode{EAGAIN}] non ci sono risorse sufficienti per creare un altro
processo (per allocare la tabella delle pagine e le strutture del task) o
si è esaurito il numero di processi disponibili.
\item[\errcode{ENOMEM}] non è stato possibile allocare la memoria per le
che non è il \acr{pid} di nessun processo.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-#include <errno.h> /* error definitions and routines */
-#include <stdlib.h> /* C standard library */
-#include <unistd.h> /* unix standard library */
-#include <stdio.h> /* standard I/O library */
-#include <string.h> /* string functions */
-
-/* Help printing routine */
-void usage(void);
-
-int main(int argc, char *argv[])
-{
-/*
- * Variables definition
- */
- int nchild, i;
- pid_t pid;
- int wait_child = 0;
- int wait_parent = 0;
- int wait_end = 0;
- ... /* handling options */
- nchild = atoi(argv[optind]);
- printf("Test for forking %d child\n", nchild);
- /* loop to fork children */
- for (i=0; i<nchild; i++) {
- if ( (pid = fork()) < 0) {
- /* on error exit */
- printf("Error on %d child creation, %s\n", i+1, strerror(errno));
- exit(-1);
- }
- if (pid == 0) { /* child */
- printf("Child %d successfully executing\n", ++i);
- if (wait_child) sleep(wait_child);
- printf("Child %d, parent %d, exiting\n", i, getppid());
- exit(0);
- } else { /* parent */
- printf("Spawned %d child, pid %d \n", i+1, pid);
- if (wait_parent) sleep(wait_parent);
- printf("Go to next child \n");
- }
- }
- /* normal exit */
- if (wait_end) sleep(wait_end);
- return 0;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/ForkTest.c}
+ \end{minipage}
+ \normalsize
\caption{Esempio di codice per la creazione di nuovi processi.}
\label{fig:proc_fork_code}
\end{figure}
periodo di attesa.
Se eseguiamo il comando\footnote{che è preceduto dall'istruzione \code{export
- LD\_LIBRARY\_PATH=./} per permettere l'uso delle librerie dinamiche.}}
+ LD\_LIBRARY\_PATH=./} per permettere l'uso delle librerie dinamiche.}
senza specificare attese (come si può notare in (\texttt{\small 17--19}) i
valori predefiniti specificano di non attendere), otterremo come output sul
terminale:
(fino alla conclusione) e poi il padre.
In generale l'ordine di esecuzione dipenderà, oltre che dall'algoritmo di
-scheduling usato dal kernel, dalla particolare situazione in si trova la
+scheduling usato dal kernel, dalla particolare situazione in cui si trova la
macchina al momento della chiamata, risultando del tutto impredicibile.
Eseguendo più volte il programma di prova e producendo un numero diverso di
figli, si sono ottenute situazioni completamente diverse, compreso il caso in
scritto prima della sua creazione. E alla fine del file (dato che in questo
caso il padre esce per ultimo) troveremo anche l'output completo del padre.
-L'esempio ci mostra un'altro aspetto fondamentale dell'interazione con i file,
+L'esempio ci mostra un altro aspetto fondamentale dell'interazione con i file,
valido anche per l'esempio precedente, ma meno evidente: il fatto cioè che non
solo processi diversi possono scrivere in contemporanea sullo stesso file
(l'argomento della condivisione dei file è trattato in dettaglio in
Quello che succede è che quando lo standard output del padre viene rediretto,
lo stesso avviene anche per tutti i figli; la funzione \func{fork} infatti ha
-la caratteristica di duplicare (allo stesso modo in cui lo fa la funzione
-\func{dup}, trattata in \secref{sec:file_dup}) nei figli tutti i file
-descriptor aperti nel padre, il che comporta che padre e figli condividono le
+la caratteristica di duplicare nei figli tutti i file descriptor aperti nel
+padre (allo stesso modo in cui lo fa la funzione \func{dup}, trattata in
+\secref{sec:file_dup}), il che comporta che padre e figli condividono le
stesse voci della \textit{file table} (per la spiegazione di questi termini si
-veda \secref{sec:file_sharing}) e fra cui c'è anche la posizione corrente nel
+veda \secref{sec:file_sharing}) fra cui c'è anche la posizione corrente nel
file.
In questo modo se un processo scrive sul file aggiornerà la posizione corrente
\val{WIFSIGNALED} ha restituito un valore non nullo.\\
\macro{WCOREDUMP(s)} & Vera se il processo terminato ha generato un
file si \textit{core dump}. Può essere valutata solo se
- \val{WIFSIGNALED} ha restituito un valore non nullo.\footnote{questa
- macro non è definita dallo standard POSIX.1, ma è presente come estensione
- sia in Linux che in altri Unix.}\\
+ \val{WIFSIGNALED} ha restituito un valore non nullo.\footnotemark \\
\macro{WIFSTOPPED(s)} & Vera se il processo che ha causato il ritorno di
\func{waitpid} è bloccato. L'uso è possibile solo avendo specificato
l'opzione \const{WUNTRACED}. \\
\label{tab:proc_status_macro}
\end{table}
+\footnotetext{questa macro non è definita dallo standard POSIX.1, ma è
+ presente come estensione sia in Linux che in altri Unix.}
+
Entrambe le funzioni di attesa restituiscono lo stato di terminazione del
processo tramite il puntatore \param{status} (se non interessa memorizzare lo
stato si può passare un puntatore nullo). Il valore restituito da entrambe le
\begin{errlist}
\item[\errcode{EACCES}] il file non è eseguibile, oppure il filesystem è
montato in \cmd{noexec}, oppure non è un file regolare o un interprete.
- \item[\errcode{EPERM}] il file ha i bit \acr{suid} o \acr{sgid}, l'utente non
- è root, e o il processo viene tracciato, o il filesystem è montato con
+ \item[\errcode{EPERM}] il file ha i bit \acr{suid} o \acr{sgid}, l'utente
+ non è root, il processo viene tracciato, o il filesystem è montato con
l'opzione \cmd{nosuid}.
\item[\errcode{ENOEXEC}] il file è in un formato non eseguibile o non
riconosciuto come tale, o compilato per un'altra architettura.
Nel secondo caso le stringhe degli argomenti sono passate alla funzione come
lista di puntatori, nella forma:
-\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
- char *arg0, char *arg1, ..., char *argn, NULL
-\end{lstlisting}
+\includecodesnip{listati/char_list.c}
che deve essere terminata da un puntatore nullo. In entrambi i casi vale la
convenzione che il primo argomento (\var{arg0} o \var{argv[0]}) viene usato
per indicare il nome del file che contiene il programma che verrà eseguito.
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 \param{file} non
-contiene una \file{/} esso viene considerato come un nome di programma, e
+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
viene posto in esecuzione è il primo che viene trovato. Se si ha un errore
\begin{figure}[htb]
\centering
- \includegraphics[width=15cm]{img/exec_rel}
+ \includegraphics[width=16cm]{img/exec_rel}
\caption{La interrelazione fra le sei funzioni della famiglia \func{exec}.}
\label{fig:proc_exec_relat}
\end{figure}
\acr{libc5}, e \file{/lib/ld-linux.so.2} per programmi linkati con le
\acr{glibc}. Infine nel caso il file sia uno script esso deve iniziare con
una linea nella forma \cmd{\#!/path/to/interpreter} dove l'interprete indicato
-deve esse un valido programma (binario, non un altro script) che verrà
-chiamato come se si fosse eseguito il comando \cmd{interpreter [arg]
+deve esse un programma valido (binario, non un altro script) che verrà
+chiamato come se si fosse eseguito il comando \cmd{interpreter [argomenti]
filename}.
Con la famiglia delle \func{exec} si chiude il novero delle funzioni su cui è
in dettaglio in \secref{sec:file_suid_sgid}). In questo caso essi saranno
impostati all'utente e al gruppo proprietari del file. Questo consente, per
programmi in cui ci sia necessità, di dare a qualunque utente normale
-privilegi o permessi di un'altro (o dell'amministratore).
+privilegi o permessi di un altro (o dell'amministratore).
Come nel caso del \acr{pid} e del \acr{ppid}, anche tutti questi
identificatori possono essere letti attraverso le rispettive funzioni:
per i quali erano richiesti, e a poterli eventualmente recuperare in caso
servano di nuovo.
-Questo in Linux viene fatto usando altri gli altri due gruppi di
-identificatori, il \textit{saved} ed il \textit{filesystem}. Il primo gruppo è
-lo stesso usato in SVr4, e previsto dallo standard POSIX quando è definita la
-costante \macro{\_POSIX\_SAVED\_IDS},\footnote{in caso si abbia a cuore la
- portabilità del programma su altri Unix è buona norma controllare sempre la
+Questo in Linux viene fatto usando altri due gruppi di identificatori, il
+\textit{saved} ed il \textit{filesystem}. Il primo gruppo è lo stesso usato in
+SVr4, e previsto dallo standard POSIX quando è definita la costante
+\macro{\_POSIX\_SAVED\_IDS},\footnote{in caso si abbia a cuore la portabilità
+ del programma su altri Unix è buona norma controllare sempre la
disponibilità di queste funzioni controllando se questa costante è
definita.} il secondo gruppo è specifico di Linux e viene usato per
migliorare la sicurezza con NFS.
dell'\textsl{user-ID effettivo} e del \textsl{group-ID effettivo} del processo
padre, e vengono impostati dalla funzione \func{exec} all'avvio del processo,
come copie dell'\textsl{user-ID effettivo} e del \textsl{group-ID effettivo}
-dopo che questo sono stati impostati tenendo conto di eventuali \acr{suid} o
+dopo che questi sono stati impostati tenendo conto di eventuali \acr{suid} o
\acr{sgid}. Essi quindi consentono di tenere traccia di quale fossero utente
e gruppo effettivi all'inizio dell'esecuzione di un nuovo programma.
consentendo l'accesso a \file{/var/log/utmp}.
Occorre però tenere conto che tutto questo non è possibile con un processo con
-i privilegi di root, in tal caso infatti l'esecuzione una \func{setuid}
-comporta il cambiamento di tutti gli identificatori associati al processo,
-rendendo impossibile riguadagnare i privilegi di amministratore. Questo
-comportamento è corretto per l'uso che ne fa \cmd{login} una volta che crea
-una nuova shell per l'utente; ma quando si vuole cambiare soltanto
+i privilegi di amministratore, in tal caso infatti l'esecuzione di una
+\func{setuid} comporta il cambiamento di tutti gli identificatori associati al
+processo, rendendo impossibile riguadagnare i privilegi di amministratore.
+Questo comportamento è corretto per l'uso che ne fa \cmd{login} una volta che
+crea una nuova shell per l'utente; ma quando si vuole cambiare soltanto
l'\textsl{user-ID effettivo} del processo per cedere i privilegi occorre
ricorrere ad altre funzioni (si veda ad esempio \secref{sec:proc_seteuid}).
-\subsection{Le funzioni \func{setreuid} e \func{setresuid}}
+\subsection{Le funzioni \func{setreuid} e \func{setregid}}
\label{sec:proc_setreuid}
-Queste due funzioni derivano da BSD che, non supportando\footnote{almeno fino
- alla versione 4.3+BSD TODO, FIXME verificare e aggiornare la nota.} gli
-identificatori del gruppo \textit{saved}, le usa per poter scambiare fra di
-loro \textit{effective} e \textit{real}. I loro prototipi sono:
+Le due funzioni \funcd{setreuid} e \funcd{setregid} derivano da BSD che, non
+supportando\footnote{almeno fino alla versione 4.3+BSD TODO, FIXME verificare
+ e aggiornare la nota.} gli identificatori del gruppo \textit{saved}, le usa
+per poter scambiare fra di loro \textit{effective} e \textit{real}. I
+rispettivi prototipi sono:
\begin{functions}
\headdecl{unistd.h}
\headdecl{sys/types.h}
dell'user-ID effettivo.
-\subsection{Le funzioni \funcd{seteuid} e \funcd{setegid}}
+\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 vengono usate per cambiare gli
-identificatori del gruppo \textit{effective}; i loro prototipi sono:
+Le due funzioni \funcd{seteuid} e \funcd{setegid} sono un'estensione allo
+standard POSIX.1 (ma sono comunque supportate dalla maggior parte degli Unix)
+e vengono usate per cambiare gli identificatori del gruppo \textit{effective};
+i loro prototipi sono:
\begin{functions}
\headdecl{unistd.h}
\headdecl{sys/types.h}
normale di \func{setuid} comporta l'impostazione di tutti gli identificatori.
-\subsection{Le funzioni \funcd{setresuid} e \funcd{setresgid}}
+\subsection{Le funzioni \func{setresuid} e \func{setresgid}}
\label{sec:proc_setresuid}
-Queste due funzioni sono un'estensione introdotta in Linux dal kernel 2.1.44,
-e permettono un completo controllo su tutti gli identificatori (\textit{real},
-\textit{effective} e \textit{saved}), i prototipi sono:
+Le due funzioni \funcd{setresuid} e \funcd{setresgid} sono un'estensione
+introdotta in Linux,\footnote{a partire dal kernel 2.1.44.} e permettono un
+completo controllo su tutti e tre i gruppi di identificatori (\textit{real},
+\textit{effective} e \textit{saved}), i loro prototipi sono:
\begin{functions}
\headdecl{unistd.h}
\headdecl{sys/types.h}
Anche queste funzioni sono un'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
+specificati come puntatori (è un altro esempio di \textit{value result
argument}). Si noti che queste funzioni sono le uniche in grado di leggere
gli identificatori del gruppo \textit{saved}.
\subsection{Le funzioni \func{setfsuid} e \func{setfsgid}}
\label{sec:proc_setfsuid}
-Queste funzioni sono usate per impostare gli identificatori del gruppo
-\textit{filesystem} che usati da Linux per il controllo dell'accesso ai file.
-Come già accennato in \secref{sec:proc_access_id} Linux definisce questo
-ulteriore gruppo di identificatori, che di norma sono assolutamente
-equivalenti a quelli del gruppo \textit{effective}, dato che ogni cambiamento
-di questi ultimi viene immediatamente riportato su di essi.
+Queste funzioni servono per impostare gli identificatori del gruppo
+\textit{filesystem} che sono usati da Linux per il controllo dell'accesso ai
+file. Come già accennato in \secref{sec:proc_access_id} Linux definisce
+questo ulteriore gruppo di identificatori, che in circostanze normali sono
+assolutamente equivalenti a quelli del gruppo \textit{effective}, dato che
+ogni cambiamento di questi ultimi viene immediatamente riportato su di essi.
C'è un solo caso in cui si ha necessità di introdurre una differenza fra gli
identificatori dei gruppi \textit{effective} e \textit{filesystem}, ed è per
ovviare ad un problema di sicurezza che si presenta quando si deve
-implementare un server NFS. Il server NFS infatti deve poter cambiare
-l'identificatore con cui accede ai file per assumere l'identità del singolo
-utente remoto, ma se questo viene fatto cambiando l'user-ID effettivo o
-l'user-ID reale il server si espone alla ricezione di eventuali segnali ostili
-da parte dell'utente di cui ha temporaneamente assunto l'identità. Cambiando
-solo l'user-ID di filesystem si ottengono i privilegi necessari per accedere ai
-file, mantenendo quelli originari per quanto riguarda tutti gli altri
-controlli di accesso, così che l'utente non possa inviare segnali al server
-NFS.
+implementare un server NFS.
+
+Il server NFS infatti deve poter cambiare l'identificatore con cui accede ai
+file per assumere l'identità del singolo utente remoto, ma se questo viene
+fatto cambiando l'user-ID effettivo o l'user-ID reale il server si espone alla
+ricezione di eventuali segnali ostili da parte dell'utente di cui ha
+temporaneamente assunto l'identità. Cambiando solo l'user-ID di filesystem si
+ottengono i privilegi necessari per accedere ai file, mantenendo quelli
+originari per quanto riguarda tutti gli altri controlli di accesso, così che
+l'utente non possa inviare segnali al server NFS.
Le due funzioni usate per cambiare questi identificatori sono \funcd{setfsuid}
e \funcd{setfsgid}, ovviamente sono specifiche di Linux e non devono essere
\label{sec:proc_setgroups}
Le ultime funzioni che esamineremo sono quelle che permettono di operare sui
-gruppi supplementari. Ogni processo può avere fino a \const{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 è
-\funcd{getgroups}; questa funzione è definita nello standard POSIX ed il suo
-prototipo è:
+gruppi supplementari cui un utente può appartenere. Ogni processo può avere
+almeno \const{NGROUPS\_MAX} gruppi supplementari\footnote{il numero massimo di
+ gruppi secondari può essere ottenuto con \func{sysconf} (vedi
+ \secref{sec:sys_sysconf}), leggendo il parametro
+ \texttt{\_SC\_NGROUPS\_MAX}.} 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 associati ad un
+processo è \funcd{getgroups}; questa funzione è definita nello standard
+POSIX.1, ed il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{unistd.h}
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 è:
+ottenere tutti i gruppi a cui appartiene un certo utente; il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{grp.h}
restituisce 0 in caso di successo e -1 in caso di fallimento.}
\end{functions}
-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.
+La funzione legge i gruppi supplementari dell'utente specificato da
+\param{user}, eseguendo una scansione del database dei gruppi (si veda
+\secref{sec:sys_user_group}). Ritorna poi 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
\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}.
+compila con il flag \cmd{-ansi}, è pertanto meglio evitarle se si vuole
+scrivere codice portabile.
+
+
+%
+% Da fare !!!
+% insieme alla risistemazioni dei titoli delle sezioni precedenti
+% (accorpare il materiale) qualosa tipo:
+% le funzioni di controllo
+% estenzioni di Linux
+%
+%\subsection{La gestione delle capabilities}
+%\label{sec:proc_capabilities}
+
+
\section{La gestione della priorità di esecuzione}
\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
+ \textbf{Sleep} & \texttt{S} & Il processo è in attesa di un
risposta dal sistema, ma può essere
interrotto da un segnale. \\
\textbf{Uninterrutible Sleep}& \texttt{D} & Il processo è in
nell'esecuzione.
Il meccanismo usato da Linux è piuttosto semplice, ad ogni processo è
-assegnata una \textit{time-slice}, cioè in intervallo di tempo (letteralmente
+assegnata una \textit{time-slice}, cioè un intervallo di tempo (letteralmente
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
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
-processi in stato \textit{runnable} associando, sulla base del valore di
-\var{counter}, un peso a ciascun processo in attesa di esecuzione,\footnote{il
+Durante la sua esecuzione lo scheduler\index{scheduler} scandisce la coda dei
+processi in stato \textit{runnable} associando, in base al valore di
+\var{counter}, un peso ad ogni processo in attesa di esecuzione,\footnote{il
calcolo del peso in realtà è un po' più complicato, ad esempio nei sistemi
- multiprocessore viene favorito un processo che è eseguito sulla stessa CPU,
- e a parità del valore di \var{counter} viene favorito chi ha una priorità
- più elevata.} chi ha il peso più alto verrà posto in esecuzione, ed il
+ multiprocessore viene favorito un processo eseguito sulla stessa CPU, e a
+ parità del valore di \var{counter} viene favorito chi ha una priorità più
+ elevata.} chi ha il peso più alto verrà posto in esecuzione, ed il
precedente processo sarà spostato in fondo alla coda. Dato che ad ogni
interruzione del timer il valore di \var{counter} del processo corrente viene
diminuito, questo assicura che anche i processi con priorità più bassa
La priorità di un processo è così controllata attraverso il valore di
\var{nice}, che stabilisce la durata della \textit{time-slice}; per il
-meccanismo appena descritto infatti un valore più lungo infatti assicura una
-maggiore attribuzione di CPU. L'origine del nome di questo parametro sta nel
-fatto che generalmente questo viene usato per diminuire la priorità di un
-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 \funcd{nice}, il cui prototipo è:
+meccanismo appena descritto infatti un valore più lungo assicura una maggiore
+attribuzione di CPU. L'origine del nome di questo parametro sta nel fatto che
+generalmente questo viene usato per diminuire la priorità di un 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 \funcd{nice}, il cui prototipo è:
\begin{prototype}{unistd.h}
{int nice(int inc)}
Aumenta il valore di \var{nice} per il processo corrente.
\item[\errcode{EINVAL}] il valore di \param{which} non è valido.
\end{errlist}}
\end{prototype}
-\noindent (in vecchie versioni può essere necessario includere anche
+\noindent nelle vecchie versioni può essere necessario includere anche
\file{<sys/time.h>}, questo non è più necessario con versioni recenti delle
-librerie, ma è comunque utile per portabilità).
+librerie, ma è comunque utile per portabilità.
-La funzione permette di leggere la priorità di un processo, di un gruppo di
-processi (vedi \secref{sec:sess_proc_group}) o di un utente, a seconda del
-valore di \param{which}, secondo la legenda di \tabref{tab:proc_getpriority},
-specificando un corrispondente valore per \param{who}; un valore nullo di
-quest'ultimo indica il processo, il gruppo di processi o l'utente correnti.
+La funzione permette, a seconda del valore di \param{which}, di leggere la
+priorità di un processo, di un gruppo di processi (vedi
+\secref{sec:sess_proc_group}) o di un utente, specificando un corrispondente
+valore per \param{who} secondo la legenda di \tabref{tab:proc_getpriority}; un
+valore nullo di quest'ultimo indica il processo, il gruppo di processi o
+l'utente correnti.
\begin{table}[htb]
\centering
siano installate le patch di RTLinux, RTAI o Adeos, con i quali è possibile
ottenere un sistema effettivamente hard real-time. In tal caso infatti gli
interrupt vengono intercettati dall'interfaccia real-time (o nel caso di
- Adeos gestiti dalle code del nano-kernel), in modo da poterlo controllare
+ Adeos gestiti dalle code del nano-kernel), in modo da poterli controllare
direttamente qualora ci sia la necessità di avere un processo con priorità
più elevata di un \textit{interrupt handler}.} mentre con l'incorrere in un
page fault\index{page fault} si possono avere ritardi non previsti. Se
non è superabile e può comportare ritardi non prevedibili riguardo ai tempi di
esecuzione di qualunque processo.
-In ogni caso occorre usare le priorità assolute con molta attenzione: se si dà
-ad un processo una priorità assoluta e questo finisce in un loop infinito,
-nessun altro processo potrà essere eseguito, ed esso sarà mantenuto in
-esecuzione permanentemente assorbendo tutta la CPU e senza nessuna possibilità
-di riottenere l'accesso al sistema. Per questo motivo è sempre opportuno,
-quando si lavora con processi che usano priorità assolute, tenere attiva una
-shell cui si sia assegnata la massima priorità assoluta, in modo da poter
-essere comunque in grado di rientrare nel sistema.
+Occorre usare le priorità assolute con molta attenzione: se si dà ad un
+processo una priorità assoluta e questo finisce in un loop infinito, nessun
+altro processo potrà essere eseguito, ed esso sarà mantenuto in esecuzione
+permanentemente assorbendo tutta la CPU e senza nessuna possibilità di
+riottenere l'accesso al sistema. Per questo motivo è sempre opportuno, quando
+si lavora con processi che usano priorità assolute, tenere attiva una shell
+cui si sia assegnata la massima priorità assoluta, in modo da poter essere
+comunque in grado di rientrare nel sistema.
Quando c'è un processo con priorità assoluta lo scheduler\index{scheduler} lo
metterà in esecuzione prima di ogni processo normale. In caso di più processi
sarà eseguito per primo quello con priorità assoluta più alta. Quando ci sono
più processi con la stessa priorità assoluta questi vengono tenuti in una coda
-tocca al kernel decidere quale deve essere eseguito.
-
+e tocca al kernel decidere quale deve essere eseguito.
Il meccanismo con cui vengono gestiti questi processi dipende dalla politica
di scheduling che si è scelto; lo standard ne prevede due:
-\begin{basedescript}{\desclabelwidth{2cm}\desclabelstyle{\nextlinelabel}}
+\begin{basedescript}{\desclabelwidth{1.2cm}\desclabelstyle{\nextlinelabel}}
\item[\textit{FIFO}] \textit{First In First Out}. Il processo viene eseguito
fintanto che non cede volontariamente la CPU, si blocca, finisce o viene
interrotto da un processo a priorità più alta.
\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}).
+ politica richiesta.
\end{errlist}}
\end{prototype}
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.
+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.
+Solo un processo con i privilegi di amministratore può impostare priorità
+assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}.
\begin{table}[htb]
\centering
massimo ed uno minimo, che nel caso sono rispettivamente 1 e 99 (il valore
zero è legale, ma indica i processi normali).
-\begin{figure}[!htb]
+\begin{figure}[!bht]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
-struct sched_param {
- int sched_priority;
-};
- \end{lstlisting}
+ \includestruct{listati/sched_param.c}
\end{minipage}
\normalsize
\caption{La struttura \structd{sched\_param}.}
\bodydesc{La funzioni ritornano il valore della priorità in caso di successo
e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori:
\begin{errlist}
- \item[\errcode{EINVAL}] il valore di \param{policy} è invalido.
+ \item[\errcode{EINVAL}] il valore di \param{policy} non è valido.
\end{errlist}}
\end{functions}
\end{errlist}}
\end{prototype}
-La funzione restituisce il valore (secondo la quanto elencato in
+La funzione restituisce il valore (secondo quanto elencato in
\tabref{tab:proc_sched_policy}) della politica di scheduling per il processo
specificato; se \param{pid} è nullo viene restituito quello del processo
chiamante.
\funcdecl{int sched\_setparam(pid\_t pid, const struct sched\_param *p)}
Imposta la priorità assoluta del processo \param{pid}.
-
\funcdecl{int sched\_getparam(pid\_t pid, struct sched\_param *p)}
Legge la priorità assoluta del processo \param{pid}.
stati completati.
Dato che in un sistema multitasking ogni processo può essere interrotto in
-qualunque momento per farne subentrare un'altro in esecuzione, niente può
+qualunque momento per farne subentrare un altro in esecuzione, niente può
assicurare un preciso ordine di esecuzione fra processi diversi o che una
sezione di un programma possa essere eseguita senza interruzioni da parte di
altri. Queste situazioni comportano pertanto errori estremamente subdoli e