Poche aggiunte
[gapil.git] / process.tex
index 2f754b992438de42fdf9a6ad1eaabad7fa8105e2..2bde8679e5846caf82025b3b789e35b8e7a9a36a 100644 (file)
-\chapter{I processi}
-\label{cha:process}
-
-Come accennato nell'introduzione in un sistema unix ogni attività del sistema
-viene svolta tramite i processi. Questo significa che quando un programma
-viene posto in esecuzione, viene fatto partire un processo che si incarica di
-eseguirne il codice. In sostanza i processi costituiscono l'unità base per
-l'allocazione e l'uso delle risorse del sistema.
-
-Una delle caratteristiche essenziali di unix (che esamineremo in dettaglio più
-avanti) è che ogni processo può a sua volta generare altri processi figli
-(\textit{child}): questo è ad esempio quello che fa la shell quando mette in
-esecuzione il programma che gli indichiamo nella linea di comando.
-
-Una seconda caratteristica è che ogni processo viene sempre generato in tale
-modo da un processo genitore (\textit{parent}) attraverso una apposita system
-call. Questo vale per tutti i processi, tranne per un processo speciale, che
-normalmente è \texttt{/sbin/init}, che invece viene lanciato dal kernel finita
-la fase di avvio e che quindi non è figlio di nessuno.
-
-Tutto ciò significa che, come per i file su disco, i processi sono organizzati
-gerarchicamente dalla relazione fra genitori e figli; alla base dell'albero in
-questo caso c'è init che è progenitore di ogni altro processo.
-
-
-\section{Una panoramica sui concetti base}
-\label{sec:proc_gen}
-
-Ogni processo viene identificato dal sistema da un numero identificativo
-unico, il \textit{process id} o \textit{pid}. Questo viene assegnato in forma
-progressiva ogni volta che un nuovo processo viene creato, fino ad un limite
-massimo (in genere essendo detto numero memorizzato in un intero a 16 bit si
-arriva a 32767) oltre il quale si riparte dal numero più basso disponibile
-(FIXME: verificare, non sono sicuro).  Per questo motivo processo il processo
-di avvio (init) ha sempre il pid uguale a uno.
-
-Quando un processo ha concluso il suo compito o ha incontrato un errore non
-risolvibile esso può essere terminato con la funzione \texttt{exit} (la
-questione è più complessa ma ci torneremo più avanti). La vita del processo
-però termina solo quando viene chiamata la quando la sua conclusione viene
-ricevuta dal processo padre, a quel punto tutte le risorse allocate nel
-sistema ad esso associate vengono rilasciate.
-
-I processi vengono creati dalla funzione \texttt{fork}; in genere questa è una
-system call, Linux però usa un'altra nomenclatura, e la funzione fork è basata
-a sua volta sulla system call \texttt{clone}, che viene usata anche per
-generare i \textit{thread}.  Il processo figlio creato dalla \textit{fork} è
-una copia identica del processo processo padre, solo che ha un suo pid proprio.
-
-Dopo l'esecuzione di una fork sia il processo padre che il processo figlio
-continuano ad essere eseguiti normalmente, ed il processo figlio esegue
-esattamente lo stesso codice del padre. La sola differenza è che nel processo
-padre il valore di ritorno della funzione fork è il pid del processo figlio,
-mentre nel figlio è zero; in questo modo il programma può identificare se
-viene eseguito dal padre o dal figlio. 
-
-Se si vuole che il processo padre si fermi fino alla conclusione del processo
-figlio questo deve essere specificato subito dopo la fork chiamando la
-funzione \texttt{wait} o la funzione \texttt{waitpid}, che restituiscono anche
-una informazione abbastanza limitata (il codice di uscita) sulle cause della
-terminazione del processo.
-
-Avere due processi che eseguono esattamente lo stesso codice non è molto
-utile, mormalmente si genera un secondo processo per affidagli l'esecuzione di
-un compito specifico (ad esempio gestire una connessione dopo che questa è
-stata stabilita), o fargli eseguire (come fa la shell) un altro programma. Per
-questo si usa la seconda funzione fondamentale per programmazione coi processi
-che è la \texttt{exec}.
-
-Il programma che un processo sta eseguendo si chiama immagine del processo
-(\textit{process image}), le funzioni della famiglia \textit{exec} permette di
-caricare un'altro programma da disco sostituendo quest'ultimo alla process
-image corrente, questo fa si che la precedente immagine venga completamente
-cancellata e quando il nuovo programma esce anche il processo termina, senza
-ritornare alla precedente immagine.
-
-Per questo motivo la \texttt{fork} e la \texttt{exec} sono funzioni molto
-particolari con caratteristiche uniche rispetto a tutte le altre, infatti la
-prima ritorna due volte (nel processo padre e nel figlio) mentre la seconda
-non ritorna mai (in quanto viene eseguito un altro programma).
-
-
-\section{Identificazione}
-\label{sec:proc_id}
-
-Come detto ogni processo è identificato univocamente dal sistema per il suo
-pid; quest'ultimo è un apposito tipo di dato, il \texttt{pid\_t} che in
-genere è un intero con segno (nel caso di Linux e delle glibc il tipo usato è
-\texttt{int}.
-
-Tutti i processi inoltre portano traccia del pid del genitore, chiamato in
-genere \textit{ppid} (da \textit{Parente Process Id}). Questi identificativi
-possono essere ottenuti da un programma usando le funzioni:
-\begin{itemize} 
-  \item \texttt{pid\_t getpid(void)} restituisce il pid del processo corrente.
-    
-  \item \texttt{pid\_t getpid(void)} restituisce il pid del padre del processo
-    corrente.
+\chapter{L'interfaccia base con i processi}
+\label{cha:process_interface}
 
-\end{itemize}
-(per l'accesso a queste funzioni e ai relativi tipi di dati occorre includere
-gli header files \texttt{unistd.h} e \texttt{sys/types.h}. 
+Come accennato nell'introduzione il processo è l'unità di base con cui un
+sistema unix alloca ed utilizza le risorse.  Questo capitolo tratterà
+l'interfaccia base fra il sistema e i processi, su come vengono passati i
+parametri, come viene gestita e allocata la memoria, su come un processo può
+richiedere servizi al sistema, su cosa deve fare quando ha finito la sua
+esecuzione.
+
+In genere un programma viene eseguito quando un processo lo fa partire
+eseguendo una funzione della famiglia \texttt{exec}; torneremo su questo e
+sulla la creazione e gestione dei processi nel prossimo capitolo, in questo
+affronteremo l'avvio e il funzionamento di un programma dal punto di vista del
+programma posto in esecuzione.
 
 
-\section{Provilegi e permessi}
-\label{sec:process_perms}
+\section{Esecuzione e conclusione di un programma}
 
-Va messo qui tutta la storia su effective, real, saved uid, e pure le cose di
-linux come il filesystem uid.
+Una delle concetti base relativi ai processi è che un processo esegue sempre
+uno ed un solo programma: si possono avere più processi che eseguono lo stesso
+programma ma ciascun processo vedrà la sua copia del codice (in realtà il
+kernel fa si che tutte le parti uguali siano condivise) avrà un suo spazio di
+indirizzi, variabili proprie e sarà eseguito in maniera completamente
+indipendente da tutti gli altri. 
 
+Anche quando all'interno di un programma possono essere presenti più
+\textsl{filoni} di esecuzione (i cosiddetti \textit{thread}), o questo possa
+essere composto da moduli multipli completamente separati, quando questo sarà
+posto in esecuzione esso apparirà al sistema come un solo processo (il
+discorso dei \textit{thread} comunque in linux necessita di una trattazione a
+parte per la peculiarità dell'implementazione).
 
 
-\section{Creazione dei processi}
-\label{sec:proc_fork}
+\section{La funzione \texttt{main}} 
+\label{sec:proc_main}
+
+Quando un programma viene lanciato dal kernel viene eseguito il
+programma \texttt{ld-linux.so}, è questo programma che prima carica le
+librerie condivise che servono al programma, effettua il link dinamico del
+codice e poi alla fine lo esegue. La procedura è controllata da alcune
+variabili di ambiente e dai settaggi di 
+
+Il sistema fa partire qualunque programma chiamando la funzione \texttt{main};
+sta al programmatore chiamare così la funzione principale del programma, se
+così non fosse lo stesso linker darebbe luogo ad errori.
+
+Lo stadard ISO C specifica che detta funzione può non avere argomenti o
+prendere due argomenti che rappresentano gli argomenti passati da linea di
+comando, in sostanza un prototipo che va sempre bene è il seguente:
+\begin{verbatim}
+     int main (int argc, char *argv[])
+\end{verbatim}
+
+
+In realtà nei sistemi unix esiste un'altro modo per definire la funzione
+\texttt{main}, che prende un terzo parametro, \texttt{char *envp[]}, che
+fornisce l'ambiente (vedi \secref{proc_environ}) del programma; questa forma
+però non è prevista dallo standard POSIX.1 per cui se si vogliono scrivere
+programmi portabili è meglio evitarla.
+
+
+
+\subsection{}
+\label{sec:proc_}
+
+
+
+\subsection{La funzione \texttt{exit}}
+\label{sec:proc_exit}
+
+
+\section{La gestione della memoria}
+\label{sec:proc_mem_manag}
+
+
+
+\section{Gestione di parametri e opzioni}
+\label{sec:parameter_options}
+
+Il passaggio dei parametri e delle variabili di ambiente dalla riga di comando
+al singolo programma quando viene lanciato è effettuato attraverso le
+variabili \texttt{argc}, \texttt{argv} che vengono passate al programma
+come argomenti della funzione principale.
+
+\subsection{Il formato dei parametri}
+\label{sec:proc_par_format}
+In genere passaggio dei parametri al programma viene effettuato dalla shell,
+che si incarica di leggere la linea di comando e di effettuarne la scansione
+(il cosiddetto \textit{parsing}) per individuare le parole che la compongono,
+ciascuna delle quali viene considerata un parametro; di default per
+individuare le parole viene usato come separatore lo spazio (comportamento
+modificabile attraverso il settaggio della variabile di ambiente IFS).
+
+Nella scansione viene costruito l'array di puntatori \texttt{argv} inserendo
+in successione il puntatore alla stringa costituente l'$n$-simo parametro; la
+variabile \texttt{argc} viene inizializzata al numero di parametri trovati, in
+questo modo il primo parametro è sempre il nome del programma (vedi \nfig).
+
+\subsection{La gestione delle opzioni}
+\label{sec:proc_opt_handling}
+
+In generale un programma unix riceve da linea di comando sia i parametri che
+le opzioni, queste ultime sono standardizzate per essere riconosciute come
+tali: un elemento di \texttt{argv} che inizia con \texttt{-} e che non sia un
+singolo \texttt{-} o \texttt{--} viene considerato un'opzione.  In in genere
+le opzioni sono costituite da un lettera preceduta dal meno e possono avere o
+no un parametro associato; un comando tipico può essere cioè qualcosa del
+tipo:
+\begin{verbatim}
+touch -r riferimento.txt -m questofile.txt
+\end{verbatim}
+ed in questo caso le opzioni sono \texttt{m} ed \texttt{r}.
+
+Per gestire le opzioni all'interno dei parametri passati in \texttt{argv} le
+librerie standard del C forniscono la funzione \texttt{getopt} (accessibile
+includendo \texttt{unistd.h}), che ha il prototipo:
+\begin{verbatim}
+int getopt(int argc, char * const argv[], const char * optstring);
+\end{verbatim}
+
+Questa funzione prende come argomenti le due variabili \texttt{argc} e
+\texttt{argv} ed una stringa che indica quali sono le opzioni valide; la
+funzione effettua la scansione della lista dei parametri ricercando ogni
+stringa che comincia con \texttt{-} e ritorna ogni volta che trova una opzione
+valida.
+
+La stringa \texttt{optstring} indica quali sono le opzioni riconosciute ed è
+costituita da tutti i caratteri usati per identificare le singole opzioni, se
+l'opzione ha un parametro al carattere deve essere fatto seguire un segno di
+due punti \texttt{:} nel caso appena accennato ad esempio la stringa di
+opzioni sarebbe \texttt{"r:m"}.
+
+La modalità di uso è pertanto quella di chiamare più volte la funzione
+all'interno di un ciclo di while fintanto che essa non ritorna il valore
+\texttt{-1} che indica che non ci sono più opzioni. Nel caso si incontri
+un'opzione non dichiarata in \texttt{optstring} viene ritornato un \texttt{?}
+mentre se l'opzione non è seguita da un parametro viene ritornato un
+\texttt{:} infine se viene incontrato il valore \texttt{--} la scansione viene
+considerata conclusa.
+
+Quando la funzione trova un'opzione essa ritorna il valore numerico del
+carattere, in questo modo si possono prendere le azioni relative usando un
+case; la funzione inizializza inoltre alcune varibili globali:
+\begin{itemize}
+\item \texttt{char * optarg} contiene il puntatore alla stringa argomento
+  dell'opzione.
+\item \texttt{int optind} alla fine della scansione restituisce l'indice del
+  primo argomento che non è un'opzione.
+\item \texttt{int opterr} previene, se posto a zero, la stampa di un messaggio
+  di errore in caso di riconoscimento di opzioni non definite.
+\item \texttt{int optopt} contiene il carattere dell'opzione non riconosciuta.
+\end{itemize}
+
+In \nfig è mostrato un programma di esempio, 
+
+
+\begin{figure}[htbp]
+  \footnotesize
+    \begin{lstlisting}{}
+    opterr = 0;  /* don't want writing to stderr */
+    while ( (i = getopt(argc, argv, "o:a:i:hve")) != -1) {
+        switch (i) {
+        case 'i':   /* input file */
+            in_file=open(optarg,O_RDONLY);
+            if (in_file<0) {
+                perror("Cannot open input file");
+                exit(1);
+            }
+            break;
+        case 'o':   /* output file (overwrite) */
+            out_file=open(optarg,O_WRONLY|O_CREAT);
+            if (out_file<0) {
+                perror("Cannot open output file");
+                exit(1);
+            }
+            break;
+            break;
+        case 'a':   /* output file (append) */
+            out_file=open(optarg,O_WRONLY|O_CREAT|O_APPEND);
+            break;
+        case 'h':   /* print help usage */
+            usage();
+            break;
+        case 'v':   /* set verbose mode */
+            debug("Option -v active\n");
+            verbose=1;
+            break;
+        case '?':   /* unrecognized options */
+            printf("Unrecognized options -%c\n",optopt);
+            usage();
+        default:    /* should not reached */
+            debug("default option\n");
+            usage();
+        }
+    }
+    debug("Optind %d, argc %d\n",optind,argc);
+  \end{lstlisting}
+  \caption{Esempio di codice per la gestione delle opzioni.}
+  \label{fig:proc_options_code}
+\end{figure}
+
+\subsection{Opzioni in formato esteso}
+\label{sec:proc_opt_extended}
+
+Un'estensione di questo schema è costituito dalle cosiddette
+\textit{long-options} espresse nella forma \texttt{--option=parameter}, anche
+la gestione di queste ultime è stata standardizzata attraverso l'uso di una
+versione estesa di \texttt{getopt}.
+
+
+\subsection{Le variabili di ambiente}
+\label{sec:proc_env_var}
+
+Questo va fatto.
+
+
+
+\section{La gestione della memoria}
+\label{sec:proc_memory_manag}
\ No newline at end of file