Ancora orphaned process group
[gapil.git] / session.tex
index 92e532d847973d7be79692c3daaf934010c6ebd3..2f73d61b53bd790d8a3f0303dcf86eb926c7ac63 100644 (file)
@@ -43,13 +43,13 @@ potr
 dello stesso login (esamineremo tutto il processo in dettaglio in
 \secref{sec:sess_login}).
 
 dello stesso login (esamineremo tutto il processo in dettaglio in
 \secref{sec:sess_login}).
 
-Siccome la shell è collegata ad un solo terminale (che viene usualmente
-chiamato \textsl{terminale di controllo}, vedi \secref{sec:sess_ctrl_term}) un
-solo comando alla volta (quello che viene detto in \textit{foreground}), potrà
-scrivere e leggere dal terminale. La shell però può eseguire anche più comandi
-in contemporanea, mandandoli in \textit{background} (aggiungendo una \cmd{\&}
-alla fine del comando), nel qual caso essi saranno eseguiti senza essere
-collegati al terminale.
+Siccome la shell è collegata ad un solo terminaleche viene usualmente
+chiamato \textsl{terminale di controllo}, (vedi \secref{sec:sess_ctrl_term})
+un solo comando alla volta (quello che viene detto in \textit{foreground}),
+potrà scrivere e leggere dal terminale. La shell però può eseguire anche più
+comandi in contemporanea, mandandoli in \textit{background} (aggiungendo una
+\cmd{\&} alla fine del comando), nel qual caso essi saranno eseguiti senza
+essere collegati al terminale.
 
 Si noti come si sia parlato di comandi e non di programmi o processi; fra le
 funzionalità della shell infatti c'è anche quella di consentire di concatenare
 
 Si noti come si sia parlato di comandi e non di programmi o processi; fra le
 funzionalità della shell infatti c'è anche quella di consentire di concatenare
@@ -60,7 +60,7 @@ questo potr
 Per questo l'esecuzione di un comando può originare più di un processo; quindi
 nella gestione del job control non si può far riferimento ai singoli processi.
 Per questo il kernel prevede la possibilità di raggruppare più processi in un
 Per questo l'esecuzione di un comando può originare più di un processo; quindi
 nella gestione del job control non si può far riferimento ai singoli processi.
 Per questo il kernel prevede la possibilità di raggruppare più processi in un
-\textit{process group} (detto anche \textsl{raggruppamento}, vedi
+\textit{process group} (detto anche \textsl{raggruppamento di processi}, vedi
 \secref{sec:sess_proc_group}) e la shell farà sì che tutti i processi che
 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
 \secref{sec:sess_proc_group}) e la shell farà sì che tutti i processi che
 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
@@ -71,21 +71,16 @@ non esserci) \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}
 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 rispettivamente in lettura o scrittura, bloccando (secondo
-il comportamento di default esposto in \secref{sec:sig_job_control}) i
-processi.
+cerca di accedere al terminale, venga inviato un segnale a tutti i processi
+del raggruppamento, in modo da bloccarli (vedi \secref{sec:sess_ctrl_term}).
 
 Un comportamento analogo si ha anche per i segnali generati dai comandi di
 
 Un comportamento analogo si 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}.
+tastiera inviati dal terminale che vengono inviati a tutti i processi del
+raggruppamento in \textit{foreground}. In particolare \cmd{C-z} 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
 
 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
