X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=session.tex;h=13bc2c5efdb1a620ca87dfca80420e65e38a1664;hp=d3a0e4febe57d617587780caa081c02688c04bb7;hb=0b590bfee0819bda5f875e4b53fa0e44715d2b92;hpb=8709795cc47d95b76fb055211d8b856c06d9c4e0 diff --git a/session.tex b/session.tex index d3a0e4f..13bc2c5 100644 --- a/session.tex +++ b/session.tex @@ -1,39 +1,277 @@ -\chapter{Sessioni di lavoro} + \chapter{Sessioni di lavoro e terminali} \label{cha:session} -Esamineremo in questo capitolo le modalità in cui sono organizzati i processi -all'interno del sistema e le varie relazioni che intercorrono fra di essi, e -le modalità che permettono, a partire dall'avvio del sistema, di organizzare -il lavoro degli utenti in sessioni di lavoro associate ai terminali di -controllo con cui essi si sono collegati al sistema. +Esamineremo in questo capitolo i concetti base del sistema delle sessioni di +lavoro, vale a dire il metodo con cui il kernel gestisce l'accesso concorrente +al sistema da parte di più utenti, permettendo loro di eseguire più programmi +in contemporanea. Nella seconda parte del capitolo tratteremo poi il +funzionamento dell'I/O su terminale, e delle varie peculiarità che esso viene +ad assumere a causa del suo stretto legame con le modalità di accesso al +sistema da parte degli utenti. -\section{La procedura di login} + +\section{Il \textit{job control}} +\label{sec:sess_job_control} + +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 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. + + +\subsection{Una panoramica introduttiva} +\label{sec:sess_job_control_overview} + +Il \textit{job control} è una caratteristica opzionale, introdotta in BSD +negli anni '80, e successivamente standardizzata da POSIX.1; la sua +disponibilità nel sistema è verificabile attraverso il controllo della macro +\macro{\_POSIX\_JOB\_CONTROL}. In generale il \textit{job control} richiede il +supporto sia da parte della shell (quasi tutte ormai lo fanno), che da parte +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 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_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, +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} (si fa 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 +più programmi in una sola riga di comando con le pipe, ed in tal caso verranno +eseguiti più programmi, inoltre, anche quando si invoca un singolo programma, +questo potrà sempre lanciare altri processi per eseguire dei compiti +specifici. + +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 +\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 +terminale, possano fare riferimento ad esso. + +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 +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. + + + + +\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{Dal login alla shell} \label{sec:sess_login} -L'organizzazione del sistema del \textit{Job Control}\footnote{viene - usualmente chiamata così la capacità del sistema di poter gestire più - processi (i \textit{job}) lanciati in contemporanea a partire da una shell, - di solito associata al terminale su cui si è appunto effettuato il login, in - modo da poter gestire la possibile presenza di più di un processo che - necessita di accedere a quest'ultimo.} è 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 semplicemente -associato ad una connessione di rete. Per questo motivo in questa prima -sezione prenderemo in esame le modalità di come avviene tutto ciò e di come il -sistema (a partire da \cmd{init}) sia in grado di gestire il tutto. - - -\subsection{Il login su terminale} -\label{sec:sess_tty_log} - -La modalità più classica di accesso ad un sistema Unix è quella del login su -terminale, che pertanto esamineremo per prima. 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}, vengano lanciati tutti gli altri -programmi. Adesso prenderemo in esame in maniera dettagliata le modalità con -cui si arriva a fornire ad un utente la shell che gli permette di lanciare i -suoi comandi. +L'organizzazione del sistema del job control è strettamente connessa alle +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 (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}, +vengano lanciati tutti gli altri processi. Adesso vedremo in maniera più +dettagliata le modalità con cui il sistema arriva a fornire ad un utente la +shell che gli permette di lanciare i suoi comandi su un terminale. Nella maggior parte delle distribuzioni di GNU/Linux\footnote{fa eccezione la distribuzione \textit{Slackware}, come alcune distribuzioni su dischetto, ed @@ -44,8 +282,8 @@ lanciati, ed in quali modalit anch'esso definito nello stesso file. Tralasciando la descrizione del sistema dei run level, (per il quale si -rimanda alla lettura della pagina di manuale di \cmd{init} e di -\file{inittab}) quello che comunque viene sempre fatto è di lanciare almeno +rimanda alla lettura delle pagine di manuale di \cmd{init} e di +\file{inittab}) quello che comunque viene sempre fatto è di eseguire almeno una istanza di un programma che permetta l'accesso ad un terminale. Uno schema di massima della procedura è riportato in \secref{fig:sess_term_login}. @@ -58,12 +296,13 @@ di massima della procedura Un terminale, che esso sia un terminale effettivo, attaccato ad una seriale o ad un altro tipo di porta di comunicazione, o una delle console virtuali -associate allo schermo, viene sempre visto attraverso attraverso un device +associate allo schermo, viene sempre visto attraverso attraverso un device driver che ne presenta un'interfaccia comune su un apposito file di dispositivo. Storicamente i primi terminali erano appunto terminali di telescriventi (\textit{teletype}), da cui deriva sia il nome dell'interfaccia, \textit{tty}, che quello dei relativi file di dispositivo, che sono sempre -della forma \texttt{/dev/tty*}. +della forma \texttt{/dev/tty*}.\footnote{questo vale anche per i terminali + associati alle connessioni di rete con \cmd{telnet} o \cmd{ssh}.} Per controllare i terminali si usa di solito il programma \cmd{getty} (od una delle sue varianti), che permette di mettersi in ascolto sugli stessi. Alla @@ -76,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 @@ -126,93 +367,16 @@ 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. +Una volta arrivati alla -\subsection{Il login via rete} -\label{sec:sess_net_log} - -Nel caso di un login via rete la cosa si fa leggermente diversa, in tal caso -infatti non esiste un terminale fisico che \cmd{init} può tenere sotto -controllo diretto, in quanto il collegamento deve avvenire tramite la rete. -Quello che succede in questo caso è che nel procedimento di avvio del sistema -si occupa di eseguire tutti i programmi che attivano la connesione di rete, -per poi avviare tutti i programmi di servizio. - -Questo viene in genere fatto attraverso una serie di script di shell, che -vengono eseguiti in un preciso ordine (di nuovo la struttura del procedimento -di avvio di System V va al di là di quanto ci interessa trattare) che -eseguiranno i programmi richiesti, fra i quali sarà compreso (se -l'amministratore lo avrà previsto) pure il server per le connessioni di rete. - -Quest'ultimo sarà posto in esecuzione e si metterà in ascolto di eventuali -connessioni sulla rete, una volta che la procedura di avvio sarà completata -gli script termineranno ed il server si troverà ad avere \cmd{init} come -processo padre. - - -\subsection{Il login attraverso X} -\label{sec:sess_X_log} - -Quanto scritto finora riguardo i terminali è piuttosto diverso quando si ha a -che fare con X. In tal caso infatti la procedura grafica per il login è -gestira da un apposito programma (il cosiddetto \textit{Display Manager}, come -\cmd{xdm}, che fa parte della distribuzione base di X o uno dei suoi molti -cloni) che viene lanciato all'avvio insieme agli altri demoni, e che si cura -di gestire la procedura di login, lanciare eventuali programmi che si vogliono -attivare all'avvio (sia fondamentali, come il gestore delle fineste, che -effimeri, come un notificatore di posta in arrivo). -In questo caso - - - -\section{Il \textit{Job control}} -\label{sec:sess_job_control} - -Lo scopo del \textit{Job control} è 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ò 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. - - - -\subsection{La struttura di base} -\label{sec:sess_relation} - -Una volta che si è completata la procedura di login illustrata in -\ref{sec:sess_login} si avrà a disposizione una shell dalla quale eseguire i -comandi. Come illustrato in \secref{sec:intro_kern_and_sys} in un sistema Unix -questi non sono altro che programmi come gli altri, inoltre essendo il sistema -multitasking, non è neanche detto che un programma venga eseguito da un solo -processo, infatti, oltre all'uso delle pipe, che permette di concatenare più -con un solo comando, ed i sigoli programmi possono anche creare ulteriori -sottoprocessi per eseguire alcuni compiti. - -Tutti questi processi, che originano da un solo comando iniziale, vengono -raggruppati in quello che viene chiamato un \textit{process group}; quando -viene creato ogni -processo viene infatti mantenuto, - - -\subsection{I \textit{process group}} -\label{sec:sess_proc_group} - - - -\subsection{Le sessioni} -\label{sec:sess_sessions} - - - -\subsection{Il terminale di controllo} -\label{sec:sess_ctrl_term} +\section{L'I/O su terminale} +\label{sec:sess_terminal_io} -\subsection{La shell e i programmi} -\label{sec:sess_shell} +Esamineremo in questa sezione le peculiarità dell'I/O su terminale, tenendo +conto delle %%% Local Variables: