Iniziati terminali di controllo
[gapil.git] / session.tex
index b97024deb0ee38f8fc2d3d4ab07c2686d80806bf..13bc2c5efdb1a620ca87dfca80420e65e38a1664 100644 (file)
@@ -1,4 +1,4 @@
-\chapter{Sessioni di lavoro e terminali}
+ \chapter{Sessioni di lavoro e terminali}
 \label{cha:session}
 
 Esamineremo in questo capitolo i concetti base del sistema delle sessioni di
@@ -17,7 +17,7 @@ Viene comunemente chiamato \textit{job control} quell'insieme di funzionalit
 il cui scopo è quello di permettere ad un utente di poter sfruttare le
 capacità multitasking di un sistema Unix per eseguire in contemporanea più
 processi, pur potendo accedere, di solito, ad un solo terminale,\footnote{con
-  X e con i terminali vituali tutto questo non è più vero, dato che si può
+  X e con i terminali virtuali tutto questo non è più vero, dato che si può
   accedere a molti terminali in contemporanea, ma il sistema è nato prima
   dell'esistenza di tutto ciò.} avendo cioè un solo punto in cui si può avere
 accesso all'input ed all'output degli stessi. 
@@ -35,12 +35,12 @@ del kernel; in particolare il kernel deve assicurare sia la presenza di un
 driver per i terminali abilitato al \textit{job control} che quella dei
 relativi segnali illustrati in \secref{sec:sig_job_control}. 
 
-In un sistema che supporta il \textit{job cotrol} una volta completato il
+In un sistema che supporta il \textit{job control} una volta completato il
 login (che esamineremo in dettaglio in \secref{sec:sess_login}), l'utente avrà
 a disposizione una shell dalla quale eseguire i comandi e potrà iniziare
 quella che viene chiamata una \textsl{sessione}, che riunisce (vedi
-\secref{sec:sess_sessions}) tutti i processi eseguiti all'interno dello stesso
-login.
+\secref{sec:sess_proc_group}) tutti i processi eseguiti all'interno dello
+stesso login.
 
 Siccome la shell è collegata ad un solo terminale (il \textsl{terminale di
   controllo}, vedi \secref{sec:sess_control_term}) solo un comando alla volta,
@@ -66,76 +66,206 @@ originano da una riga di comando appartengano allo stesso \textit{process
   group}, in modo che le varie funzioni di controllo, ed i segnali inviati dal
 terminale, possano fare riferimento ad esso.
 
-In generale allora all'interno di una sessione avremo un solo \textit{process
-  group} in \textit{foreground}, che riunisce i processi che possono accedere
-al terminale, e più \textit{process group} in \textit{background}, che non
+In generale allora all'interno di una sessione avremo un eventuale (possono
+non esserci comandi in \textit{foreground}) \textit{process group} in
+\textit{foreground}, che riunisce i processi che possono accedere al
+terminale, e più \textit{process group} in \textit{background}, che non
 possono accedervi. Il job control prevede che quando un processo appartenente
 ad un raggruppamento in \textit{background} cerca di accedere al terminale
 questo invii a tutti i processi del raggruppamento un segnale di
-\macro{SIGTTIN} o di \macro{SIGTTOU} (a seconda che l'accesso sia in lettura o
-scrittura)
-
-
-
-
-
-
-
-
-
-
-
-
-\subsection{I \textit{process group}}
+\macro{SIGTTIN} o di \macro{SIGTTOU}, a seconda che l'accesso sia
+rispettivamente in lettura o scrittura, bloccando (secondo il comportamento
+di default esposto in \secref{sec:sig_job_control}) i processi.
+
+Un comportamento analogo sia ha anche per i segnali generati dai comandi di
+tastiera inviati dal terminale con \cmd{C-z}, \cmd{C-c}, \cmd{C-y} e
+\verb|C-\|; questi generano rispettivamente i segnali \macro{SIGTSTP},
+\macro{SIGINT}, \macro{SIGQUIT} e \macro{SIGTERM}, che vengono inviati a tutti
+i processi del raggruppamento in \textit{foreground}. In particolare il primo
+di essi, \macro{SIGTSTP}, interrompe l'esecuzione del comando, che può poi
+essere mandato in \textit{background} con il comando \cmd{bg}. Il comando
+\cmd{fg} consente invece di mettere in \textit{foreground} un comando
+precedentemente lanciato in \textit{background}.
+
+Di norma la shell si cura anche di notificare all'utente (di solito prima
+della stampa a video del prompt) lo stato dei vari processi, essa infatti usa
+le caratteristiche della funzione \func{waitpid} (si riveda quanto detto in
+\secref{sec:proc_wait}) per verificare quali gruppi di processi sono bloccati
+e quali sono terminati. 
+
+
+\subsection{I \textit{process group} e le \textsl{sessioni}}
 \label{sec:sess_proc_group}
 