@@ -242,7 +237,7 @@ componente.  Inoltre la funzione distacca il processo da ogni terminale di
 controllo (torneremo sull'argomento in \secref{sec:sess_ctrl_term}) cui fosse
 in precedenza associato.
 
 controllo (torneremo sull'argomento in \secref{sec:sess_ctrl_term}) cui fosse
 in precedenza associato.
 
-La funzione ha successo soltanto se il processo non è già leader di un
+  funzione ha successo soltanto se il processo non è già leader di un
 \textit{process group}, per cui per usarla 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
 \textit{process group}, per cui per usarla 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
@@ -278,26 +273,172 @@ di controllo. \footnote{Lo standard POSIX.1 non specifica nulla riguardo
   l'implementazione; in Linux anch'esso viene mantenuto nella solita struttura
   \var{task\_struct}, nel campo \var{tty}.}  In generale ogni processo eredita
 dal padre, insieme al \acr{pgid} e al \acr{sid} anche il terminale di
   l'implementazione; in Linux anch'esso viene mantenuto nella solita struttura
   \var{task\_struct}, nel campo \var{tty}.}  In generale ogni processo eredita
 dal padre, insieme al \acr{pgid} e al \acr{sid} anche il terminale di
-controllo. In questo modo tutti processi originati dallo stesso leader di
-sessione mantengono lo stesso terminale di controllo.
+controllo (vedi \secref{sec:proc_fork}). In questo modo tutti processi
+originati dallo stesso leader di sessione mantengono lo stesso terminale di
+controllo.
 
 Alla creazione di una nuova sessione con \func{setsid} ogni associazione con
 il precedente terminale di controllo viene cancellata, ed il processo che è
 
 Alla creazione di una nuova sessione con \func{setsid} ogni associazione con
 il precedente terminale di controllo viene cancellata, ed il processo che è
-divenuto un nuovo leader di sessione dovrà riottenere (qualora sia necessario,
-cosa che, come vedremo in \secref{sec:sess_daemon}, non è sempre vera), un
-terminale di controllo. In generale questo viene fatto automaticamente dal
-sistema quando il leader di sessione apre il suo primo terminale\footnote{a
-  meno di non avere richiesto esplicitamente che questo non diventi un
-  terminale di controllo con il flag \macro{O\_NOCTTY} (vedi
-  \secref{sec:file_open}). In questo Linux segue la semantica di SVr4; BSD
-  invece richiede che il terminale venga allocato esplicitamente con una
-  \func{ioctl} con il comando \macro{TIOCSCTTY}.} che diventa automaticamente
-il terminale di controllo. 
-
-Per ciascuna sessione di lavoro avremo allora un terminale di controllo, ed un
-processo di \textit{foreground}, che è quello 
-
-Il kernel identifica 
+divenuto un nuovo leader di sessione dovrà riottenere\footnote{solo quando ciò
+  è necessario, cosa che, come vedremo in \secref{sec:sess_daemon}, non è
+  sempre vera}, un terminale di controllo. In generale questo viene fatto
+automaticamente dal sistema\footnote{a meno di non avere richiesto
+  esplicitamente che questo non diventi un terminale di controllo con il flag
+  \macro{O\_NOCTTY} (vedi \secref{sec:file_open}). In questo Linux segue la
+  semantica di SVr4; BSD invece richiede che il terminale venga allocato
+  esplicitamente con una \func{ioctl} con il comando \macro{TIOCSCTTY}.}
+quando viene aperto il primo terminale (cioè uno dei vari file di dispositivo
+\file{/dev/tty*}) che diventa automaticamente il terminale di controllo,
+mentre il processo diventa il \textsl{processo di controllo} di quella
+sessione.
+
+In genere (a meno di redirezioni) nelle sessioni di lavoro questo terminale è
+associato ai file standard (di input, output ed error) dei processi nella
+sessione, ma solo quelli che fanno parte del cosiddetto gruppo di
+\textit{foreground}, possono leggere e scrivere in certo istante. Per
+impostare il gruppo di \textit{foreground} di un terminale si usa la funzione
+\func{tcsetpgrp}, il cui prototipo è:
+\begin{functions}
+  \headdecl{unistd.h}
+  \headdecl{termios.h}
+  
+  \funcdecl{int tcsetpgrp(int fd, pid\_t pgrpid)} Imposta a \param{pgrpid} il
+  \textit{process group} di \textit{foreground} del terminale associato al
+  file descriptor \param{fd}.
+   
+  \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+    errore, nel qual caso \var{errno} assumerà i valori:
+    \begin{errlist}
+    \item[\macro{ENOTTY}] Il file \param{fd} non corrisponde al terminale di
+      controllo del processo chiamante.
+    \item[\macro{ENOSYS}] Il sistema non supporta il job control.
+    \item[\macro{EPERM}] Il \textit{process group} specificato non è nella
+    stessa sessione del processo chiamante.
+    \end{errlist}
+    ed inoltre \macro{EBADF} ed \macro{EINVAL}. 
+  }
+\end{functions}
+\noindent la funzione può essere eseguita con successo solo da
+un processo nella stessa sessione e con lo stesso terminale di controllo. 
+
+Come accennato in \secref{sec:sess_job_control_overview}, tutti i processi (e
+relativi gruppi) che non fanno parte del gruppo di \textit{foreground} sono
+detti in \textit{background}; se uno si essi cerca di accedere al terminale di
+controllo provocherà l'invio da parte del kernel di uno dei due segnali
+\macro{SIGTTIN} o \macro{SIGTTOU} (a seconda che l'accesso sia stato in
+lettura o scrittura) a tutto il suo \textit{process group}; dato che il
+comportamento di default di questi segnali (si riveda quanto esposto in
+\secref{sec:sig_job_control}) è di bloccare il processo, di norma questo
+comporta che tutti i membri del gruppo verranno fermati, ma non si avranno
+condizioni di errore.\footnote{la shell in genere notifica comunque un
+  avvertimento, avvertendo la presenza di processi bloccati grazie all'uso di
+  \func{waitpid}.} Se però si bloccano o ignorano i due segnali citati, le
+funzioni di lettura e scrittura falliranno con un errore di \macro{EIO}.
+
+Un processo può contollare qual'è il gruppo di \textit{foreground} associato
+ad un terminale con la funzione \func{tcgetpgrp}, il cui prototipo è:
+\begin{functions}
+  \headdecl{unistd.h} \headdecl{termios.h}
+  
+  \funcdecl{pid\_t tcgetpgrp(int fd)} Legge il \textit{process group} di
+  \textit{foreground} del terminale associato al file descriptor \param{fd}.
+  \bodydesc{La funzione restituisce in caso di successo il \acr{pgid} del
+    gruppo di \textit{foreground}, e -1 in caso di errore, nel qual caso
+    \var{errno} assumerà i valori:
+    \begin{errlist}
+    \item[\macro{ENOTTY}] Non c'è un terminale di controllo o \param{fd} non
+      corrisponde al terminale di controllo del processo chiamante.
+    \end{errlist}
+    ed inoltre \macro{EBADF} ed \macro{ENOSYS}. 
+  }
+\end{functions}
+
+Si noti come entrambe le funzioni usino come argomento il valore di un file
+descriptor, il risultato comunque non dipende dal file descriptor che si usa
+ma solo dal terminale cui fa riferimento; il kernel inoltre permette a ciascun
+processo di accedere direttamente al suo terminale di controllo attraverso il
+file speciale \file{/dev/tty}, che per ogni processo è un sinonimo per il
+proprio terminale di controllo.  Questo consente anche a processi che possono
+aver rediretto l'output di accedere al terminale, pur non disponendo più del
+file descriptor originario; un caso tipico è il programma \cmd{crypt} che
+accetta la redirezione sullo standard input di un file da decrittare, ma deve
+poi leggere la password dal terminale.
+
+Un'altra caratteristica del terminale di controllo usata nel job control è che
+utilizzando su di esso le combinazioni di tasti speciali (\cmd{C-z},
+\cmd{C-c}, \cmd{C-y} e \verb|C-\|) si farà si che il kernel invii i
+corrispondenti segnali (rispettivamente \macro{SIGTSTP}, \macro{SIGINT},
+\macro{SIGQUIT} e \macro{SIGTERM}, trattati in \secref{sec:sig_job_control}) a
+tutti i processi del gruppo di \textit{foreground}; in questo modo la shell
+può gestire il blocco e l'interruzione dei vari comandi.
+Per completare la trattazione delle caratteristiche del job control legate al
+terminale di controllo, occorre prendere in considerazione i vari casi legati
+alla terminazione anomala dei processi, che sono di norma gestite attraverso
+il segnale \macro{SIGHUP}. Il nome del segnale deriva da \textit{hungup},
+termine che viene usato per indicare la condizione in cui il terminale diventa
+inutilizzabile, (letteralmente sarebbe \textsl{impiccagione}). 
+
+Quando si verifica questa condizione, ad esempio se si interrompe la linea, o
+va giù la rete o più semplicemente si chiude forzatamente la finestra di
+terminale su cui si stava lavorando, il kernel provvederà ad inviare il
+segnale di \macro{SIGHUP} al processo di controllo. L'azione preimpostata in
+questo caso è la terminazione del processo, il problema che si pone è cosa
+accade agli altri processi nella sessione, che non han più un processo di
+controllo che possa gestire l'accesso al terminale, che potrebbe essere
+riutilizzato per qualche altra sessione.
+
+Lo standard POSIX.1 prevede che quando il processo di controllo termina, che
+ciò avvenga o meno per un \textit{hungup} del terminale (ad esempio si
+potrebbe terminare direttamente la shell con \cmd{kill}) venga inviato un
+segnale di \macro{SIGHUP} ai processi del gruppo di foreground. In questo modo
+essi potranno essere avvisati che non esiste più un processo in grado di
+gestire il terminale (di norma tutto ciò comporta la terminazione anche di
+questi ultimi).
+
+Restano però gli eventuali processi in background, che non ricevono il
+segnale; in effetti se il terminale non dovesse più servire essi potrebbero
+proseguire fino al completamento della loro esecuzione; ma si pone il problema
+di come gestire quelli che sono bloccati, o che si bloccano nell'accesso al
+terminale, in assenza di un processo che sia in grado di effettuare il
+controllo dello stesso.
+
+Questa è la situazione in cui si ha quello che viene chiamato un
+\textit{orphaned process group}. Lo standard POSIX.1 lo definisce come un
+\textit{process group} i cui processi hanno come padri esclusivamente o altri
+processi nel gruppo, o processi fuori della sessione.  Lo standard prevede
+inoltre che se la terminazione di un processo fa sì che un raggruppamento di
+processi diventi orfano e se i suoi membri sono bloccati, ad essi vengano
+inviati in sequenza i segnali di \macro{SIGHUP} e \macro{SIGCONT}.
+
+La definizione può sembrare complicata, e a prima vista non è chiaro cosa
+tutto ciò abbia a che fare con il problema della terminazione del processo di
+controllo.  Consideriamo allora cosa avviene di norma nel \textit{job
+  control}: una sessione viene creata con \func{setsid} che crea anche un
+nuovo process group: per definizione quest'ultimo è sempre \textsl{orfano},
+dato che il padre del leader di sessione è fuori dalla stessa e il nuovo
+process group contiene solo il leader di sessione. Questo è un caso limite, e
+non viene emesso nessun segnale perché quanto previsto dallo standard riguarda
+solo i raggruppamenti che diventano orfani in seguito alla terminazione di un
+processo.\footnote{l'emissione dei segnali infatti avviene solo nella fase di
+  uscita del processo, come una delle operazioni legate all'esecuzione di
+  \func{_exit}, secondo quanto illustrato in \secref{sec:proc_termination}.}
+
+Il leader di sessione provvederà a creare nuovi raggruppamenti di processi che
+a questo punto non sono orfani in quanto esso resta padre per almeno uno dei
+processi del gruppo (gli altri possono derivare dal primo). Alla terminazione
+del leader di sessione però avremo che, come visto in
+\secref{sec:proc_termination}, tutti i suoi figli vengono adottati da
+\cmd{init}, che è fuori dalla sessione. Questo renderà orfani tutti i process
+group creati direttamente dal leader di sessione (a meno di non aver spostato
+con \func{setpgid} un processo da un gruppo ad un altro, cosa che di norma non
+viene fatta) i quali riceveranno, nel caso siano bloccati, i due segnali:
+\macro{SIGCONT} ne farà proseguire l'esecuzione, e, essendo stato nel
+frattempo inviato anche \macro{SIGHUP}, se non c'è un gestore per
+quest'ultimo, essi saranno terminati.
+
+
+
 
 \subsection{Dal login alla shell}
 \label{sec:sess_login}
 
 \subsection{Dal login alla shell}
 \label{sec:sess_login}
@@ -414,6 +555,21 @@ ricevendo un \macro{SIGCHLD} all'uscita della shell, a rilanciare \cmd{getty}
 per ripetere da capo tutto il procedimento.
 
 
 per ripetere da capo tutto il procedimento.
 
 
+In generale quando con il contollo di sessione è la shell che assume il ruolo
+di processo di controllo, seleziona il gruppo di \textit{foregroud} e gestisce
+l'assegnazione dei process group ai programmi eseguiti sulla stessa riga di
+comando. 
+
+Qualora un processo venga bloccato nella gestione della sessione, sia
+implicitamente, perché cerca di eseguire dell'I/O sul terminale mentre è in
+background, sia esplicitamente con l'uso di \cmd{C-z}, la shell è in grado di
+rilevare l'evento grazie all'uso di \func{waitpid} con l'opzione
+\macro{WUNTRACED}. In questo modo la shell può notificare (di solito prima
+della stampa del prompt, lo stato dei vari processi. 
+
+
+
+
 
 \subsection{Prescrizioni per un programma \textit{daemon}}
 \label{sec:sess_daemon}
 
 \subsection{Prescrizioni per un programma \textit{daemon}}
 \label{sec:sess_daemon}