X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=session.tex;h=2f73d61b53bd790d8a3f0303dcf86eb926c7ac63;hp=92e532d847973d7be79692c3daaf934010c6ebd3;hb=9448294bbb0d4ffbf8e606a39e5c0c616776cbde;hpb=c21ecd755b45e99ed8b1524e03444bf189bfcc06 diff --git a/session.tex b/session.tex index 92e532d..2f73d61 100644 --- a/session.tex +++ b/session.tex @@ -43,13 +43,13 @@ potr 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 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. 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 -\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 @@ -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} -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 -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 @@ -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. -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 @@ -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 -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 è -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} @@ -414,6 +555,21 @@ ricevendo un \macro{SIGCHLD} all'uscita della shell, a rilanciare \cmd{getty} 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}