X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=session.tex;h=a43f0789d0f5262e0048068503126ded5dd499c0;hp=80e73394504f08e6e97d86eeccc27023465441b0;hb=d7d656d5cd4969c58126d2c35950a607c282e330;hpb=d46995abfd6f4e2fcd46cdb8ba369dbb6ba36492 diff --git a/session.tex b/session.tex index 80e7339..a43f078 100644 --- a/session.tex +++ b/session.tex @@ -6,9 +6,9 @@ sistema, per questo anche oggi che esistono molte altre interfacce, essi continuano a coprire un ruolo particolare, restando strettamente legati al funzionamento dell'interfaccia a linea di comando. -Mella prima parte del capitolo esamineremo i concetti base del sistema delle +Nella prima parte del capitolo esamineremo i concetti base del sistema delle sessioni di lavoro, vale a dire il metodo con cui il kernel permette ad un -utente di gestire le capacità multitiasking del sistema, permettendo di +utente di gestire le capacità multitasking del sistema, permettendo 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 il @@ -593,7 +593,7 @@ corrispondenza dell'uscita del leader di sessione). Per questo motivo un programma che deve funzionare come demone deve sempre prendere autonomamente i provvedimenti opportuni (come distaccarsi dal terminale e dalla sessione) ad impedire eventuali interferenze da parte del -sistema del \textit{job contol}; questi sono riassunti in una lista di +sistema del \textit{job control}; questi sono riassunti in una lista di prescrizioni\footnote{ad esempio sia Stevens in \cite{APUE}, che la \textit{Unix Programming FAQ} \cite{UnixFAQ} ne riportano di sostanzialmente identiche.} da seguire quando si scrive un demone. @@ -796,7 +796,7 @@ con un OR aritmetico di una qualunque delle costanti riportate in \end{table} La funzione che si usa per generare un messaggio è \func{syslog}, dato che -l'uso di \func{openlog} è ozionale, sarà quest'ultima a provvede a chiamare la +l'uso di \func{openlog} è opzionale, sarà quest'ultima a provvede a chiamare la prima qualora ciò non sia stato fatto (nel qual caso il valore di \param{ident} è nullo). Il suo prototipo è: \begin{prototype}{syslog.h} @@ -917,14 +917,8 @@ canali di comunicazione dal kernel e che di solito vengono associati alle connessioni di rete (ad esempio per trattare i dati inviati con \cmd{telnet} o \cmd{ssh}). -% In generale tutti i terminali hanno un insieme di funzionalità comuni, che -% vengono chiamate \textsl{discipline di linea}; esse contraddistinguono le -% modalità con cui il kernel manipola (ad esempio la reazione ad un carattere di -% cancellazione per la tastiera, o la gestione della linea tramite PPP o SLIP) i -% dati grezzi che vengono immessi sul dispositivo; - L'I/O sui terminali si effettua con le stesse modalità dei file normali: si -apre il relativo file di dispositivo, e si leggono e scriveno i dati con le +apre il relativo file di dispositivo, e si leggono e scrivono i dati con le usuali funzioni di lettura e scrittura, così se apriamo una console virtuale avremo che \func{read} leggerà quanto immesso dalla tastiera, mentre \func{write} scriverà sullo schermo. In realtà questo è vero solo a grandi @@ -965,17 +959,17 @@ kernel. La coda di ingresso mantiene i caratteri che sono stati letti dal terminale ma non ancora letti da un processo, la sua dimensione è definita dal parametro di -sistema \macro{MAX\_INPUT}, che ne specifica il limite minimo, in realtà la -coda può essere più grande e cambiare dimensione dinamicamente. Se è stato -abilitato il controllo di flusso in ingresso il driver emette i caratteri di -STOP e START per bloccare e sbloccare l'ingresso dei dati; altrimenti i -caratteri immessi oltre le dimensioni massime vengono persi; in alcuni casi il -driver provvede ad inviare automaticamente un avviso (un carattere di BELL, -che provoca un beep) sull'output quando si eccedono le dimensioni della coda. -Se è abilitato il modo canonico i caratteri in ingresso restano nella coda -fintanto che non viene ricevuto un a capo; un'altra costante, -\macro{MAX\_CANON}, specifica la dimensione massima di una riga in modo -canonico. +sistema \macro{MAX\_INPUT} (si veda \secref{sec:sys_file_limits}), che ne +specifica il limite minimo, in realtà la coda può essere più grande e cambiare +dimensione dinamicamente. Se è stato abilitato il controllo di flusso in +ingresso il driver emette i caratteri di STOP e START per bloccare e sbloccare +l'ingresso dei dati; altrimenti i caratteri immessi oltre le dimensioni +massime vengono persi; in alcuni casi il driver provvede ad inviare +automaticamente un avviso (un carattere di BELL, che provoca un beep) +sull'output quando si eccedono le dimensioni della coda. Se è abilitato il +modo canonico i caratteri in ingresso restano nella coda fintanto che non +viene ricevuto un a capo; un'altra parametro del sistema, \macro{MAX\_CANON}, +specifica la dimensione massima di una riga in modo canonico. La coda di uscita è analoga a quella di ingresso e contiene i caratteri scritti dai processi ma non ancora inviati al terminale. Se è abilitato il @@ -998,8 +992,8 @@ System V in una unica interfaccia, che Alcune di queste funzioni prendono come argomento un file descriptor (in origine molte operazioni venivano effettuate con \func{ioctl}), ma ovviamente possono essere usate solo con file che corrispondano effettivamente ad un -terminale; questo che può essere verificato utilizzando la funzione -\func{isatty}, il cui prototipo è: +terminale (altrimenti si otterrà un errore di \macro{ENOTTY}); questo può +essere evitato utilizzando la funzione \func{isatty}, il cui prototipo è: \begin{prototype}{unistd.h}{int isatty(int desc)} Controlla se il file descriptor \param{desc} è un terminale. @@ -1009,11 +1003,11 @@ terminale; questo che pu \end{prototype} Un'altra funzione che fornisce informazioni su un terminale è \func{ttyname}, -che permette anche di ottenere il nome del terminale associato ad un file +che permette di ottenere il nome del terminale associato ad un file descriptor; il suo prototipo è: \begin{prototype}{unistd.h}{char *ttyname(int desc)} - Restituisce il nome di un terminale. + Restituisce il nome del terminale associato al file \param{desc}. \bodydesc{La funzione restituisce il puntatore alla stringa contenente il nome del terminale associato \param{desc} e \macro{NULL} in caso di @@ -1021,15 +1015,66 @@ descriptor; il suo prototipo \end{prototype} Si tenga presente che la funzione restituisce un indirizzo di dati statici, -che pertanto possono essere sovrascritti da successive chiamate. La funzione è -prevista da POSIX.1, che non definisce \func{isatty}. +che pertanto possono essere sovrascritti da successive chiamate. Una funzione +funzione analoga, anch'essa prevista da POSIX.1, è \func{ctermid}, il cui +prototipo è: +\begin{prototype}{stdio.h}{char *ctermid(char *s)} + + Restituisce il nome del terminale di controllo del processo. + + \bodydesc{La funzione restituisce il puntatore alla stringa contenente il + pathname del terminale.} +\end{prototype} + +La funzione scrive il pathname del terminale di controllo del processo +chiamante nella stringa posta all'indirizzo specificato dall'argomento +\param{s}. La memoria per contenere la stringa deve essere stata allocata in +precedenza ed essere lunga almeno +\macro{L\_ctermid}\footnote{\macro{L\_ctermid} è una delle varie costanti del + sistema, non trattata esplicitamente in \secref{sec:sys_characteristics} che + indica la dimensione che deve avere una stringa per poter contenere il nome + di un terminale.} caratteri. + +Esiste infine una versione rientrante \func{ttyname\_r} della funzione +\func{ttyname}, che non presenta il problema dell'uso di una zona di memoria +statica; il suo prototipo è: +\begin{prototype}{unistd.h}{int ttyname\_r(int desc, char *buff, size\_t len)} + + Restituisce il nome del terminale associato al file \param{desc}. + + \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{ERANGE}] la lunghezza del buffer, \param{len}, non è + sufficiente per contenere la stringa restituita. + \end{errlist} + ed inoltre \macro{EBADF} ed \macro{ENOSYS}. +} +\end{prototype} + +La funzione prende due argomenti, il puntatore alla zona di memoria +\param{buff}, in cui l'utente vuole che il risultato venga scritto (dovrà +ovviamente essere stata allocata in precedenza), e la relativa dimensione, +\param{len}; se la stringa che deve essere restituita eccede questa dimensione +si avrà una condizione di errore. + +Se si passa come argomento \macro{NULL} la funzione restituisce il puntatore +ad una stringa statica che può essere sovrascritta da chiamate successive. Si +tenga presente che il pathname restituito potrebbe non identificare +univocamente il terminale (ad esempio potrebbe essere \file{/dev/tty}), +inoltre non è detto che il processo possa effettivamente aprire il terminale. I vari attributi vengono mantenuti per ciascun terminale in una struttura -\var{termios}, (la cui definizione è in \figref{fig:term_termios}), usata -dalle varie funzioni dell'interfaccia. In \figref{fig:term_termios} si sono -riportati solo i campi previsti dallo standard POSIX.1, in genere le varie -implementazioni ne aggiungono degli altri (in Linux e BSD ci sono quelli che -specificano le velocità della linea) per mantenere ulteriori informazioni. +\var{termios}, (la cui definizione è riportata in \figref{fig:term_termios}), +usata dalle varie funzioni dell'interfaccia. In \figref{fig:term_termios} si +sono riportati tutti i campi della definizione usata in Linux; di questi solo +i primi cinque sono previsti dallo standard POSIX.1, ma le varie +implementazioni ne aggiungono degli altri per mantenere ulteriori +informazioni.\footnote{la definizione della struttura si trova in + \file{bits/termios.h}, da non includere mai direttamente, Linux, seguendo + l'esempio di BSD, aggiunge i due campi \var{c\_ispeed} e \var{c\_ospeed} per + mantenere le velocità delle linee seriali, ed un campo ulteriore, + \var{c\_line} per ... (NdT, trovare a che serve).} \begin{figure}[!htb] \footnotesize \centering @@ -1041,7 +1086,10 @@ struct termios { tcflag_t c_cflag; /* control modes */ tcflag_t c_lflag; /* local modes */ cc_t c_cc[NCCS]; /* control characters */ -}; + cc_t c_line; /* line discipline */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +; \end{lstlisting} \end{minipage} \normalsize @@ -1059,7 +1107,7 @@ modificare i bit su cui non si interviene. \begin{table}[b!ht] \footnotesize \centering - \begin{tabular}[c]{|l|p{13cm}|} + \begin{tabular}[c]{|l|p{11cm}|} \hline \textbf{Valore}& \textbf{Significato}\\ \hline @@ -1107,7 +1155,7 @@ modificare i bit su cui non si interviene. input. \\ \macro{INLCR} & Se impostato il carattere di a capo (\verb|'\n'|) viene automaticamente trasformato in un - ritorno carello (\verb|'\r'|).\\ + ritorno carrello (\verb|'\r'|).\\ \macro{IUCLC} & Se impostato trasforma i caratteri maiuscoli dal terminale in minuscoli sull'ingresso (opzione non POSIX).\\ @@ -1152,7 +1200,7 @@ pseudo-terminali usati nelle connessioni di rete. \begin{table}[htb] \footnotesize \centering - \begin{tabular}[c]{|l|p{13cm}|} + \begin{tabular}[c]{|l|p{11cm}|} \hline \textbf{Valore}& \textbf{Significato}\\ \hline @@ -1199,7 +1247,7 @@ pseudo-terminali usati nelle connessioni di rete. \hline \end{tabular} \caption{Costanti identificative dei vari bit del flag di controllo - \var{c\_oflag} delle modalità di outputdi un terminale.} + \var{c\_oflag} delle modalità di output di un terminale.} \label{tab:sess_termios_oflag} \end{table} @@ -1235,7 +1283,7 @@ valore. \begin{table}[htb] \footnotesize \centering - \begin{tabular}[c]{|l|p{13cm}|} + \begin{tabular}[c]{|l|p{11cm}|} \hline \textbf{Valore}& \textbf{Significato}\\ \hline @@ -1273,7 +1321,7 @@ valore. valore ne indica la lunghezza (in bit), ed i valori possibili sono \macro{CS5}, \macro{CS6}, \macro{CS7} e \macro{CS8} - corripondenti ad un analogo numero di bit.\\ + corrispondenti ad un analogo numero di bit.\\ \macro{CBAUD} & Maschera dei bit (4+1) usati per impostare della velocità della linea (il \textit{baud rate}) in ingresso. In Linux non è implementato in quanto viene @@ -1311,13 +1359,13 @@ standard POSIX non specifica nulla riguardo l'implementazione, ma solo delle funzioni di lettura e scrittura) che mantengono le velocità delle linee seriali all'interno dei flag; come accennato in Linux questo viene fatto (seguendo l'esempio di BSD) attraverso due campi aggiuntivi, \var{c\_ispeed} e -\var{c\_ospeed}, nella struttura \var{termios} (non mostrati in -\secref{fig:term_termios}). +\var{c\_ospeed}, nella struttura \var{termios} (mostrati in +\figref{fig:term_termios}). \begin{table}[b!ht] \footnotesize \centering - \begin{tabular}[c]{|l|p{13cm}|} + \begin{tabular}[c]{|l|p{11cm}|} \hline \textbf{Valore}& \textbf{Significato}\\ \hline @@ -1395,7 +1443,10 @@ Il quarto flag, mantenuto nel campo \var{c\_lflag}, driver e l'utente, come abilitare l'eco, gestire i caratteri di controllo e l'emissione dei segnali, impostare modo canonico o non canonico; un elenco dei vari bit, del loro significato e delle costanti utilizzate per identificarli è -riportato in \tabref{tab:sess_termios_lflag}. +riportato in \tabref{tab:sess_termios_lflag}. Con i terminali odierni l'unico +flag con cui probabilmente si può avere a che fare è questo, in quanto è con +questo che si impostano le caratteristiche generiche comuni a tutti i +terminali. Si tenga presente che i flag che riguardano le modalità di eco dei caratteri (\macro{ECHOE}, \macro{ECHOPRT}, \macro{ECHOK}, \macro{ECHOKE}, @@ -1404,14 +1455,111 @@ riconoscimento dei vari caratteri dipende dalla modalit avviene solo in modo canonico, pertanto questi flag non hanno significato se non è impostato \macro{ICANON}. -Con i terminali odierni l'unico flag con cui probabilmente si può avere a che -fare è questo, che è l'unico che concerne le caratteristiche generiche comuni -a tutti i terminali. +Oltre ai vari flag per gestire le varie caratteristiche dei terminali, +\var{termios} contiene pure il campo \var{c\_cc} che viene usato per impostare +i caratteri speciali associati alle varie funzioni di controllo. Il numero di +questi caratteri speciali è indicato dalla costante \macro{NCCS}, POSIX ne +specifica almeno 11, ma molte implementazioni ne definiscono molti +altri.\footnote{in Linux il valore della costante è 32, anche se i caratteri + effettivamente definiti sono solo 17.} -Per impostare tutti questi flag lo standard POSIX prevede due funzioni: -\func{tcgetattr} e \func{tcsetattr}; entrambe prendono come parametro un -puntatore ad struttura \var{termios} che deve essere oportunamente -inizializzata, il loro prototipo è: +\begin{table}[htb] + \footnotesize + \centering + \begin{tabular}[c]{|l|c|c|p{8cm}|} + \hline + \textbf{Indice} & \textbf{Valore}&\textbf{Codice} & \textbf{Funzione}\\ + \hline + \hline + \macro{VINTR} &\texttt{0x03}&(\verb|C-c|)& Carattere di interrupt, + provoca l'emissione di + \macro{SIGINT}. \\ + \macro{VQUIT} &\texttt{0x1C}&(\verb|C-\|)& Carattere di uscita provoca + l'emissione di + \macro{SIGQUIT}.\\ + \macro{VERASE} &\texttt{0x7f}& DEL & Carattere di ERASE, cancella + l'ultimo carattere precedente + nella linea.\\ + \macro{VKILL} &\texttt{0x15}&(\verb|C-u|)& Carattere di KILL, cancella + l'intera riga.\\ + \macro{VEOF} &\texttt{0x04}&(\verb|C-d|)& Carattere di + \textit{end-of-file}. Causa + l'invio del contenuto del + buffer di ingresso al + processo in lettura anche se + non è ancora stato ricevuto + un a capo. Se è il primo + carattere immesso comporta il + ritorno di \func{read} con + zero caratteri, cioè la + condizione di + \textit{end-of-file}.\\ + \macro{VTIME} & --- & --- & Timeout, in decimi di secondo, per + una lettura in modo non canonico. \\ + \macro{VMIN} & --- & --- & Numero minimo di caratteri per una + lettura in modo non canonico.\\ + \macro{VSWTC} &\texttt{0x00}& NUL & Carattere di switch. Non supportato + in Linux.\\ + \macro{VSTART} &\texttt{0x21}&(\verb|C-q|)& Carattere di START. Riavvia un + output bloccato da uno STOP.\\ + \macro{VSTOP} &\texttt{0x23}&(\verb|C-s|)& Carattere di STOP. Blocca + l'output fintanto che non + viene premuto un carattere di + START.\\ + \macro{VSUSP} &\texttt{0x1A}&(\verb|C-z|)& Carattere di + sospensione. Invia il segnale + \macro{SIGTSTP}.\\ + \macro{VEOL} &\texttt{0x00}& NUL & Carattere di fine riga. Agisce come + un a capo, ma non viene scartato ed + è letto come l'ultimo carattere + nella riga. \\ + \macro{VREPRINT}&\texttt{0x12}&(\verb|C-r|)& Ristampa i caratteri non + ancora letti. \\ + \macro{VDISCARD}&\texttt{0x07}&(\verb|C-o|)& Non riconosciuto in Linux. \\ + \macro{VWERASE} &\texttt{0x17}&(\verb|C-w|)& Cancellazione di una parola.\\ + \macro{VLNEXT} &\texttt{0x16}&(\verb|C-v|)& Carattere di escape, serve a + quotare il carattere + successivo che non viene + interpretato ma passato + direttamente all'output. \\ + \macro{VEOL2} &\texttt{0x00}& NUL & Ulteriore carattere di fine + riga. Ha lo stesso effetto di + \macro{VEOL} ma può essere un + carattere diverso. \\ + \hline + \end{tabular} + \caption{Valori dei caratteri di controllo mantenuti nel campo \var{c\_cc} + della struttura \var{termios}.} + \label{tab:sess_termios_cc} +\end{table} + + +A ciascuna di queste funzioni di controllo corrisponde un elemento del vettore +\var{c\_cc} che specifica quale è il carattere speciale associato; per +portabilità invece di essere indicati con la loro posizione numerica nel +vettore, i vari elementi vengono indicizzati attraverso delle opportune +costanti, il cui nome corrisponde all'azione ad essi associata. Un elenco +completo dei caratteri di controllo, con le costanti e delle funzionalità +associate è riportato in \tabref{tab:sess_termios_cc}, usando quelle +definizioni diventa possibile assegnare un nuovo carattere di controllo con un +codice del tipo: +\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}% + value.c_cc[VEOL2] = '\n'; +\end{lstlisting} + +La maggior parte di questi caratteri (tutti tranne \macro{VTIME} e +\macro{VMIN}) hanno effetto solo quando il terminale viene utilizzato in modo +canonico; per alcuni devono essere essere soddisfatte ulteriori richieste, ad +esempio \macro{VINTR}, \macro{VSUSP}, e \macro{VQUIT} richiedono sia settato +\macro{ISIG}; \macro{VSTART} e \macro{VSTOP} richiedono sia settato +\macro{IXON}; \macro{VLNEXT}, \macro{VWERASE}, \macro{VREPRINT} richiedono sia +settato \macro{IEXTEN}. In ogni caso quando vengono attivati i caratteri +vengono interpretati e non sono passati sulla coda di ingresso. + +Per leggere ed scrivere tutte le impostazioni dei terminali lo standard POSIX +prevede due funzioni, \func{tcgetattr} e \func{tcsetattr}; entrambe utilizzano +come argomento un puntatore ad struttura \var{termios} che sarà quella in cui +andranno immagazzinate le impostazioni, il loro prototipo è: \begin{functions} \headdecl{unistd.h} \headdecl{termios.h} @@ -1431,18 +1579,62 @@ inizializzata, il loro prototipo } \end{functions} -Le funzioni operano sul terminale identificato dal file descriptor \param{fd} -utilizzando la struttura specificata dal puntatore \param{termios\_p} per lo -scambio dei dati. Come già accennato i valori di ciascun bit devono essere -specificati avendo cura di mantenere intatti gli altri; per questo motivo in -generale si deve prima leggere il valore corrente delle impostazioni con -\func{tcgetattr} per poi modificare i valori impostati. +Le funzioni operano sul terminale cui fa riferimento il file descriptor +\param{fd} utilizzando la struttura indicata dal puntatore \param{termios\_p} +per lo scambio dei dati. Si tenga presente che le impostazioni sono associate +al terminale e non al file descriptor; questo significa che se si è cambiata +una impostazione un qualunque altro processo che apra lo stesso terminale, od +un qualunque altro file descriptor che vi faccia riferimento, vedrà le nuove +impostazioni pur non avendo nulla a che fare con il file descriptor che si è +usato per effettuare i cambiamenti. + +Questo significa che non è possibile usare file descriptor diversi per +utilizzare automaticamente il terminale in modalità diverse, se esiste una +necessità di accesso differenziato di questo tipo occorrerà cambiare +esplicitamente la modalità tutte le volte che si passa da un file descriptor +ad un altro. + +La funzione \func{tcgetattr} legge i valori correnti delle impostazioni di un +terminale qualunque nella struttura puntata da \param{termios\_p}; +\func{tcsetattr} invece effettua la scrittura delle impostazioni e quando +viene invocata sul proprio terminale di controllo può essere eseguita con +successo solo da un processo in foreground. Se invocata da un processo in +background infatti tutto il gruppo riceverà un segnale di \macro{SIGTTOU} come +se si fosse tentata una scrittura, a meno che il processo chiamante non abbia +\macro{SIGTTOU} ignorato o bloccato, nel qual caso l'operazione sarà eseguita. -In \figref{fig:term_set_attr} si è riportato il codice delle due funzioni -\func{SetTermAttr} e \func{UnSetTermAttr} che possono essere usate -rispettivamente per impostare o rimuovere un qualunque bit di \var{c\_lflag}, -con le dovute precauzioni. Il codice di entrambe le funzioni può essere -trovato nel file \file{SetTermAttr.c} dei sorgenti allegati. +La funzione \func{tcsetattr} prevede tre diverse modalità di funzionamento, +specificabili attraverso l'argomento \param{optional\_actions}, che permette +di stabilire come viene eseguito il cambiamento delle impostazioni del +terminale, i valori possibili sono riportati in +\tabref{tab:sess_tcsetattr_option}; di norma (come fatto per le due funzioni +di esempio) si usa sempre \macro{TCSANOW}, le altre opzioni possono essere +utili qualora si cambino i parametri di output. + +\begin{table}[htb] + \footnotesize + \centering + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Valore}& \textbf{Significato}\\ + \hline + \hline + \macro{TCSANOW} & Esegue i cambiamenti in maniera immediata. \\ + \macro{TCSADRAIN}& I cambiamenti vengono eseguiti dopo aver atteso che + tutto l'output presente sulle code è stato scritto. \\ + \macro{TCSAFLUSH}& È identico a \macro{TCSADRAIN}, ma in più scarta + tutti i dati presenti sulla coda di input.\\ + \hline + \end{tabular} + \caption{Possibili valori per l'argomento \param{optional\_actions} della + funzione \func{tcsetattr}.} + \label{tab:sess_tcsetattr_option} +\end{table} + +Occorre infine tenere presente che \func{tcsetattr} ritorna con successo anche +se soltanto uno dei cambiamenti richiesti è stato eseguito. Pertanto se si +effettuano più cambiamenti è buona norma controllare con una ulteriore +chiamata a \func{tcgetattr} che essi siano stati eseguiti tutti quanti. \begin{figure}[!htb] \footnotesize @@ -1455,7 +1647,6 @@ int SetTermAttr(int fd, tcflag_t flag) { struct termios values; int res; - res = tcgetattr (desc, &values); if (res) { perror("Cannot get attributes"); @@ -1469,11 +1660,41 @@ int SetTermAttr(int fd, tcflag_t flag) } return 0; } + \end{lstlisting} + \caption{Codice della funzione \func{SetTermAttr} che permette di + impostare uno dei flag di controllo locale del terminale.} + \label{fig:term_set_attr} +\end{figure} + +Come già accennato per i cambiamenti effettuati ai vari flag di controllo +occorre che i valori di ciascun bit siano specificati avendo cura di mantenere +intatti gli altri; per questo motivo in generale si deve prima leggere il +valore corrente delle impostazioni con \func{tcgetattr} per poi modificare i +valori impostati. + +In \figref{fig:term_set_attr} e \figref{fig:term_unset_attr} si è riportato +rispettivamente il codice delle due funzioni \func{SetTermAttr} e +\func{UnSetTermAttr}, che possono essere usate per impostare o rimuovere, con +le dovute precauzioni, un qualunque bit di \var{c\_lflag}. Il codice di +entrambe le funzioni può essere trovato nel file \file{SetTermAttr.c} dei +sorgenti allegati. + +La funzione \func{SetTermAttr} provvede ad impostare il bit specificato +dall'argomento \param{flag}; prima si leggono i valori correnti +(\texttt{\small 10}) con \func{tcgetattr}, uscendo con un messaggio in caso di +errore (\texttt{\small 11--14}), poi si provvede a impostare solo i bit +richiesti (possono essere più di uno) con un OR binario (\texttt{\small 15}); +infine si scrive il nuovo valore modificato con \func{tcsetattr} +(\texttt{\small 16}), notificando un eventuale errore (\texttt{\small 11--14}) +o uscendo normalmente. + +\begin{figure}[!htb] + \footnotesize + \begin{lstlisting}{}% int UnSetTermAttr(int fd, tcflag_t flag) { struct termios values; int res; - res = tcgetattr (desc, &values); if (res) { perror("Cannot get attributes"); @@ -1488,30 +1709,182 @@ int UnSetTermAttr(int fd, tcflag_t flag) return 0; } \end{lstlisting} - \caption{Codice delle funzioni \func{SetTermAttr} e \func{UnSetTermAttr} per - impostare o rimuovere uno dei flag di controllo locale del terminale.} - \label{fig:term_set_attr} + \caption{Codice della funzione \func{UnSetTermAttr} che permette di + rimuovere uno dei flag di controllo locale del terminale.} + \label{fig:term_unset_attr} \end{figure} -La prima funzione provvede ad impostare il bit specificato dall'argomento -\param{flag}; prima si leggono i valori correnti (\texttt{\small 10}) con -\func{tcgetattr}, uscendo con un messaggio in caso di errore (\texttt{\small - 11--14}), poi si provvede a impostare solo i bit richiesti (possono essere -più di uno) con un OR binario (\texttt{\small 15}); infine si scrive il nuovo -valore modificato con \func{tcsetattr} (\texttt{\small 16}), notificando un -eventuale errore (\texttt{\small 11--14}) o uscendo normalmente. +La seconda funzione, \func{UnSetTermAttr}, è assolutamente identica alla +prima, solo che in questo caso (in \texttt{\small 15}) si rimuovono i bit +specificati dall'argomento \param{flag} usando un AND binario del valore +negato. -La seconda funzione è identica alla prima, solo che in questo caso -(\texttt{\small 33}) si rimuovono i bit specificati dall'argomento -\param{flag} usando un AND binario del valore negato. -La funzione \func{tcsetattr} prevede tre diverse modalità di funzionamento, -specificabili attraverso l'argomento \param{optional\_actions}, che permette -di stabilire come viene eseguito il cambiamento delle impostazioni del -terminale, i valori possibili sono riportati in -\ref{tab:sess_tcsetattr_option}; di norma (come fatto per le due funzioni di -esempio) si usa sempre \macro{TCSANOW}, le altre opzioni possono essere utili -qualora si cambino i parametri di output. +Al contrario di tutte le altre caratteristiche dei terminali, che possono +essere impostate esplicitamente utilizzando gli opportuni campi di +\var{termios}, per le velocità della linea (il cosiddetto \textit{baud rate}) +non è prevista una implementazione standardizzata, per cui anche se in Linux +sono mantenute in due campi dedicati nella struttura, questi non devono essere +acceduti direttamente ma solo attraverso le apposite funzioni di interfaccia +provviste da POSIX.1. + +Lo standard prevede due funzioni per scrivere la velocità delle linee seriali, +\func{cfsetispeed} per la velocità della linea di ingresso e +\func{cfsetospeed} per la velocità della linea di uscita; i loro prototipi +sono: +\begin{functions} + \headdecl{unistd.h} + \headdecl{termios.h} + \funcdecl{int cfsetispeed(struct termios *termios\_p, speed\_t speed)} + Imposta la velocità delle linee seriali in ingresso. + + \funcdecl{int cfsetospeed(struct termios *termios\_p, speed\_t speed)} + Imposta la velocità delle linee seriali in uscita. + + \bodydesc{Entrambe le funzioni restituiscono 0 in caso di successo e -1 in + caso di errore, che avviene solo quando il valore specificato non è + valido.} +\end{functions} + +Si noti che le funzioni si limitano a scrivere opportunamente il valore della +velocità prescelta \var{speed} all'interno della struttura puntata da +\var{termios\_p}; per effettuare l'impostazione effettiva occorrerà poi +chiamare \func{tcsetattr}. + +Si tenga presente che per le linee seriali solo alcuni valori di velocità sono +validi; questi possono essere specificati direttamente (le \acr{glibc} +prevedono che i valori siano indicati in bit per secondo), ma in generale +altre versioni di librerie possono utilizzare dei valori diversi; per questo +POSIX.1 prevede una serie di costanti che però servono solo per specificare le +velocità tipiche delle linee seriali: +\begin{verbatim} + B0 B50 B75 B110 B134 B150 + B200 B300 B600 B1200 B1800 B2400 + B4800 B9600 B19200 B38400 B57600 B115200 + B230400 B460800 +\end{verbatim} + +Un terminale può utilizzare solo alcune delle velocità possibili, le funzioni +però non controllano se il valore specificato è valido, dato che non possono +sapere a quale terminale le velocità saranno applicate; sarà l'esecuzione di +\func{tcsetattr} a fallire quando si cercherà di eseguire l'impostazione. + +Di norma il valore ha senso solo per i terminali seriali dove indica appunto +la velocità della linea di trasmissione; se questa non corrisponde a quella +del terminale quest'ultimo non potrà funzionare: quando il terminale non è +seriale il valore non influisce sulla velocità di trasmissione dei dati. + +In generale impostare un valore nullo (\macro{B0}) sulla linea di output fa si +che il modem non asserisca più le linee di controllo, interrompendo di fatto +la connessione, qualora invece si utilizzi questo valore per la linea di input +l'effetto sarà quello di rendere la sua velocità identica a quella della linea +di output. + +Analogamente a quanto avviene per l'impostazione, le velocità possono essere +lette da una struttura \var{termios} utilizzando altre due funzioni, +\func{cfgetispeed} e \func{cfgetospeed}, i cui prototipi sono: +\begin{functions} + \headdecl{unistd.h} + \headdecl{termios.h} + \funcdecl{speed\_t cfgetispeed(struct termios *termios\_p)} + Legge la velocità delle linee seriali in ingresso. + + \funcdecl{speed\_t cfgetospeed(struct termios *termios\_p)} + Legge la velocità delle linee seriali in uscita. + + \bodydesc{Entrambe le funzioni restituiscono la velocità della linea, non + sono previste condizioni di errore.} +\end{functions} + +Anche in questo caso le due funzioni estraggono i valori della velocità della +linea da una struttura, il cui indirizzo è specificato dall'argomento +\param{termios\_p} che deve essere stata letta in precedenza con +\func{tcgetaddr}. + + + +\subsection{La gestione della disciplina di linea.} +\label{sec:term_line_discipline} + +Come illustrato dalla struttura riportata in \figref{fig:term_struct} tutti i +terminali hanno un insieme di funzionalità comuni, che prevedono la presenza +di code di ingresso ed uscita; in generale si fa riferimento ad esse con il +nome di \textsl{discipline di linea}. + + +Lo standard POSIX prevede alcune funzioni che permettono di intervenire +direttamente sulla gestione di quest'ultime e sull'interazione fra i dati in +ingresso ed uscita e le relative code. In generale tutte queste funzioni +vengono considerate, dal punto di vista dell'accesso al terminale, come delle +funzioni di scrittura, pertanto se usate da processi in background sul loro +terminale di controllo provocano l'emissione di \macro{SIGTTOU} come +illustrato in \secref{sec:sess_ctrl_term}.\footnote{con la stessa eccezione, + già vista per \func{tcsetaddr}, che quest'ultimo sia bloccato o ignorato dal + processo chiamante.} + +Una prima funzione, che è efficace solo in caso di terminali seriali asincroni +(non fa niente per tutti gli altri terminali), è \func{tcsendbreak}; il suo +prototipo è: +\begin{functions} + \headdecl{unistd.h} + \headdecl{termios.h} + + \funcdecl{int tcsendbreak(int fd, int duration)} Genera una condizione di + break inviando un flusso di bit nulli. + + \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + errore, nel qual caso \var{errno} assumerà i valori \macro{EBADF} o + \macro{ENOTTY}.} +\end{functions} + +La funzione invia un flusso di bit nulli (che genera una condizione di break) +sul terminale associato a \param{fd}; un valore nullo di \param{duration} +implica una durata del flusso fra 0.25 e 0.5 secondi, un valore diverso da +zero implica una durata pari a \code{duration*T} dove \code{T} è un valore +compreso fra 0.25 e 0.5.\footnote{POSIX specifica il comportamento solo nel + caso si sia impostato un valore nullo per \param{duration}; il comportamento + negli altri casi può dipendere dalla implementazione.} + +Le altre funzioni previste da POSIX servono a controllare il comportamento +dell'interazione fra le code associate al terminale e l'utente; la prima è +\func{tcdrain}, il cui prototipo è: +\begin{functions} + \headdecl{unistd.h} + \headdecl{termios.h} + + \funcdecl{int tcdrain(int fd)} Attende lo svuotamento della coda di output. + + \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + errore, nel qual caso \var{errno} assumerà i valori \macro{EBADF} o + \macro{ENOTTY}.} +\end{functions} + +La funzione blocca il processo fino a che tutto l'output presente sulla coda +di uscita non è stato trasmesso al terminale associato ad \param{fd}. % La + % funzione è un punto di cancellazione per i + % programmi multi-thread, in tal caso le + % chiamate devono essere protette con dei + % gestori di cancellazione. + +Una seconda funzione, \func{tcflush}, permette svuotare immediatamente le code +di cancellando tutti i dati presenti al loro interno; il suo prototipo è: +\begin{functions} + \headdecl{unistd.h} \headdecl{termios.h} + + \funcdecl{int tcflush(int fd, int queue)} Cancella i dati presenti + nelle code di ingresso o di uscita. + + \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + errore, nel qual caso \var{errno} assumerà i valori \macro{EBADF} o + \macro{ENOTTY}.} +\end{functions} + +La funzione agisce sul terminale associato a \param{fd}, l'argomento +\param{queue} permette di specificare su quale coda (ingresso, uscita o +entrambe), operare. Esso può prendere i valori riportati in +\tabref{tab:sess_tcflush_queue}, nel caso si specifichi la coda di ingresso +cancellerà i dati ricevuti ma non ancora letti, nel caso si specifichi la coda +di uscita cancellerài dati scritti ma non ancora trasmessi. \begin{table}[htb] \footnotesize @@ -1521,134 +1894,111 @@ qualora si cambino i parametri di output. \textbf{Valore}& \textbf{Significato}\\ \hline \hline - \macro{TCSANOW} & Esegue i cambiamenti in maniera immediata. \\ - \macro{TCSADRAIN}& I cambiamenti vengono eseguiti dopo aver atteso che - tutto l'output presente sulle code è stato scritto. \\ - \macro{TCSAFLUSH}& È identico a \macro{TCSADRAIN}, ma in più scarta - tutti i dati presenti sulla coda di input.\\ + \macro{TCIFLUSH} & Cancella i dati sulla coda di ingresso. \\ + \macro{TCOFLUSH} & Cancella i dati sulla coda di uscita. \\ + \macro{TCIOFLUSH}& Cancella i dati su entrambe le code.\\ \hline \end{tabular} - \caption{Possibili valori per l'argomento \param{optional\_actions} della - funzione \func{tcsetattr}.} - \label{tab:sess_tcsetattr_option} + \caption{Possibili valori per l'argomento \param{queue} della + funzione \func{tcflush}.} + \label{tab:sess_tcflush_queue} \end{table} -Infine occorre tenere presente che \func{tcsetattr} ritorna con successo anche -se soltanto uno dei cambiamenti richiesti è stato eseguito. Pertanto se si -effettuano più cambiamenti è buona norma controllare con una ulteriore -chiamata a \func{tcgetattr} che essi siano stati eseguiti tutti quanti. -Oltre ai vari flag per gestire le varie caratteristiche dei terminali, -\var{termios} contiene pure il campo \var{c\_cc} che viene usato per impostare -i caratteri speciali associati alle varie funzioni di controllo. Il numero di -questi caratteri speciali è indicato dalla costante \macro{NCCS}, POSIX ne -specifica almeno 11, ma molte implementazioni ne definiscono molti -altri.\footnote{in Linux il valore della costante è 32, anche se i caratteri - effettivamente definiti sono solo 17.} +L'ultima funzione dell'interfaccia che interviene sulla disciplina di linea è +\func{tcflow}, che viene usata per sospendere la trasmissione e la ricezione +dei dati sul terminale; il suo prototipo è: +\begin{functions} + \headdecl{unistd.h} + \headdecl{termios.h} + + \funcdecl{int tcflow(int fd, int action)} + + Sospende e rivvia il flusso dei dati sul terminale. + + \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + errore, nel qual caso \var{errno} assumerà i valori \macro{EBADF} o + \macro{ENOTTY}.} +\end{functions} + +La funzione permette di controllare (interrompendo e facendo riprendere) il +flusso dei dati fra il terminale ed il sistema sia in ingresso che in uscita. +Il comportamento della funzione è regolato dall'argomento \param{action}, i +cui possibili valori, e relativa azione eseguita dalla funzione, sono +riportati in \secref{tab:sess_tcflow_action}. \begin{table}[htb] - \footnotesize + \footnotesize \centering - \begin{tabular}[c]{|l|c|c|p{9cm}|} + \begin{tabular}[c]{|l|p{8cm}|} \hline - \textbf{Indice} & \textbf{Valore}&\textbf{Codice} & \textbf{Funzione}\\ + \textbf{Valore}& \textbf{Azione}\\ \hline \hline - \macro{VINTR} &\texttt{0x03}&(\verb|C-c|)& Carattere di interrupt, - provoca l'emissione di - \macro{SIGINT}. \\ - \macro{VQUIT} &\texttt{0x1C}&(\verb|C-\|)& Carattere di uscita provoca - l'emissione di - \macro{SIGQUIT}.\\ - \macro{VERASE} &\texttt{0x7f}& DEL & Carattere di ERASE, cancella - l'ultimo carattere precedente - nella linea.\\ - \macro{VKILL} &\texttt{0x15}&(\verb|C-u|)& Carattere di KILL, cancella - l'intera riga.\\ - \macro{VEOF} &\texttt{0x04}&(\verb|C-d|)& Carattere di - \textit{end-of-file}. Causa - l'invio del contenuto del - buffer di ingresso al - processo in lettura anche se - non è ancora stato ricevuto - un a capo. Se è il primo - carattere immesso comporta il - ritorno di \func{read} con - zero caratteri, cioè la - condizione di - \textit{end-of-file}.\\ - \macro{VTIME} & --- & --- & Timeout, in decimi di secondo, per - una lettura in modo non canonico. \\ - \macro{VMIN} & --- & --- & Numero minimo di caratteri per una - lettura in modo non canonico.\\ - \macro{VSWTC} &\texttt{0x00}& NUL & Carattere di switch. Non supportato - in Linux.\\ - \macro{VSTART} &\texttt{0x21}&(\verb|C-q|)& Carattere di START. Riavvia un - output bloccato da uno STOP.\\ - \macro{VSTOP} &\texttt{0x23}&(\verb|C-s|)& Carattere di STOP. Blocca - l'output fintanto che non - viene premuto un carattere di - START.\\ - \macro{VSUSP} &\texttt{0x1A}&(\verb|C-z|)& Carattere di - sospensione. Invia il segnale - \macro{SIGTSTP}.\\ - \macro{VEOL} &\texttt{0x00}& NUL & Carattere di fine riga. Agisce come - un a capo, ma non viene scartato ed - è letto come l'ultimo carattere - nella riga. \\ - \macro{VREPRINT}&\texttt{0x12}&(\verb|C-r|)& Ristampa i caratteri non - ancora letti. \\ - \macro{VDISCARD}&\texttt{0x07}&(\verb|C-o|)& Non riconosciuto in Linux. \\ - \macro{VWERASE} &\texttt{0x17}&(\verb|C-w|)& Cancellazione di una parola.\\ - \macro{VLNEXT} &\texttt{0x16}&(\verb|C-v|)& Carattere di escape, serve a - quotare il carattere - successivo che non viene - interpretato ma passato - direttamente all'output. \\ - \macro{VEOL2} &\texttt{0x00}& NUL & Ulteriore carattere di fine - riga. Ha lo stesso effetto di - \macro{VEOL} ma può essere un - carattere diverso. \\ + \macro{TCOOFF}& Sospende l'output.\\ + \macro{TCOON} & Riprende un output precedentemente sospeso.\\ + \macro{TCIOFF}& Il sistema trasmette un carattere di STOP, che + fa interrompere la trasmissione dei dati dal terminale. \\ + \macro{TCION} & Il sistema trasmette un carattere di START, che + fa riprendere la trasmissione dei dati dal terminale.\\ \hline \end{tabular} - \caption{Valori dei caratteri di controllo mantenuti nel campo \var{c\_cc} - della struttura \var{termios}.} - \label{tab:sess_termios_cc} + \caption{Possibili valori per l'argomento \param{action} della + funzione \func{tcflow}.} + \label{tab:sess_tcflow_action} \end{table} -A ciascuna di queste funzioni di controllo corriponde un elemento del vettore -\var{c\_cc} che specifica quale è il carattere speciale associato; per -portabilità invece di essere indicati con la loro posizione numerica, i vari -elementi vengono indicizzati attraverso delle opportune costanti il cui nome -corrisponde all'azione ad essi associata. Un elenco completo dei caratteri di -controllo, con le costanti e delle funzionalità associate è riportato in -\tabref{tab:sess_termios_cc}, usando quelle definizioni diventa possibile -assegnare un nuovo carattere di controllo con un codice del tipo: - -\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}% - value.c_cc[VEOL2] = '\n'; -\end{lstlisting} - -\noindent e si potrà poi ricorrere a \func{tcsetattr} per rendere effettiva la -nuova impostazione. - -Come già accennato POSIX.1 prevede due funzioni da utilizzare esplicitamente -per settare la velocità delle linee seriali, \func{cfsetispeed} e -\func{cfsetospeed} - - -\subsection{Il \textsl{modo canonico}} -\label{sec:term_canonic_mode} - -Il modo canonico - - -\subsection{Il \textsl{modo non canonico}} -\label{sec:term_noncanonic_mode} - -Il modo non canonico - +\subsection{Operare in \textsl{modo non canonico}} +\label{sec:term_non_canonical} + +Operare con un terminale in modo canonico è relativamente semplice; basta +eseguire una lettura e la funzione ritornerà quando una il driver del +terminale avrà completato una linea di input. Non è detto che la linea sia +letta interamente (si può aver richiesto un numero inferiore di byte) ma in +ogni caso nessun dato verrà perso, e il resto della linea sarà letto alla +chiamata successiva. + +Inoltre in modo canonico la gestione dell'input è di norma eseguita +direttamente dal driver del terminale, che si incarica (a seconda di quanto +impostato con le funzioni viste nei paragrafi precedenti) di cancellare i +caratteri, bloccare e riavviare il flusso dei dati, terminare la linea quando +viene ricevuti uno dei vari caratteri di terminazione (NL, EOL, EOL2, EOF). + +In modo non canonico tocca invece al programma gestire tutto quanto, i +caratteri NL, EOL, EOL2, EOF, ERASE, KILL, CR, REPRINT non vengono +interpretati automaticamente ed inoltre, non dividendo più l'input in linee, +il sistema non ha più un limite definito per quando ritornare i dati ad un +processo. Per questo motivo abbiamo visto che in \var{c\_cc} sono previsti due +caratteri speciali, MIN e TIME (specificati dagli indici \macro{VMIN} e +\macro{VTIME} in \var{c\_cc}) che dicono al sistema di ritornare da una +\func{read} quando è stata letta una determinata quantità di dati o è passato +un certo tempo. + +Come accennato nella relativa spiegazione in \tabref{tab:sess_termios_cc}, +TIME e MIN non sono in realtà caratteri ma valori numerici. Il comportamento +del sistema per un terminale in modalità non canonica prevede quattro casi +distinti: +\begin{description} +\item[MIN$>0$, TIME$>0$] In questo caso MIN stabilisce il numero minimo di + caratteri desiderati e TIME un tempo di attesa, in decimi di secondo, fra un + carattere e l'altro. Una \func{read} ritorna se vengono ricevuti almeno MIN + caratteri prima della scadenza di TIME (MIN è solo un limite inferiore, se + la funzione ha richiesto un numero maggiore di caratteri ne possono essere + restituiti di più); se invece TIME scade vengono restituiti i byte ricevuti + fino ad allora (un carattere viene sempre letto, dato che il timer inizia a + scorrere solo dopo la ricezione del primo carattere). +\item[MIN$>0$, TIME$=0$] Una \func{read} ritorna solo dopo che sono stati + ricevuti almeno MIN caratteri. Questo significa che una \func{read} può + bloccarsi indefinitamente. +\item[MIN$=0$, TIME$>0$] In questo caso TIME indica un tempo di attesa dalla + chiamata di \func{read}, la funzione ritorna non appena viene ricevuto un + carattere o scade il tempo. Si noti che è possibile che \func{read} ritorni + con un valore nullo. +\item[MIN$=0$, TIME$=0$] In questo caso una \func{read} ritorna immediatamente + restituendo tutti i caratteri ricevuti. Anche in questo caso può ritornare + con un valore nullo. +\end{description}