+Come accennato in \secref{sec:sess_job_control_overview} nel job control i
+processi vengono raggruppati in \textit{process group} e \textit{sessioni};
+per far questo vengono utilizzati due ulteriori identificatori (oltre quelli
+visti in \secref{sec:proc_pid}) che il kernel associa a ciascun processo:
+l'identificatore del \textit{process group} e l'identificatore della
+\textsl{sessione}, che vengono indicati rispettivamente con le sigle
+\acr{pgid} e \acr{sid}, e sono mantenuti in variabili di tipo \type{pid\_t}. I
+valori di questi identificatori possono essere visualizzati dal comando
+\cmd{ps} usando l'opzione \cmd{-j}.
+
+Un \textit{process group} è pertanto definito da tutti i processi che hanno lo
+stesso \acr{pgid}; è possibile leggere il valore di questo identificatore con
+le funzioni \func{getpgid} e \func{getpgrp},\footnote{\func{getpgrp} è
+  definita nello standard POSIX.1, mentre \func{getpgid} è richiesta da SVr4.}
+i cui prototipi sono:
+\begin{functions}
+  \headdecl{unistd.h}
+
+  \funcdecl{pid\_t getpgid(pid\_t pid)} 
+  Legge il \acr{pgid} del processo \param{pid}.
+
+  \funcdecl{pid\_t getpgrp(void)}
+  Legge il \acr{pgid} del processo corrente.
+  
+  \bodydesc{Le funzioni restituiscono il \acr{pgid} del processo,
+    \func{getpgrp} ha sempre successo, mentre \func{getpgid} restituisce -1
+    ponendo \var{errno} a \macro{ESRCH} se il processo selezionato non esiste.}
+\end{functions}
+
+La funzione \func{getpgid} permette di specificare il \acr{pid} del processo
+di cui si vuole sapere il \acr{pgid}; un valore nullo per \param{pid}
+restituisce il \acr{pgid} del processo corrente; \func{getpgrp} è di norma
+equivalente a \code{getpgid(0)}.
+
+In maniera analoga l'identificatore della sessione può essere letto dalla
+funzione \func{getsid}, che però nelle \acr{glibc}\footnote{la system call è
+  stata introdotta in Linux a partire dalla versione 1.3.44, il supporto nelle
+  librerie del C è iniziato dalla versione 5.2.19. La funzione non è prevista
+  da POSIX.1, che parla solo di processi leader di sessione, e non di
+  \textit{session id}.} è accessibile solo definendo \macro{\_XOPEN\_SOURCE} e
+\macro{\_XOPEN\_SOURCE\_EXTENDED}; il suo prototipo è:
+\begin{prototype}{unistd.h}{pid\_t getsid(pid\_t pid)}
+  Legge l'identificatore di sessione del processo \param{pid}.
+  
+  \bodydesc{La funzione restituisce l'identificatore (un numero positivo) in
+  caso di successo, e -1 in caso di errore, nel qual caso \var{errno} assumerà
+  i valori:
+    \begin{errlist}
+    \item[\macro{ESRCH}] Il processo selezionato non esiste.
+    \item[\macro{EPERM}] In alcune implementazioni viene restituito quando il
+      processo selezionato non fa parte della stessa sessione del processo
+      corrente.
+    \end{errlist}
+  }
+\end{prototype}
+
+Entrambi gli identificatori vengono inizializzati alla creazione di ciascun
+processo con lo stesso valore che hanno nel processo padre, per cui un
+processo appena creato appartiene sempre allo stesso raggruppamento e alla
+stessa sessione del padre. Vedremo poi come sia possibile creare più
+\textit{process group} all'interno della stessa sessione, e spostare i
+processi dall'uno all'altro, ma sempre all'interno di una stessa sessione.
+
+Ciascun gruppo di processi ha sempre un processo principale, il cosiddetto
+\textit{process group leader}, che è identificato dall'avere un \acr{pgid}
+uguale al suo \acr{pid}, in genere questo è il primo processo del gruppo, che
+si incarica di lanciare tutti gli altri. Un nuovo gruppo si crea con la
+funzione \func{setpgrp},\footnote{questa è la definizione di POSIX.1, BSD
+  definisce una funzione con lo stesso nome, che però è identica a
+  \func{setpgid}; nelle \acr{glibc} viene sempre usata sempre questa
+  definizione, a meno di non richiedere esplicitamente la compatibilità
+  all'indietro con BSD, definendo la macro \macro{\_BSD\_SOURCE}.} il cui
+prototipo è:
+\begin{prototype}{unistd.h}{int setpgrp(void)}
+  Modifica il \acr{pgid} al valore del \acr{pid} del processo corrente.
+  
+  \bodydesc{La funzione restituisce il valore del nuovo \textit{process
+      group}.}
+\end{prototype}
+
+La funzione, assegnando al \acr{pgid} il valore del \acr{pid} processo
+corrente, rende questo \textit{process leader} di un nuovo gruppo, tutti i
+successivi processi da esso creati apparterranno (a meno di non cambiare di
+nuovo il \acr{pgid}) al nuovo gruppo. È possibile invece spostare un processo
+da un gruppo ad un altro con la funzione \func{setpgid}, il cui prototipo è:
+\begin{prototype}{unistd.h}{int setpgid(pid\_t pid, pid\_t pgid)}
+  Assegna al \acr{pgid} del processo \param{pid} il valore \param{pgid}.
+  
+  \bodydesc{La funzione ritorna il valore del nuovo \textit{process group}, e
+  -1 in caso di errore, nel qual caso \var{errno} assumerà i valori:
+    \begin{errlist}
+    \item[\macro{ESRCH}] Il processo selezionato non esiste.
+    \item[\macro{EPERM}] Il cambiamento non è consentito.
+    \item[\macro{EINVAL}] Il valore di \param{pgid} è negativo.
+    \end{errlist}
+ }
+\end{prototype}
+
+La funzione permette di cambiare il \acr{pgid} del processo \param{pid}, ma il
+cambiamento può essere effettuato solo se \param{pgid} indica un
+\textit{process group} che è nella stessa sessione del processo chiamante.
+Inoltre la funzione può essere usata soltanto sul processo corrente o su uno
+dei suoi figli, ed in quest'ultimo caso ha successo soltanto se questo non ha
+ancora eseguito una \func{exec}. Specificando un valore nullo per \param{pid}
+si indica il processo corrente, mentre specificando un valore nullo per
+\param{pgid} si imposta il \textit{process group} al valore del \acr{pid} del
+processo selezionato; pertanto \func{setpgrp} è equivalente a \code{setpgid(0,
+  0)}.
+
+Di norma questa funzione viene usata dalla shell quando si usano delle
+pipeline, per mettere nello stesso process group tutti i programmi lanciati su
+ogni linea di comando; essa viene chiamata dopo una \func{fork} sia dal
+processo padre, per impostare il valore nel figlio, che da quest'ultimo, per
+sé stesso, in modo che il cambiamento di \textit{process group} sia immediato
+per entrambi; una delle due chiamate sarà ridondante, ma non potendo
+determinare quale dei due processi viene eseguito per primo, occorre eseguirle
+comunque entrambe per evitare di esporsi ad una race condition. 
+
+Si noti come nessuna delle funzioni esaminate finora permetta di spostare un
+processo da una sessione ad un altra; infatti l'unico modo di far cambiare
+sessione ad un processo è quello di crearne una nuova con l'uso di
+\func{setsid}; il suo prototipo è:
+\begin{prototype}{unistd.h}{pid\_t setsid(void)}
+  Crea una nuova sessione sul processo corrente settandone \acr{sid} e
+  \acr{pgid}.
+  
+  \bodydesc{La funzione ritorna il valore del nuovo \acr{sid}, e -1 in caso di
+    errore, il solo errore possibile è \macro{EPERM}, che si ha quando il
+    \acr{pgid} e \acr{pid} del processo concidono.}
+\end{prototype}
+
+La funzione imposta il \acr{pgid} ed il \acr{sid} del processo corrente al
+valore del suo \acr{pid}, creando così una nuova sessione ed un nuovo
+\textit{process group} di cui esso diventa leader (come per i \textit{process
+  group} un processo si dice leader di sessione se il suo \acr{sid} è uguale
+al suo \acr{pid}).  Infine il processo viene distaccato dal terminale di
+controllo.
+
+La funzione ha successo soltanto se il processo non è già leader per un
+\textit{process group}, per cui di norma si esegue una \func{fork} e si esce,
+per poi chiamare \func{setsid} nel processo figlio, in modo che, avendo questo
+lo stesso \acr{pgid} del padre ma un \acr{pid} diverso, non ci siano
+possibilità di errore.  Questa funzione viene usata di solito dal processo di
+login quando si lancia una nuova shell per un utente.
 
 
-Per poter gestire il \textit{Job Control} il kernel associa a ciascun processo
-due ulteriori identificatori (oltre quelli visti in \secref{sec:proc_pid}):
-l'identificatore del cosiddetto \textit{process group} (o
-\textsl{ragguppamento di processi}), cui si fa di norma riferimento con la
-sigla \acr{pgid}, l'identificatore di sessione (il \textit{session id}) cui si
-fa riferimento con la sigla \acr{sid}).  In questo modo, sulla base dei valori
-dei rispettivi indicatori, i processi vengono organizzati in \textsl{sessioni}
-e \textsl{raggruppamenti}.
-
-Entrambi gli identificatori vengono impostati alla creazione di ciascun
-processo allo stesso valore che hanno nel processo padre, un processo appena
-creato cioè appartiene sempre allo stesso raggruppamento e alla stessa
-sessione del padre. La differenza fra i due identificatori è che un processo
-può cambiare \acr{pgid} soltanto ad un valore che corrisponda al
-\textit{process group} di un altro processo della stessa sessione, oppure al
-suo stesso \acr{pid} (creando così un nuovo \textit{process group}). Se invece
-si modifica il \acr{sid} il processo viene automaticamente messo anche in un
-nuovo \textit{process group}, corrispondente al suo \acr{pid}.
-
-
-
-
-\subsection{Le sessioni}
-\label{sec:sess_sessions}
-
 
 
 \subsection{Il terminale di controllo}
 \label{sec:sess_ctrl_term}
 
+Come accennato in \secref{sec:sess_job_control_overview} ad ogni sessione di
+lavoro è associato un terminale di controllo.  
 
 
-\subsection{La procedura di login}
+
+\subsection{Dal login alla shell}
 \label{sec:sess_login}
 
 L'organizzazione del sistema del job control è strettamente connessa alle
-modalità con cui un utente accede al sistema, collegandosi ad esso con un
-terminale, che sia questo realmente tale, come un VT100 collegato ad una
-seriale o virtuale, come quelli associati a schermo e tastiera o ad una
+modalità con cui un utente accede al sistema per dare comandi, collegandosi ad
+esso con un terminale, che sia questo realmente tale, come un VT100 collegato
+ad una seriale o virtuale, come quelli associati a schermo e tastiera o ad una
 connessione di rete. Dato che i concetti base sono gli stessi, e dato che alla
 fine le differenze sono\footnote{in generale nel caso di login via rete o di
   terminali lanciati dall'interfaccia grafica cambia anche il processo da cui
   ha origine l'esecuzione della shell.} nel device cui il kernel associa i
-file standard di \secref{sec:file_std_descr}, tratteremo solo il caso in
-questo è il classico terminale.
+file standard (vedi \secref{sec:file_std_descr}) per l'I/O, tratteremo solo il
+caso classico del terminale.
 
 Abbiamo già brevemente illustrato in \secref{sec:intro_kern_and_sys} le
 modalità con cui il sistema si avvia, e di come, a partire da \cmd{init},
@@ -185,15 +315,17 @@ dall'amministratore nel file di configurazione del programma,
 \file{/etc/inittab}.
 
 Quando viene lanciato da \cmd{init} il programma parte con i privilegi di
-amministratore e con un ambiente vuoto; \cmd{getty} si cura di aprire il
-terminale in lettura sullo standard input ed in scrittura sullo standard
-output e sullo standard error, e di effettuare, qualora servano, ulteriori
-settaggi,\footnote{ad esempio, come qualcuno si sarà accorto scrivendo un nome
-  di login in maiuscolo, può effettuare la conversione automatica dell'input
-  in minuscolo, ponendosi in una modalità speciale che non distingue fra i due
-  tipi di caratteri (a beneficio di alcuni vecchi terminali che non
-  supportavano le minuscole).} ed infine il programma stamperà un messaggio di
-benvenuto per poi porsi in attesa dell'immissione del nome di un utente.
+amministratore e con un ambiente vuoto; \cmd{getty} si cura di chiamare
+\func{setsid} per creare una nuova sessione ed un nuovo process group, e di
+aprire il terminale in lettura sullo standard input ed in scrittura sullo
+standard output e sullo standard error, e di effettuare, qualora servano,
+ulteriori settaggi,\footnote{ad esempio, come qualcuno si sarà accorto
+  scrivendo un nome di login in maiuscolo, può effettuare la conversione
+  automatica dell'input in minuscolo, ponendosi in una modalità speciale che
+  non distingue fra i due tipi di caratteri (a beneficio di alcuni vecchi
+  terminali che non supportavano le minuscole).} ed infine il programma
+stamperà un messaggio di benvenuto per poi porsi in attesa dell'immissione del
+nome di un utente.
 
 Una volta che si sia immesso il nome di login \cmd{getty} esegue direttamente
 il programma \cmd{login} con una \func{exevle}, passando come argomento la
@@ -235,12 +367,7 @@ che il processo genitore resta sempre \cmd{init} quest'ultimo provveder
 ricevendo un \macro{SIGCHLD} all'uscita della shell, a rilanciare \cmd{getty}
 per ripetere da capo tutto il procedimento.
 
-
-
-
-Lo stato del sistema può essere verificato con il comando \cmd{ps -je f}
-
-
+Una volta arrivati alla