From: Simone Piccardi Date: Sun, 6 Apr 2014 09:05:09 +0000 (+0000) Subject: Piccole correzioni e revisione di epoll e signalfd. X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=2ee09e1100e6d070dbf5d4d13d900dba516d83de;p=gapil.git Piccole correzioni e revisione di epoll e signalfd. --- diff --git a/fileadv.tex b/fileadv.tex index 325d8a5..60a002b 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -590,29 +590,29 @@ semantica POSIX), e la variabile \var{cmd} che specifica la modalità di richiesta del \textit{file lock} (bloccante o meno), a seconda dell'opzione \cmd{-b}. -Il programma inizia col controllare (\texttt{\small 11--14}) che venga passato +Il programma inizia col controllare (\texttt{\small 11-14}) che venga passato un argomento (il file da bloccare), che sia stato scelto (\texttt{\small - 15--18}) il tipo di blocco, dopo di che apre (\texttt{\small 19}) il file, -uscendo (\texttt{\small 20--23}) in caso di errore. A questo punto il + 15-18}) il tipo di blocco, dopo di che apre (\texttt{\small 19}) il file, +uscendo (\texttt{\small 20-23}) in caso di errore. A questo punto il comportamento dipende dalla semantica scelta; nel caso sia BSD occorre reimpostare il valore di \var{cmd} per l'uso con \func{flock}; infatti il valore preimpostato fa riferimento alla semantica POSIX e vale rispettivamente \const{F\_SETLKW} o \const{F\_SETLK} a seconda che si sia impostato o meno la modalità bloccante. -Nel caso si sia scelta la semantica BSD (\texttt{\small 25--34}) prima si -controlla (\texttt{\small 27--31}) il valore di \var{cmd} per determinare se +Nel caso si sia scelta la semantica BSD (\texttt{\small 25-34}) prima si +controlla (\texttt{\small 27-31}) il valore di \var{cmd} per determinare se si vuole effettuare una chiamata bloccante o meno, reimpostandone il valore opportunamente, dopo di che a seconda del tipo di blocco al valore viene aggiunta la relativa opzione, con un OR aritmetico, dato che \func{flock} vuole un argomento \param{operation} in forma di maschera binaria. Nel caso invece che si sia scelta la semantica POSIX le operazioni sono molto più -immediate si prepara (\texttt{\small 36--40}) la struttura per il lock, e lo +immediate si prepara (\texttt{\small 36-40}) la struttura per il lock, e lo si esegue (\texttt{\small 41}). In entrambi i casi dopo aver richiesto il blocco viene controllato il -risultato uscendo (\texttt{\small 44--46}) in caso di errore, o stampando un -messaggio (\texttt{\small 47--49}) in caso di successo. Infine il programma si +risultato uscendo (\texttt{\small 44-46}) in caso di errore, o stampando un +messaggio (\texttt{\small 47-49}) in caso di successo. Infine il programma si pone in attesa (\texttt{\small 50}) finché un segnale (ad esempio un \cmd{C-c} dato da tastiera) non lo interrompa; in questo caso il programma termina, e tutti i blocchi vengono rilasciati. @@ -1280,16 +1280,19 @@ interruzione si potranno eseguire le relative operazioni. \label{sec:file_poll} Nello sviluppo di System V, invece di utilizzare l'interfaccia di -\func{select}, che è una estensione tipica di BSD, è stata introdotta un'altra -interfaccia, basata sulla funzione \funcd{poll},\footnote{la funzione è - prevista dallo standard XPG4, ed è stata introdotta in Linux come system - call a partire dal kernel 2.1.23 ed inserita nelle \acr{libc} 5.4.28.} il +\func{select}, che è una estensione tipica di BSD, è stata introdotta una +interfaccia completamente diversa, basata sulla funzione di sistema +\funcd{poll},\footnote{la funzione è prevista dallo standard XPG4, ed è stata + introdotta in Linux come system call a partire dal kernel 2.1.23 ed inserita + nelle \acr{libc} 5.4.28, originariamente l'argomento \param{nfds} era di + tipo \ctyp{unsigned int}, la funzione è stata inserita nello standard + POSIX.1-2001 in cui è stato introdotto il tipo nativo \type{nfds\_t}.} il cui prototipo è: \begin{funcproto}{ \fhead{sys/poll.h} -\fdecl{int poll(struct pollfd *ufds, unsigned int nfds, int timeout)} -\fdesc{La funzione attende un cambiamento di stato su un insieme di file +\fdecl{int poll(struct pollfd *ufds, nfds\_t nfds, int timeout)} +\fdesc{Attende un cambiamento di stato su un insieme di file descriptor.} } @@ -1311,8 +1314,19 @@ vettore di strutture \struct{pollfd}. Come con \func{select} si può interrompere l'attesa dopo un certo tempo, questo deve essere specificato con l'argomento \param{timeout} in numero di millisecondi: un valore negativo indica un'attesa indefinita, mentre un valore nullo comporta il ritorno -immediato (e può essere utilizzato per impiegare \func{poll} in modalità -\textsl{non-bloccante}). +immediato, e può essere utilizzato per impiegare \func{poll} in modalità +\textsl{non-bloccante}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.90\textwidth} + \includestruct{listati/pollfd.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{pollfd}, utilizzata per specificare le + modalità di controllo di un file descriptor alla funzione \func{poll}.} + \label{fig:file_pollfd} +\end{figure} Per ciascun file da controllare deve essere inizializzata una struttura \struct{pollfd} nel vettore indicato dall'argomento \param{ufds}. La @@ -1321,30 +1335,24 @@ prevede tre campi: in \var{fd} deve essere indicato il numero del file descriptor da controllare, in \var{events} deve essere specificata una maschera binaria di flag che indichino il tipo di evento che si vuole controllare, mentre in \var{revents} il kernel restituirà il relativo -risultato. Usando un valore negativo per \param{fd} la corrispondente -struttura sarà ignorata da \func{poll}. Dato che i dati in ingresso sono del +risultato. + +Usando un valore negativo per \param{fd} la corrispondente struttura sarà +ignorata da \func{poll} ed il campo \var{revents} verrà azzerato, questo +consente di eliminare temporaneamente un file descriptor dalla lista senza +dover modificare il vettore \param{ufds}. Dato che i dati in ingresso sono del tutto indipendenti da quelli in uscita (che vengono restituiti in \var{revents}) non è necessario reinizializzare tutte le volte il valore delle strutture \struct{pollfd} a meno di non voler cambiare qualche condizione. -\begin{figure}[!htb] - \footnotesize \centering - \begin{minipage}[c]{\textwidth} - \includestruct{listati/pollfd.h} - \end{minipage} - \normalsize - \caption{La struttura \structd{pollfd}, utilizzata per specificare le - modalità di controllo di un file descriptor alla funzione \func{poll}.} - \label{fig:file_pollfd} -\end{figure} - Le costanti che definiscono i valori relativi ai bit usati nelle maschere -binarie dei campi \var{events} e \var{revents} sono riportati in +binarie dei campi \var{events} e \var{revents} sono riportate in tab.~\ref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono -suddivise in tre gruppi, nel primo gruppo si sono indicati i bit utilizzati -per controllare l'attività in ingresso, nel secondo quelli per l'attività in -uscita, mentre il terzo gruppo contiene dei valori che vengono utilizzati solo -nel campo \var{revents} per notificare delle condizioni di errore. +suddivise in tre gruppi principali, nel primo gruppo si sono indicati i bit +utilizzati per controllare l'attività in ingresso, nel secondo quelli per +l'attività in uscita, infine il terzo gruppo contiene dei valori che vengono +utilizzati solo nel campo \var{revents} per notificare delle condizioni di +errore. \begin{table}[htb] \centering @@ -1386,33 +1394,35 @@ nel campo \var{revents} per notificare delle condizioni di errore. dettagli in sez.~\ref{sec:TCP_shutdown}.} Il valore \const{POLLMSG} non viene utilizzato ed è definito solo per -compatibilità con l'implementazione di SysV che usa gli -\textit{stream};\footnote{essi sono una interfaccia specifica di SysV non - presente in Linux, e non hanno nulla a che fare con i file \textit{stream} - delle librerie standard del C.} è da questi che derivano i nomi di alcune -costanti, in quanto per essi sono definite tre classi di dati: -\textsl{normali}, \textit{prioritari} ed \textit{urgenti}. In Linux la -distinzione ha senso solo per i dati urgenti \itindex{out-of-band} dei socket -(vedi sez.~\ref{sec:TCP_urgent_data}), ma su questo e su come \func{poll} -reagisce alle varie condizioni dei socket torneremo in +compatibilità con l'implementazione di System V che usa i cosiddetti +``\textit{stream}''. Si tratta di una interfaccia specifica di SysV non +presente in Linux, che non ha nulla a che fare con gli \textit{stream} delle +librerie standard del C visti in sez.~\ref{sec:file_stream}. Da essa derivano +i nomi di alcune costanti poiché per quegli \textit{stream} sono definite tre +classi di dati: \textsl{normali}, \textit{prioritari} ed \textit{urgenti}. In +Linux la distinzione ha senso solo per i dati urgenti \itindex{out-of-band} +dei socket (vedi sez.~\ref{sec:TCP_urgent_data}), ma su questo e su come +\func{poll} reagisce alle varie condizioni dei socket torneremo in sez.~\ref{sec:TCP_serv_poll}, dove vedremo anche un esempio del suo utilizzo. -Si tenga conto comunque che le costanti relative ai diversi tipi di dati -normali e prioritari, vale a dire \const{POLLRDNORM}, \const{POLLWRNORM}, -\const{POLLRDBAND} e \const{POLLWRBAND} fanno riferimento alle implementazioni -in stile SysV (in particolare le ultime due non vengono usate su Linux), e -sono utilizzabili soltanto qualora si sia definita la macro -\macro{\_XOPEN\_SOURCE}.\footnote{e ci si ricordi di farlo sempre in testa al - file, definirla soltanto prima di includere \headfile{sys/poll.h} non è - sufficiente.} - -In caso di successo funzione ritorna restituendo il numero di file (un valore -positivo) per i quali si è verificata una delle condizioni di attesa richieste -o per i quali si è verificato un errore, nel qual caso vengono utilizzati i -valori di tab.~\ref{tab:file_pollfd_flags} esclusivi di \var{revents}. Un -valore nullo indica che si è raggiunto il timeout, mentre un valore negativo -indica un errore nella chiamata, il cui codice viene riportato al solito -tramite \var{errno}. +Le costanti relative ai diversi tipi di dati normali e prioritari che fanno +riferimento alle implementazioni in stile System V sono \const{POLLRDNORM}, +\const{POLLWRNORM}, \const{POLLRDBAND} e \const{POLLWRBAND}. Le prime due sono +equivalenti rispettivamente a \const{POLLIN} e \const{POLLOUT}, +\const{POLLRDBAND} non viene praticamente mai usata su Linux mentre +\const{POLLWRBAND} ha senso solo sui socket. In ogni caso queste costanti sono +utilizzabili soltanto qualora si sia definita la macro +\macro{\_XOPEN\_SOURCE}. + +In caso di successo \func{poll} ritorna restituendo il numero di file (un +valore positivo) per i quali si è verificata una delle condizioni di attesa +richieste o per i quali si è verificato un errore, avvalorando i relativi bit +di \var{revents}. In caso di errori sui file vengono utilizzati i valori della +terza sezione di tab.~\ref{tab:file_pollfd_flags} che hanno significato solo +per \var{revents} (se specificati in \var{events} vengono ignorati). Un valore +di ritorno nullo indica che si è raggiunto il timeout, mentre un valore +negativo indica un errore nella chiamata, il cui codice viene riportato al +solito tramite \var{errno}. L'uso di \func{poll} consente di superare alcuni dei problemi illustrati in precedenza per \func{select}; anzitutto, dato che in questo caso si usa un @@ -1420,11 +1430,10 @@ vettore di strutture \struct{pollfd} di dimensione arbitraria, non esiste il limite introdotto dalle dimensioni massime di un \itindex{file~descriptor~set} \textit{file descriptor set} e la dimensione dei dati passati al kernel dipende solo dal numero dei file descriptor che si vogliono controllare, non -dal loro valore.\footnote{anche se usando dei bit un \textit{file descriptor - set} può essere più efficiente di un vettore di strutture \struct{pollfd}, - qualora si debba osservare un solo file descriptor con un valore molto alto - ci si troverà ad utilizzare inutilmente un maggiore quantitativo di - memoria.} +dal loro valore. Infatti, anche se usando dei bit un \textit{file descriptor + set} può essere più efficiente di un vettore di strutture \struct{pollfd}, +qualora si debba osservare un solo file descriptor con un valore molto alto ci +si troverà ad utilizzare inutilmente un maggiore quantitativo di memoria. Inoltre con \func{select} lo stesso \itindex{file~descriptor~set} \textit{file descriptor set} è usato sia in ingresso che in uscita, e questo significa @@ -1444,16 +1453,19 @@ prevista da nessuno standard; essa può essere utilizzata esclusivamente se si definisce la macro \macro{\_GNU\_SOURCE} ed ovviamente non deve essere usata se si ha a cuore la portabilità. La funzione è \funcd{ppoll}, ed il suo prototipo è: -\begin{prototype}{sys/poll.h} - {int ppoll(struct pollfd *fds, nfds\_t nfds, const struct timespec *timeout, - const sigset\_t *sigmask)} - - La funzione attende un cambiamento di stato su un insieme di file - descriptor. - - \bodydesc{La funzione restituisce il numero di file descriptor con attività - in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore, - ed in quest'ultimo caso \var{errno} assumerà uno dei valori: + +\begin{funcproto}{ +\fhead{sys/poll.h} +\fdecl{int ppoll(struct pollfd *fds, nfds\_t nfds, + const struct timespec *timeout, \\ +\phantom{int ppoll(}const sigset\_t *sigmask)} + +\fdesc{Attende un cambiamento di stato su un insieme di file descriptor.} +} + +{La funzione ritorna il numero di file descriptor con attività in caso di + successo, $0$ se c'è stato un timeout e $-1$ per un errore, nel qual caso + \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato in uno degli insiemi. @@ -1461,8 +1473,9 @@ prototipo è: \item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite \const{RLIMIT\_NOFILE}. \end{errlist} - ed inoltre \errval{EFAULT} e \errval{ENOMEM}.} -\end{prototype} +ed inoltre \errval{EFAULT} e \errval{ENOMEM} nel loro significato generico. +} +\end{funcproto} La funzione ha lo stesso comportamento di \func{poll}, solo che si può specificare, con l'argomento \param{sigmask}, il puntatore ad una @@ -1476,14 +1489,17 @@ del seguente codice: Eccetto per \param{timeout}, che come per \func{pselect} deve essere un puntatore ad una struttura \struct{timespec}, gli altri argomenti comuni con \func{poll} hanno lo stesso significato, e la funzione restituisce gli stessi -risultati illustrati in precedenza. Come nel caso di \func{pselect} la system -call che implementa \func{ppoll} restituisce, se la funzione viene interrotta -da un segnale, il tempo mancante in \param{timeout}, e come per \func{pselect} -la funzione di libreria fornita dalle \acr{glibc} maschera questo -comportamento non modificando mai il valore di \param{timeout}.\footnote{anche - se in questo caso non esiste nessuno standard che richiede questo - comportamento.} - +risultati illustrati in precedenza. Come nel caso di \func{pselect} la +\textit{system call} che implementa \func{ppoll} restituisce, se la funzione +viene interrotta da un segnale, il tempo mancante in \param{timeout}, e come +per \func{pselect} la funzione di libreria fornita dalle \acr{glibc} maschera +questo comportamento non modificando mai il valore di \param{timeout} anche se +in questo caso non esiste nessuno standard che richieda questo comportamento. + +Infine anche per \func{poll} e \func{ppoll} valgono le considerazioni relative +alla possibilità di avere delle notificazione spurie della disponibilita di +accesso ai file descriptor illustrate per \func{select} in +sez.~\ref{sec:file_select}, che non staremo a ripetere qui. \subsection{L'interfaccia di \textit{epoll}} \label{sec:file_epoll} @@ -1501,10 +1517,10 @@ da \func{poll} a trasferire i dati da e verso il kernel è proporzionale al numero di file descriptor osservati, non a quelli che presentano attività. Quando ci sono decine di migliaia di file descriptor osservati e migliaia di -eventi al secondo,\footnote{il caso classico è quello di un server web di un - sito con molti accessi.} l'uso di \func{poll} comporta la necessità di -trasferire avanti ed indietro da user space a kernel space la lunga lista -delle strutture \struct{pollfd} migliaia di volte al secondo. A questo poi si +eventi al secondo (il caso classico è quello di un server web di un sito con +molti accessi) l'uso di \func{poll} comporta la necessità di trasferire avanti +ed indietro da \textit{user space} a \textit{kernel space} una lunga lista di +strutture \struct{pollfd} migliaia di volte al secondo. A questo poi si aggiunge il fatto che la maggior parte del tempo di esecuzione sarà impegnato ad eseguire una scansione su tutti i file descriptor tenuti sotto controllo per determinare quali di essi (in genere una piccola percentuale) sono @@ -1513,13 +1529,12 @@ dell'interfaccia dell'\textit{I/O multiplexing} viene a costituire un collo di bottiglia che degrada irrimediabilmente le prestazioni. Per risolvere questo tipo di situazioni sono state ideate delle interfacce -specialistiche\footnote{come \texttt{/dev/poll} in Solaris, o \texttt{kqueue} - in BSD.} il cui scopo fondamentale è quello di restituire solamente le -informazioni relative ai file descriptor osservati che presentano una -attività, evitando così le problematiche appena illustrate. In genere queste -prevedono che si registrino una sola volta i file descriptor da tenere sotto -osservazione, e forniscono un meccanismo che notifica quali di questi -presentano attività. +specialistiche (come \texttt{/dev/poll} in Solaris, o \texttt{kqueue} in BSD) +il cui scopo fondamentale è quello di restituire solamente le informazioni +relative ai file descriptor osservati che presentano una attività, evitando +così le problematiche appena illustrate. In genere queste prevedono che si +registrino una sola volta i file descriptor da tenere sotto osservazione, e +forniscono un meccanismo che notifica quali di questi presentano attività. Le modalità con cui avviene la notifica sono due, la prima è quella classica (quella usata da \func{poll} e \func{select}) che viene chiamata \textit{level @@ -1546,88 +1561,87 @@ il file descriptor sia tornato non essere pronto, si potrà ricevere una ulteriore notifica qualora ritornasse pronto. Nel caso di Linux al momento la sola interfaccia che fornisce questo tipo di -servizio è \textit{epoll},\footnote{l'interfaccia è stata creata da Davide - Libenzi, ed è stata introdotta per la prima volta nel kernel 2.5.44, ma la - sua forma definitiva è stata raggiunta nel kernel 2.5.66.} anche se sono in -discussione altre interfacce con le quali si potranno effettuare lo stesso -tipo di operazioni;\footnote{al momento della stesura di queste note (Giugno - 2007) un'altra interfaccia proposta è quella di \textit{kevent}, che - fornisce un sistema di notifica di eventi generico in grado di fornire le - stesse funzionalità di \textit{epoll}, esiste però una forte discussione - intorno a tutto ciò e niente di definito.} \textit{epoll} è in grado di -operare sia in modalità \textit{level triggered} che \textit{edge triggered}. - -La prima versione \textit{epoll} prevedeva l'apertura di uno speciale file di -dispositivo, \texttt{/dev/epoll}, per ottenere un file descriptor da -utilizzare con le funzioni dell'interfaccia,\footnote{il backporting - dell'interfaccia per il kernel 2.4, non ufficiale, utilizza sempre questo - file.} ma poi si è passati all'uso di apposite \textit{system call}. Il -primo passo per usare l'interfaccia di \textit{epoll} è pertanto quello -ottenere detto file descriptor chiamando una delle funzioni -\funcd{epoll\_create} e \funcd{epoll\_create1},\footnote{l'interfaccia di - \textit{epoll} è stata inserita nel kernel a partire dalla versione 2.5.44, - ed il supporto è stato aggiunto alle \acr{glibc} 2.3.2.} i cui prototipi -sono: -\begin{functions} - \headdecl{sys/epoll.h} +servizio è chiamata \textit{epoll},\footnote{l'interfaccia è stata creata da + Davide Libenzi, ed è stata introdotta per la prima volta nel kernel 2.5.44, + ma la sua forma definitiva è stata raggiunta nel kernel 2.5.66, il supporto + è stato aggiunto nelle \acr{glibc} a partire dalla versione 2.3.2.} anche se +sono state in discussione altre interfacce con le quali effettuare lo stesso +tipo di operazioni; \textit{epoll} è in grado di operare sia in modalità +\textit{level triggered} che \textit{edge triggered}. + +La prima versione di \textit{epoll} prevedeva l'apertura di uno speciale file +di dispositivo, \texttt{/dev/epoll}, per ottenere un file descriptor da +utilizzare con le funzioni dell'interfaccia ma poi si è passati all'uso di +apposite \textit{system call}. Il primo passo per usare l'interfaccia di +\textit{epoll} è pertanto quello ottenere detto file descriptor chiamando una +delle due funzioni di sistema \funcd{epoll\_create} e \funcd{epoll\_create1}, +i cui prototipi sono: - \funcdecl{int epoll\_create(int size)} - \funcdecl{int epoll\_create1(int flags)} - - Apre un file descriptor per \textit{epoll}. - - \bodydesc{Le funzioni restituiscono un file descriptor per \textit{epoll} in - caso di successo, o $-1$ in caso di errore, nel qual caso \var{errno} - assumerà uno dei valori: +\begin{funcproto}{ +\fhead{sys/epoll.h} +\fdecl{int epoll\_create(int size)} +\fdecl{int epoll\_create1(int flags)} + +\fdesc{Apre un file descriptor per \textit{epoll}.} +} +{Le funzioni ritornano un file descriptor per \textit{epoll} in caso di + successo e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei + valori: \begin{errlist} \item[\errcode{EINVAL}] si è specificato un valore di \param{size} non positivo o non valido per \param{flags}. - \item[\errcode{ENFILE}] si è raggiunto il massimo di file descriptor aperti - nel sistema. \item[\errcode{EMFILE}] si è raggiunto il limite sul numero massimo di istanze di \textit{epoll} per utente stabilito da \sysctlfile{fs/epoll/max\_user\_instances}. + \item[\errcode{ENFILE}] si è raggiunto il massimo di file descriptor aperti + nel sistema. \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel per creare l'istanza. \end{errlist} -} -\end{functions} +} +\end{funcproto} Entrambe le funzioni restituiscono un file descriptor speciale,\footnote{esso non è associato a nessun file su disco, inoltre a differenza dei normali file descriptor non può essere inviato ad un altro processo attraverso un socket locale (vedi sez.~\ref{sec:sock_fd_passing}).} detto anche \textit{epoll descriptor}, che viene associato alla infrastruttura utilizzata -dal kernel per gestire la notifica degli eventi. Nel caso di -\func{epoll\_create} l'argomento \param{size} serviva a dare l'indicazione del -numero di file descriptor che si vorranno tenere sotto controllo, e costituiva -solo un suggerimento per semplificare l'allocazione di risorse sufficienti, -non un valore massimo.\footnote{ma a partire dal kernel 2.6.8 esso viene - totalmente ignorato e l'allocazione è sempre dinamica.} - -La seconda versione della funzione, \func{epoll\_create1} è stata -introdotta\footnote{è disponibile solo a partire dal kernel 2.6.27.} come -estensione della precedente, per poter passare dei flag di controllo come -maschera binaria in fase di creazione del file descriptor. Al momento l'unico -valore legale per \param{flags} (a parte lo zero) è \const{EPOLL\_CLOEXEC}, -che consente di impostare in maniera atomica sul file descriptor il flag di -\itindex{close-on-exec} \textit{close-on-exec} (si veda il significato di -\const{O\_CLOEXEC} in sez.~\ref{sec:file_open_close}), senza che sia +dal kernel per gestire la notifica degli eventi. Una volta che se ne sia +terminato l'uso si potranno rilasciare tutte le risorse allocate chiudendolo +come ogni altro file descriptor con \func{close}. + +Nel caso di \func{epoll\_create} l'argomento \param{size} serviva a dare +l'indicazione del numero di file descriptor che si vorranno tenere sotto +controllo, e costituiva solo un suggerimento per semplificare l'allocazione di +risorse sufficienti, non un valore massimo, ma a partire dal kernel 2.6.8 esso +viene totalmente ignorato e l'allocazione è sempre dinamica. + +La seconda versione della funzione, \func{epoll\_create1} è stata introdotta +come estensione della precedente (è disponibile solo a partire dal kernel +2.6.27) per poter passare dei flag di controllo come maschera binaria in fase +di creazione del file descriptor. Al momento l'unico valore legale +per \param{flags} (a parte lo zero) è \const{EPOLL\_CLOEXEC}, che consente di +impostare in maniera atomica sul file descriptor il flag di +\itindex{close-on-exec} \textit{close-on-exec} (si è trattato il significato +di \const{O\_CLOEXEC} in sez.~\ref{sec:file_open_close}), senza che sia necessaria una successiva chiamata a \func{fcntl}. Una volta ottenuto un file descriptor per \textit{epoll} il passo successivo è indicare quali file descriptor mettere sotto osservazione e quali operazioni -controllare, per questo si deve usare la seconda funzione dell'interfaccia, -\funcd{epoll\_ctl}, il cui prototipo è: -\begin{prototype}{sys/epoll.h} - {int epoll\_ctl(int epfd, int op, int fd, struct epoll\_event *event)} - - Esegue le operazioni di controllo di \textit{epoll}. - - \bodydesc{La funzione restituisce $0$ in caso di successo o $-1$ in caso di - errore, nel qual caso \var{errno} assumerà uno dei valori: +controllare, per questo si deve usare la seconda funzione di sistema +dell'interfaccia, \funcd{epoll\_ctl}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/epoll.h} +\fdecl{int epoll\_ctl(int epfd, int op, int fd, struct epoll\_event *event)} + +\fdesc{Esegue le operazioni di controllo di \textit{epoll}.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{EBADF}] il file descriptor \param{epfd} o \param{fd} non sono + \item[\errcode{EBADF}] i file descriptor \param{epfd} o \param{fd} non sono validi. \item[\errcode{EEXIST}] l'operazione richiesta è \const{EPOLL\_CTL\_ADD} ma \param{fd} è già stato inserito in \param{epfd}. @@ -1638,13 +1652,14 @@ controllare, per questo si deve usare la seconda funzione dell'interfaccia, \const{EPOLL\_CTL\_DEL} ma \param{fd} non è inserito in \param{epfd}. \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel gestire l'operazione richiesta. - \item[\errcode{EPERM}] il file \param{fd} non supporta \textit{epoll}. \item[\errcode{ENOSPC}] si è raggiunto il limite massimo di registrazioni per utente di file descriptor da osservare imposto da \sysctlfile{fs/epoll/max\_user\_watches}. + \item[\errcode{EPERM}] il file associato a \param{fd} non supporta l'uso di + \textit{epoll}. \end{errlist} -} -\end{prototype} + } +\end{funcproto} Il comportamento della funzione viene controllato dal valore dall'argomento \param{op} che consente di specificare quale operazione deve essere eseguita. @@ -1670,7 +1685,8 @@ delle operazioni cui fanno riferimento. \param{event}.\\ \const{EPOLL\_CTL\_DEL}& Rimuove il file descriptor \param{fd} dalla lista dei file controllati tramite \param{epfd}.\\ - \hline + \const{EPOLL\_CTL\_DISABLE}& da fare.\\ + \hline \end{tabular} \caption{Valori dell'argomento \param{op} che consentono di scegliere quale operazione di controllo effettuare con la funzione \func{epoll\_ctl}.} @@ -1700,7 +1716,7 @@ sotto controllo. L'argomento viene ignorato con l'operazione \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{0.90\textwidth} \includestruct{listati/epoll_event.h} \end{minipage} \normalsize @@ -1731,7 +1747,7 @@ identificazione del file descriptor. \begin{table}[htb] \centering \footnotesize - \begin{tabular}[c]{|l|p{8cm}|} + \begin{tabular}[c]{|l|p{10cm}|} \hline \textbf{Valore} & \textbf{Significato} \\ \hline @@ -1760,7 +1776,8 @@ identificazione del file descriptor. \const{EPOLLET} & Imposta la notifica in modalità \textit{edge triggered} per il file descriptor associato.\\ \const{EPOLLONESHOT}& Imposta la modalità \textit{one-shot} per il file - descriptor associato.\footnotemark\\ + descriptor associato (questa modalità è disponibile + solo a partire dal kernel 2.6.2).\\ \hline \end{tabular} \caption{Costanti che identificano i bit del campo \param{events} di @@ -1772,9 +1789,6 @@ identificazione del file descriptor. ed è utile per riconoscere la chiusura di una connessione dall'altro capo quando si lavora in modalità \textit{edge triggered}.} -\footnotetext[48]{questa modalità è disponibile solo a partire dal kernel - 2.6.2.} - % TODO aggiunto EPOLLWAKEUP con il 3.5 @@ -1810,33 +1824,35 @@ non è necessario usare \const{EPOLL\_CTL\_DEL}. Infine una particolare modalità di notifica è quella impostata con \const{EPOLLONESHOT}: a causa dell'implementazione di \textit{epoll} infatti quando si è in modalità \textit{edge triggered} l'arrivo in rapida successione -di dati in blocchi separati\footnote{questo è tipico con i socket di rete, in - quanto i dati arrivano a pacchetti.} può causare una generazione di eventi -(ad esempio segnalazioni di dati in lettura disponibili) anche se la -condizione è già stata rilevata.\footnote{si avrebbe cioè una rottura della - logica \textit{edge triggered}.} +di dati in blocchi separati (questo è tipico con i socket di rete, in quanto i +dati arrivano a pacchetti) può causare una generazione di eventi (ad esempio +segnalazioni di dati in lettura disponibili) anche se la condizione è già +stata rilevata (si avrebbe cioè una rottura della logica \textit{edge + triggered}). Anche se la situazione è facile da gestire, la si può evitare utilizzando \const{EPOLLONESHOT} per impostare la modalità \textit{one-shot}, in cui la notifica di un evento viene effettuata una sola volta, dopo di che il file descriptor osservato, pur restando nella lista di osservazione, viene -automaticamente disattivato,\footnote{la cosa avviene contestualmente al - ritorno di \func{epoll\_wait} a causa dell'evento in questione.} e per -essere riutilizzato dovrà essere riabilitato esplicitamente con una successiva -chiamata con \const{EPOLL\_CTL\_MOD}. +automaticamente disattivato (la cosa avviene contestualmente al ritorno di +\func{epoll\_wait} a causa dell'evento in questione) e per essere riutilizzato +dovrà essere riabilitato esplicitamente con una successiva chiamata con +\const{EPOLL\_CTL\_MOD}. Una volta impostato l'insieme di file descriptor che si vogliono osservare con i relativi eventi, la funzione che consente di attendere l'occorrenza di uno di tali eventi è \funcd{epoll\_wait}, il cui prototipo è: -\begin{prototype}{sys/epoll.h} - {int epoll\_wait(int epfd, struct epoll\_event * events, int maxevents, int - timeout)} - - Attende che uno dei file descriptor osservati sia pronto. - - \bodydesc{La funzione restituisce il numero di file descriptor pronti in - caso di successo o $-1$ in caso di errore, nel qual caso \var{errno} - assumerà uno dei valori: + +\begin{funcproto}{ +\fhead{sys/epoll.h} +\fdecl{int epoll\_wait(int epfd, struct epoll\_event * events, int maxevents, + int timeout)} + +\fdesc{Attende che uno dei file descriptor osservati sia pronto.} +} + +{La funzione ritorna il numero di file descriptor pronti in caso di successo e + $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] il file descriptor \param{epfd} non è valido. \item[\errcode{EFAULT}] il puntatore \param{events} non è valido. @@ -1845,8 +1861,8 @@ di tali eventi è \funcd{epoll\_wait}, il cui prototipo è: \item[\errcode{EINVAL}] il file descriptor \param{epfd} non è stato ottenuto con \func{epoll\_create}, o \param{maxevents} non è maggiore di zero. \end{errlist} -} -\end{prototype} +} +\end{funcproto} La funzione si blocca in attesa di un evento per i file descriptor registrati nella lista di osservazione di \param{epfd} fino ad un tempo massimo @@ -1859,10 +1875,10 @@ con l'argomento \param{maxevents}. La funzione ritorna il numero di eventi rilevati, o un valore nullo qualora sia scaduto il tempo massimo impostato con \param{timeout}. Per quest'ultimo, oltre ad un numero di millisecondi, si può utilizzare il valore nullo, che -indica di non attendere e ritornare immediatamente,\footnote{anche in questo - caso il valore di ritorno sarà nullo.} o il valore $-1$, che indica -un'attesa indefinita. L'argomento \param{maxevents} dovrà invece essere sempre -un intero positivo. +indica di non attendere e ritornare immediatamente (anche in questo caso il +valore di ritorno sarà nullo) o il valore $-1$, che indica un'attesa +indefinita. L'argomento \param{maxevents} dovrà invece essere sempre un intero +positivo. Come accennato la funzione restituisce i suoi risultati nel vettore di strutture \struct{epoll\_event} puntato da \param{events}; in tal caso nel @@ -1871,8 +1887,8 @@ eventi accaduti, mentre nel campo \var{data} sarà restituito il valore che era stato impostato per il file descriptor per cui si è verificato l'evento quando questo era stato registrato con le operazioni \const{EPOLL\_CTL\_MOD} o \const{EPOLL\_CTL\_ADD}, in questo modo il campo \var{data} consente di -identificare il file descriptor.\footnote{ed è per questo che, come accennato, - è consuetudine usare per \var{data} il valore del file descriptor stesso.} +identificare il file descriptor, ed è per questo che, come accennato, è +consuetudine usare per \var{data} il valore del file descriptor stesso. Si ricordi che le occasioni per cui \func{epoll\_wait} ritorna dipendono da come si è impostata la modalità di osservazione (se \textit{level triggered} o @@ -1901,21 +1917,24 @@ per fare questo di nuovo è necessaria una variante della funzione di attesa che consenta di reimpostare all'uscita una \index{maschera~dei~segnali} maschera di segnali, analoga alle estensioni \func{pselect} e \func{ppoll} che abbiamo visto in precedenza per \func{select} e \func{poll}; in questo caso la -funzione si chiama \funcd{epoll\_pwait}\footnote{la funziona è stata +funzione si chiama \funcd{epoll\_pwait}\footnote{la funzione è stata introdotta a partire dal kernel 2.6.19, ed è come tutta l'interfaccia di \textit{epoll}, specifica di Linux.} ed il suo prototipo è: -\begin{prototype}{sys/epoll.h} - {int epoll\_pwait(int epfd, struct epoll\_event * events, int maxevents, + +\begin{funcproto}{ +\fhead{sys/epoll.h} +\fdecl{int epoll\_pwait(int epfd, struct epoll\_event * events, int maxevents, int timeout, const sigset\_t *sigmask)} - Attende che uno dei file descriptor osservati sia pronto, mascherando i - segnali. +\fdesc{Attende che uno dei file descriptor osservati sia pronto, mascherando + i segnali.} } - \bodydesc{La funzione restituisce il numero di file descriptor pronti in - caso di successo o $-1$ in caso di errore, nel qual caso \var{errno} - assumerà uno dei valori già visti con \funcd{epoll\_wait}. -} -\end{prototype} +{La funzione ritorna il numero di file descriptor pronti in caso di successo e + $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori già + visti con \funcd{epoll\_wait}. + +} +\end{funcproto} La funzione è del tutto analoga \funcd{epoll\_wait}, soltanto che alla sua uscita viene ripristinata la \index{maschera~dei~segnali} maschera di segnali @@ -1963,15 +1982,15 @@ risposte, mentre con l'arrivo di un segnale si possono avere interruzioni asincrone in qualunque momento. Questo comporta la necessità di dover gestire, quando si deve tener conto di entrambi i tipi di eventi, le interruzioni delle funzioni di attesa sincrone, ed evitare possibili -\itindex{race~condition} \textit{race conditions}.\footnote{in sostanza se non - fossero per i segnali non ci sarebbe da doversi preoccupare, fintanto che si - effettuano operazioni all'interno di un processo, della non atomicità delle - \index{system~call~lente} \textit{system call} lente che vengono interrotte - e devono essere riavviate.} +\itindex{race~condition} \textit{race conditions}. In sostanza se non ci +fossero i segnali non ci sarebbe da preoccuparsi, fintanto che si effettuano +operazioni all'interno di un processo, della non atomicità delle +\index{system~call~lente} \textit{system call} lente che vengono interrotte e +devono essere riavviate. Abbiamo visto però in sez.~\ref{sec:sig_real_time} che insieme ai segnali \textit{real-time} sono state introdotte anche delle interfacce di gestione -sincrona dei segnali con la funzione \func{sigwait} e le sue affini. Queste +sincrona dei segnali, con la funzione \func{sigwait} e le sue affini. Queste funzioni consentono di gestire i segnali bloccando un processo fino alla avvenuta ricezione e disabilitando l'esecuzione asincrona rispetto al resto del programma del gestore del segnale. Questo consente di risolvere i problemi @@ -1986,9 +2005,9 @@ Per risolvere questo problema nello sviluppo del kernel si è pensato di introdurre un meccanismo alternativo per la notifica dei segnali (esteso anche ad altri eventi generici) che, ispirandosi di nuovo alla filosofia di Unix per cui tutto è un file, consentisse di eseguire la notifica con l'uso di -opportuni file descriptor.\footnote{ovviamente si tratta di una funzionalità - specifica di Linux, non presente in altri sistemi unix-like, e non prevista - da nessuno standard, per cui va evitata se si ha a cuore la portabilità.} +opportuni file descriptor. Ovviamente si tratta di una funzionalità specifica +di Linux, non presente in altri sistemi unix-like, e non prevista da nessuno +standard, per cui va evitata se si ha a cuore la portabilità. In sostanza, come per \func{sigwait}, si può disabilitare l'esecuzione di un gestore in occasione dell'arrivo di un segnale, e rilevarne l'avvenuta @@ -2000,10 +2019,10 @@ stesso modo di quelli associati a file o socket, per cui alla fine si potrà attendere in contemporanea sia l'arrivo del segnale che la disponibilità di accesso ai dati relativi a questi ultimi. -La funzione che permette di abilitare la ricezione dei segnali tramite file -descriptor è \funcd{signalfd},\footnote{in realtà quella riportata è - l'interfaccia alla funzione fornita dalle \acr{glibc}, esistono infatti due - versioni diverse della \textit{system call}; una prima versione, +La funzione di sistema che permette di abilitare la ricezione dei segnali +tramite file descriptor è \funcd{signalfd},\footnote{in realtà quella + riportata è l'interfaccia alla funzione fornita dalle \acr{glibc}, esistono + infatti due versioni diverse della \textit{system call}; una prima versione, \func{signalfd}, introdotta nel kernel 2.6.22 e disponibile con le \acr{glibc} 2.8 che non supporta l'argomento \texttt{flags}, ed una seconda versione, \funcm{signalfd4}, introdotta con il kernel 2.6.27 e che è quella @@ -2011,27 +2030,30 @@ descriptor è \funcd{signalfd},\footnote{in realtà quella riportata è argomento aggiuntivo \code{size\_t sizemask} che indica la dimensione della \index{maschera~dei~segnali} maschera dei segnali, il cui valore viene impostato automaticamente dalle \acr{glibc}.} il cui prototipo è: -\begin{prototype}{sys/signalfd.h} - {int signalfd(int fd, const sigset\_t *mask, int flags)} - Crea o modifica un file descriptor per la ricezione dei segnali. +\begin{funcproto}{ +\fhead{sys/signalfd.h} +\fdecl{int signalfd(int fd, const sigset\_t *mask, int flags)} - \bodydesc{La funzione restituisce un numero di file descriptor in caso di - successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: +\fdesc{Crea o modifica un file descriptor per la ricezione dei segnali.} +} + +{La funzione ritorna un numero di file descriptor in caso di successo e $-1$ + per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] il valore \param{fd} non indica un file descriptor. \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto con \func{signalfd} o il valore di \param{flags} non è valido. - \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file - descriptor di \func{signalfd}. \item[\errcode{ENODEV}] il kernel non può montare internamente il dispositivo per la gestione anonima degli \itindex{inode} \textit{inode} associati al file descriptor. + \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file + descriptor di \func{signalfd}. \end{errlist} - ed inoltre \errval{EMFILE} e \errval{ENFILE}. -} -\end{prototype} + ed inoltre \errval{EMFILE} e \errval{ENFILE} nel loro significato generico. + +} +\end{funcproto} La funzione consente di creare o modificare le caratteristiche di un file descriptor speciale su cui ricevere le notifiche della ricezione di @@ -2056,11 +2078,11 @@ loro inserimento nella maschera verrà ignorato senza generare errori. L'argomento \param{flags} consente di impostare direttamente in fase di creazione due flag per il file descriptor analoghi a quelli che si possono impostare con una creazione ordinaria con \func{open}, evitando una -impostazione successiva con \func{fcntl}.\footnote{questo è un argomento - aggiuntivo, introdotto con la versione fornita a partire dal kernel 2.6.27, - per kernel precedenti il valore deve essere nullo.} L'argomento deve essere -specificato come maschera binaria dei valori riportati in -tab.~\ref{tab:signalfd_flags}. +impostazione successiva con \func{fcntl}.\footnote{si ricordi che questo è un + argomento aggiuntivo, introdotto con la versione fornita a partire dal + kernel 2.6.27, per kernel precedenti il valore deve essere nullo.} +L'argomento deve essere specificato come maschera binaria dei valori riportati +in tab.~\ref{tab:signalfd_flags}. \begin{table}[htb] \centering @@ -2087,9 +2109,10 @@ ordinaria dei segnali indicati da \param{mask}; questa, se si vuole effettuare la ricezione tramite il file descriptor, dovrà essere disabilitata esplicitamente bloccando gli stessi segnali con \func{sigprocmask}, altrimenti verranno comunque eseguite le azioni di default (o un eventuale gestore -installato in precedenza).\footnote{il blocco non ha invece nessun effetto sul - file descriptor restituito da \func{signalfd}, dal quale sarà possibile - pertanto ricevere qualunque segnale, anche se questo risultasse bloccato.} +installato in precedenza). Il blocco non ha invece nessun effetto sul file +descriptor restituito da \func{signalfd}, dal quale sarà possibile pertanto +ricevere qualunque segnale, anche se questo risultasse bloccato. + Si tenga presente inoltre che la lettura di una struttura \struct{signalfd\_siginfo} relativa ad un segnale pendente è equivalente alla esecuzione di un gestore, vale a dire che una volta letta il segnale non sarà @@ -2108,12 +2131,12 @@ diversi. Inoltre è anche possibile tenere sotto osservazione lo stesso segnale con più file descriptor, anche se la pratica è sconsigliata; in tal caso la ricezione del segnale potrà essere effettuata con una lettura da uno qualunque dei file descriptor a cui è associato, ma questa potrà essere eseguita -soltanto una volta.\footnote{questo significa che tutti i file descriptor su - cui è presente lo stesso segnale risulteranno pronti in lettura per le - funzioni di \textit{I/O multiplexing}, ma una volta eseguita la lettura su - uno di essi il segnale sarà considerato ricevuto ed i relativi dati non - saranno più disponibili sugli altri file descriptor, che (a meno di una - ulteriore occorrenza del segnale nel frattempo) di non saranno più pronti.} +soltanto una volta. Questo significa che tutti i file descriptor su cui è +presente lo stesso segnale risulteranno pronti in lettura per le funzioni di +\textit{I/O multiplexing}, ma una volta eseguita la lettura su uno di essi il +segnale sarà considerato ricevuto ed i relativi dati non saranno più +disponibili sugli altri file descriptor, che (a meno di una ulteriore +occorrenza del segnale nel frattempo) di non saranno più pronti. Quando il file descriptor per la ricezione dei segnali non serve più potrà essere chiuso con \func{close} liberando tutte le risorse da esso allocate. In @@ -2150,7 +2173,7 @@ successivo con \func{fcntl}. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{0.90\textwidth} \includestruct{listati/signalfd_siginfo.h} \end{minipage} \normalsize @@ -2169,6 +2192,17 @@ dimensione maggiore potranno essere letti in unica soluzione i dati relativi ad eventuali più segnali pendenti, fino al numero massimo di strutture \struct{signalfd\_siginfo} che possono rientrare nel buffer. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/FifoReporter-init.c} + \end{minipage} + \normalsize + \caption{Sezione di inizializzazione del codice del programma + \file{FifoReporter.c}.} + \label{fig:fiforeporter_code_init} +\end{figure} + Il contenuto di \struct{signalfd\_siginfo} ricalca da vicino quella della analoga struttura \struct{siginfo\_t} (illustrata in fig.~\ref{fig:sig_siginfo_t}) usata dall'interfaccia ordinaria dei segnali, e @@ -2188,43 +2222,32 @@ codice completo si trova al solito nei sorgenti allegati alla guida (nel file In fig.~\ref{fig:fiforeporter_code_init} si è riportata la parte iniziale del programma in cui vengono effettuate le varie inizializzazioni necessarie per l'uso di \itindex{epoll} \textit{epoll} e \func{signalfd}, a partire -(\texttt{\small 12--16}) dalla definizione delle varie variabili e strutture +(\texttt{\small 12-16}) dalla definizione delle varie variabili e strutture necessarie. Al solito si è tralasciata la parte dedicata alla decodifica delle opzioni che consentono ad esempio di cambiare il nome del file associato alla fifo. -\begin{figure}[!htbp] - \footnotesize \centering - \begin{minipage}[c]{\codesamplewidth} - \includecodesample{listati/FifoReporter-init.c} - \end{minipage} - \normalsize - \caption{Sezione di inizializzazione del codice del programma - \file{FifoReporter.c}.} - \label{fig:fiforeporter_code_init} -\end{figure} - -Il primo passo (\texttt{\small 19--20}) è la creazione di un file descriptor +Il primo passo (\texttt{\small 19-20}) è la creazione di un file descriptor \texttt{epfd} di \itindex{epoll} \textit{epoll} con \func{epoll\_create} che è quello che useremo per il controllo degli altri. É poi necessario disabilitare la ricezione dei segnali (nel caso \signal{SIGINT}, \signal{SIGQUIT} e \signal{SIGTERM}) per i quali si vuole la notifica tramite -file descriptor. Per questo prima li si inseriscono (\texttt{\small 22--25}) +file descriptor. Per questo prima li si inseriscono (\texttt{\small 22-25}) in una \index{maschera~dei~segnali} maschera di segnali \texttt{sigmask} che useremo con (\texttt{\small 26}) \func{sigprocmask} per disabilitarli. Con la -stessa maschera si potrà per passare all'uso (\texttt{\small 28--29}) di +stessa maschera si potrà per passare all'uso (\texttt{\small 28-29}) di \func{signalfd} per abilitare la notifica sul file descriptor -\var{sigfd}. Questo poi (\texttt{\small 30--33}) dovrà essere aggiunto con +\var{sigfd}. Questo poi (\texttt{\small 30-33}) dovrà essere aggiunto con \func{epoll\_ctl} all'elenco di file descriptor controllati con \texttt{epfd}. -Occorrerà infine (\texttt{\small 35--38}) creare la \textit{named fifo} se -questa non esiste ed aprirla per la lettura (\texttt{\small 39--40}); una +Occorrerà infine (\texttt{\small 35-38}) creare la \textit{named fifo} se +questa non esiste ed aprirla per la lettura (\texttt{\small 39-40}); una volta fatto questo sarà necessario aggiungere il relativo file descriptor (\var{fifofd}) a quelli osservati da \itindex{epoll} \textit{epoll} in maniera del tutto analoga a quanto fatto con quello relativo alla notifica dei segnali. -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/FifoReporter-main.c} @@ -2235,118 +2258,117 @@ segnali. \end{figure} Una volta completata l'inizializzazione verrà eseguito indefinitamente il -ciclo principale del programma (\texttt{\small 2--45}) che si è riportato in +ciclo principale del programma (\texttt{\small 2-45}) che si è riportato in fig.~\ref{fig:fiforeporter_code_body}, fintanto che questo non riceva un segnale di \signal{SIGINT} (ad esempio con la pressione di \texttt{C-c}). Il -ciclo prevede che si attenda (\texttt{\small 2--3}) la presenza di un file -descriptor pronto in lettura con \func{epoll\_wait},\footnote{si ricordi che - entrambi i file descriptor \var{fifofd} e \var{sigfd} sono stati posti in - osservazioni per eventi di tipo \const{EPOLLIN}.} che si bloccherà fintanto -che non siano stati scritti dati sulla fifo o che non sia arrivato un -segnale.\footnote{per semplificare il codice non si è trattato il caso in cui - \func{epoll\_wait} viene interrotta da un segnale, assumendo che tutti - quelli che possano interessare siano stati predisposti per la notifica - tramite file descriptor, per gli altri si otterrà semplicemente l'uscita dal - programma.} +ciclo prevede che si attenda (\texttt{\small 2-3}) la presenza di un file +descriptor pronto in lettura con \func{epoll\_wait} (si ricordi che entrambi i +file descriptor \var{fifofd} e \var{sigfd} sono stati posti in osservazioni +per eventi di tipo \const{EPOLLIN}) che si bloccherà fintanto che non siano +stati scritti dati sulla fifo o che non sia arrivato un segnale.\footnote{per + semplificare il codice non si è trattato il caso in cui \func{epoll\_wait} + viene interrotta da un segnale, assumendo che tutti quelli che possano + interessare siano stati predisposti per la notifica tramite file descriptor, + per gli altri si otterrà semplicemente l'uscita dal programma.} Anche se in questo caso i file descriptor pronti possono essere al più due, si è comunque adottato un approccio generico in cui questi verranno letti -all'interno di un opportuno ciclo (\texttt{\small 5--44}) sul numero +all'interno di un opportuno ciclo (\texttt{\small 5-44}) sul numero restituito da \func{epoll\_wait}, esaminando i risultati presenti nel vettore \var{events} all'interno di una catena di condizionali alternativi sul valore -del file descriptor riconosciuto come pronto.\footnote{controllando cioè a - quale dei due file descriptor possibili corrisponde il campo relativo, - \var{events[i].data.fd}.} +del file descriptor riconosciuto come pronto, controllando cioè a quale dei +due file descriptor possibili corrisponde il campo relativo, +\var{events[i].data.fd}. -Il primo condizionale (\texttt{\small 6--24}) è relativo al caso che si sia +Il primo condizionale (\texttt{\small 6-24}) è relativo al caso che si sia ricevuto un segnale e che il file descriptor pronto corrisponda (\texttt{\small 6}) a \var{sigfd}. Dato che in generale si possono ricevere anche notifiche relativi a più di un singolo segnale, si è scelto di leggere una struttura \struct{signalfd\_siginfo} alla volta, eseguendo la lettura -all'interno di un ciclo (\texttt{\small 8--24}) che prosegue fintanto che vi +all'interno di un ciclo (\texttt{\small 8-24}) che prosegue fintanto che vi siano dati da leggere. -Per questo ad ogni lettura si esamina (\texttt{\small 9--14}) se il valore di +Per questo ad ogni lettura si esamina (\texttt{\small 9-14}) se il valore di ritorno della funzione \func{read} è negativo, uscendo dal programma (\texttt{\small 11}) in caso di errore reale, o terminando il ciclo (\texttt{\small 13}) con un \texttt{break} qualora si ottenga un errore di -\errcode{EAGAIN} per via dell'esaurimento dei dati.\footnote{si ricordi come - sia la fifo che il file descriptor per i segnali siano stati aperti in - modalità non-bloccante, come previsto per l’\textit{I/O multiplexing}, - pertanto ci si aspetta di ricevere un errore di \errcode{EAGAIN} quando non - vi saranno più dati da leggere.} +\errcode{EAGAIN} per via dell'esaurimento dei dati. Si ricordi infatti come +sia la fifo che il file descriptor per i segnali siano stati aperti in +modalità non-bloccante, come previsto per l’\textit{I/O multiplexing}, +pertanto ci si aspetta di ricevere un errore di \errcode{EAGAIN} quando non vi +saranno più dati da leggere. In presenza di dati invece il programma proseguirà l'esecuzione stampando -(\texttt{\small 19--20}) il nome del segnale ottenuto all'interno della -struttura \struct{signalfd\_siginfo} letta in \var{siginf}\footnote{per la - stampa si è usato il vettore \var{sig\_names} a ciascun elemento del quale - corrisponde il nome del segnale avente il numero corrispondente, la cui - definizione si è omessa dal codice di fig.~\ref{fig:fiforeporter_code_init} - per brevità.} ed il \textit{pid} del processo da cui lo ha ricevuto; inoltre -(\texttt{\small 21--24}) si controllerà anche se il segnale ricevuto è +(\texttt{\small 19-20}) il nome del segnale ottenuto all'interno della +struttura \struct{signalfd\_siginfo} letta in \var{siginf} ed il \textit{pid} +del processo da cui lo ha ricevuto;\footnote{per la stampa si è usato il + vettore \var{sig\_names} a ciascun elemento del quale corrisponde il nome + del segnale avente il numero corrispondente, la cui definizione si è omessa + dal codice di fig.~\ref{fig:fiforeporter_code_init} per brevità.} inoltre +(\texttt{\small 21-24}) si controllerà anche se il segnale ricevuto è \signal{SIGINT}, che si è preso come segnale da utilizzare per la terminazione del programma, che verrà eseguita dopo aver rimosso il file della \textit{name fifo}. -Il secondo condizionale (\texttt{\small 26--39}) è invece relativo al caso in +Il secondo condizionale (\texttt{\small 26-39}) è invece relativo al caso in cui ci siano dati pronti in lettura sulla fifo e che il file descriptor pronto corrisponda (\texttt{\small 26}) a \var{fifofd}. Di nuovo si effettueranno le -letture in un ciclo (\texttt{\small 28--39}) ripetendole fin tanto che la +letture in un ciclo (\texttt{\small 28-39}) ripetendole fin tanto che la funzione \func{read} non restituisce un errore di \errcode{EAGAIN} -(\texttt{\small 29--35}).\footnote{il procedimento è lo stesso adottato per il - file descriptor associato al segnale, in cui si esce dal programma in caso - di errore reale, in questo caso però alla fine dei dati prima di uscire si - stampa anche (\texttt{\small 32}) un messaggio di chiusura.} Se invece vi -sono dati validi letti dalla fifo si inserirà (\texttt{\small 36}) una -terminazione di stringa sul buffer e si stamperà il tutto (\texttt{\small - 37--38}) sullo \textit{standard output}. L'ultimo condizionale -(\texttt{\small 40--44}) è semplicemente una condizione di cattura per una +(\texttt{\small 29-35}). Il procedimento è lo stesso adottato per il file +descriptor associato al segnale, in cui si esce dal programma in caso di +errore reale, in questo caso però alla fine dei dati prima di uscire si stampa +anche (\texttt{\small 32}) un messaggio di chiusura. + +Se invece vi sono dati validi letti dalla fifo si inserirà (\texttt{\small + 36}) una terminazione di stringa sul buffer e si stamperà il tutto +(\texttt{\small 37-38}) sullo \textit{standard output}. L'ultimo condizionale +(\texttt{\small 40-44}) è semplicemente una condizione di cattura per una eventualità che comunque non dovrebbe mai verificarsi, e che porta alla uscita dal programma con una opportuna segnalazione di errore. A questo punto si potrà eseguire il comando lanciandolo su un terminale, ed osservarne le reazioni agli eventi generati da un altro terminale; lanciando il programma otterremo qualcosa del tipo: -\begin{Verbatim} -piccardi@hain:~/gapil/sources$ ./a.out +\begin{Console} +piccardi@hain:~/gapil/sources$ \textbf{./a.out} FifoReporter starting, pid 4568 -\end{Verbatim} +\end{Console} %$ e scrivendo qualcosa sull'altro terminale con: -\begin{Verbatim} -root@hain:~# echo prova > /tmp/reporter.fifo -\end{Verbatim} +\begin{Console} +root@hain:~# \textbf{echo prova > /tmp/reporter.fifo} +\end{Console} si otterrà: -\begin{Verbatim} +\begin{Console} Message from fifo: prova end message -\end{Verbatim} +\end{Console} mentre inviando un segnale: -\begin{Verbatim} -root@hain:~# kill 4568 -\end{Verbatim} +\begin{Console} +root@hain:~# \textbf{kill 4568} +\end{Console} si avrà: -\begin{Verbatim} +\begin{Console} Signal received: Got SIGTERM From pid 3361 -\end{Verbatim} +\end{Console} ed infine premendo \texttt{C-\bslash} sul terminale in cui è in esecuzione si vedrà: -\begin{Verbatim} -^\Signal received: +\begin{Console} +^\\Signal received: Got SIGQUIT From pid 0 -\end{Verbatim} +\end{Console} e si potrà far uscire il programma con \texttt{C-c} ottenendo: -\begin{Verbatim} +\begin{Console} ^CSignal received: Got SIGINT From pid 0 SIGINT means exit -\end{Verbatim} - +\end{Console} Lo stesso paradigma di notifica tramite file descriptor usato per i segnali è stato adottato anche per i timer. In questo caso, rispetto a quanto visto in @@ -2355,10 +2377,10 @@ file descriptor senza dover ricorrere ad altri meccanismi di notifica come un segnale o un \textit{thread}. Di nuovo questo ha il vantaggio di poter utilizzare le funzioni dell'\textit{I/O multiplexing} per attendere allo stesso tempo la disponibilità di dati o la ricezione della scadenza di un -timer.\footnote{in realtà per questo sarebbe già sufficiente \func{signalfd} - per ricevere i segnali associati ai timer, ma la nuova interfaccia - semplifica notevolmente la gestione e consente di fare tutto con una sola - \textit{system call}.} +timer. In realtà per questo sarebbe già sufficiente \func{signalfd} per +ricevere i segnali associati ai timer, ma la nuova interfaccia semplifica +notevolmente la gestione e consente di fare tutto con una sola \textit{system + call}. Le funzioni di questa nuova interfaccia ricalcano da vicino la struttura delle analoghe versioni ordinarie introdotte con lo standard POSIX.1-2001, che @@ -2368,30 +2390,33 @@ abbiamo già illustrato in sez.~\ref{sec:sig_timer_adv}.\footnote{questa reintrodotta in una forma considerata adeguata nel kernel 2.6.25, il supporto nelle \acr{glibc} è stato introdotto a partire dalla versione 2.8.6, la versione del kernel 2.6.22, presente solo su questo kernel, non è - supportata e non deve essere usata.} La prima funzione prevista, quella che -consente di creare un timer, è \funcd{timerfd\_create}, il cui prototipo è: -\begin{prototype}{sys/timerfd.h} - {int timerfd\_create(int clockid, int flags)} + supportata e non deve essere usata.} La prima funzione di sistema prevista, +quella che consente di creare un timer, è \funcd{timerfd\_create}, il cui +prototipo è: - Crea un timer associato ad un file descriptor per la notifica. +\begin{funcproto}{ +\fhead{sys/timerfd.h} +\fdecl{int timerfd\_create(int clockid, int flags)} - \bodydesc{La funzione restituisce un numero di file descriptor in caso di - successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: +\fdesc{Crea un timer associato ad un file descriptor per la notifica.} +} + +{La funzione ritorna un numero di file descriptor in caso di successo e $-1$ + per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EINVAL}] l'argomento \param{clockid} non è \const{CLOCK\_MONOTONIC} o \const{CLOCK\_REALTIME}, o l'argomento \param{flag} non è valido, o è diverso da zero per kernel precedenti il 2.6.27. - \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file - descriptor di \func{signalfd}. \item[\errcode{ENODEV}] il kernel non può montare internamente il dispositivo per la gestione anonima degli \itindex{inode} \textit{inode} associati al file descriptor. + \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file + descriptor di \func{signalfd}. \end{errlist} - ed inoltre \errval{EMFILE} e \errval{ENFILE}. -} -\end{prototype} + ed inoltre \errval{EMFILE} e \errval{ENFILE} nel loro significato generico. +} +\end{funcproto} La funzione prende come primo argomento un intero che indica il tipo di orologio a cui il timer deve fare riferimento, i valori sono gli stessi delle @@ -2429,41 +2454,43 @@ tab.~\ref{tab:timerfd_flags}. In caso di successo la funzione restituisce un file descriptor sul quale verranno notificate le scadenze dei timer. Come per quelli restituiti da \func{signalfd} anche questo file descriptor segue la semantica dei sistemi -unix-like, in particolare resta aperto attraverso una \func{exec},\footnote{a - meno che non si sia impostato il flag di \textit{close-on exec} con - \const{TFD\_CLOEXEC}.} e viene duplicato attraverso una \func{fork}; questa +unix-like, in particolare resta aperto attraverso una \func{exec} (a meno che +non si sia impostato il flag di \textit{close-on exec} con +\const{TFD\_CLOEXEC}) e viene duplicato attraverso una \func{fork}; questa ultima caratteristica comporta però che anche il figlio può utilizzare i dati di un timer creato nel padre, a differenza di quanto avviene invece con i -timer impostati con le funzioni ordinarie.\footnote{si ricordi infatti che, - come illustrato in sez.~\ref{sec:proc_fork}, allarmi, timer e segnali - pendenti nel padre vengono cancellati per il figlio dopo una \func{fork}.} +timer impostati con le funzioni ordinarie. Si ricordi infatti che, come +illustrato in sez.~\ref{sec:proc_fork}, allarmi, timer e segnali pendenti nel +padre vengono cancellati per il figlio dopo una \func{fork}. Una volta creato il timer con \func{timerfd\_create} per poterlo utilizzare occorre \textsl{armarlo} impostandone un tempo di scadenza ed una eventuale -periodicità di ripetizione, per farlo si usa la funzione omologa di -\func{timer\_settime} per la nuova interfaccia; questa è +periodicità di ripetizione, per farlo si usa una funzione di sistema omologa +di \func{timer\_settime} per la nuova interfaccia; questa è \funcd{timerfd\_settime} ed il suo prototipo è: -\begin{prototype}{sys/timerfd.h} - {int timerfd\_settime(int fd, int flags, - const struct itimerspec *new\_value, - struct itimerspec *old\_value)} - Crea un timer associato ad un file descriptor per la notifica. +\begin{funcproto}{ +\fhead{sys/timerfd.h} +\fdecl{int timerfd\_settime(int fd, int flags, + const struct itimerspec *new\_value,\\ +\phantom{int timerfd\_settime(}struct itimerspec *old\_value)} - \bodydesc{La funzione restituisce un numero di file descriptor in caso di - successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: +\fdesc{Crea un timer associato ad un file descriptor per la notifica.} +} + +{La funzione ritorna un numero di file descriptor in caso di successo e $-1$ + per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] l'argomento \param{fd} non corrisponde ad un file descriptor. + \item[\errcode{EFAULT}] o \param{new\_value} o \param{old\_value} non sono + puntatori validi. \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto con \func{timerfd\_create}, o i valori di \param{flag} o dei campi \var{tv\_nsec} in \param{new\_value} non sono validi. - \item[\errcode{EFAULT}] o \param{new\_value} o \param{old\_value} non sono - puntatori validi. \end{errlist} -} -\end{prototype} +} +\end{funcproto} In questo caso occorre indicare su quale timer si intende operare specificando come primo argomento il file descriptor ad esso associato, che deve essere @@ -2486,14 +2513,16 @@ valori possibili rispettivamente soltanto $0$ e L'ultima funzione prevista dalla nuova interfaccia è \funcd{timerfd\_gettime}, che è l'analoga di \func{timer\_gettime}, il suo prototipo è: -\begin{prototype}{sys/timerfd.h} - {int timerfd\_gettime(int fd, struct itimerspec *curr\_value)} - Crea un timer associato ad un file descriptor per la notifica. +\begin{funcproto}{ +\fhead{sys/timerfd.h} +\fdecl{int timerfd\_gettime(int fd, struct itimerspec *curr\_value)} - \bodydesc{La funzione restituisce un numero di file descriptor in caso di - successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: +\fdesc{Crea un timer associato ad un file descriptor per la notifica.} +} + +{La funzione ritorna un numero di file descriptor in caso di successo e $-1$ + per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] l'argomento \param{fd} non corrisponde ad un file descriptor. @@ -2501,24 +2530,18 @@ che è l'analoga di \func{timer\_gettime}, il suo prototipo è: con \func{timerfd\_create}. \item[\errcode{EFAULT}] o \param{curr\_value} non è un puntatore valido. \end{errlist} -} -\end{prototype} - - - - +ed inoltre nel suo significato generico. + +} +\end{funcproto} Questo infatti diverrà pronto in lettura per tutte le varie funzioni dell'I/O multiplexing in presenza di una o più scadenze del timer ad esso associato. Inoltre sarà possibile ottenere il numero di volte che il timer è scaduto -dalla ultima impostazione - -che può essere -usato per leggere le notifiche delle scadenze dei timer. Queste possono essere -ottenute leggendo in maniera ordinaria il file descriptor con una \func{read}, - - +dalla ultima impostazione che può essere usato per leggere le notifiche delle +scadenze dei timer. Queste possono essere ottenute leggendo in maniera +ordinaria il file descriptor con una \func{read}, % TODO trattare qui eventfd, timerfd introdotte con il 2.6.22 @@ -3268,17 +3291,17 @@ funzioni di ausilio è riportato in fig.~\ref{fig:inotify_monitor_example}. \end{figure} Una volta completata la scansione delle opzioni il corpo principale del -programma inizia controllando (\texttt{\small 11--15}) che sia rimasto almeno +programma inizia controllando (\texttt{\small 11-15}) che sia rimasto almeno un argomento che indichi quale file o directory mettere sotto osservazione (e qualora questo non avvenga esce stampando la pagina di aiuto); dopo di che -passa (\texttt{\small 16--20}) all'inizializzazione di \textit{inotify} +passa (\texttt{\small 16-20}) all'inizializzazione di \textit{inotify} ottenendo con \func{inotify\_init} il relativo file descriptor (oppure usce in caso di errore). -Il passo successivo è aggiungere (\texttt{\small 21--30}) alla coda di +Il passo successivo è aggiungere (\texttt{\small 21-30}) alla coda di notifica gli opportuni osservatori per ciascuno dei file o directory indicati all'invocazione del comando; questo viene fatto eseguendo un ciclo -(\texttt{\small 22--29}) fintanto che la variabile \var{i}, inizializzata a +(\texttt{\small 22-29}) fintanto che la variabile \var{i}, inizializzata a zero (\texttt{\small 21}) all'inizio del ciclo, è minore del numero totale di argomenti rimasti. All'interno del ciclo si invoca (\texttt{\small 23}) \func{inotify\_add\_watch} per ciascuno degli argomenti, usando la maschera @@ -3287,7 +3310,7 @@ nella scansione delle opzioni), in caso di errore si esce dal programma altrimenti si incrementa l'indice (\texttt{\small 29}). Completa l'inizializzazione di \textit{inotify} inizia il ciclo principale -(\texttt{\small 32--56}) del programma, nel quale si resta in attesa degli +(\texttt{\small 32-56}) del programma, nel quale si resta in attesa degli eventi che si intendono osservare. Questo viene fatto eseguendo all'inizio del ciclo (\texttt{\small 33}) una \func{read} che si bloccherà fintanto che non si saranno verificati eventi. @@ -3298,13 +3321,13 @@ dimensioni adeguate, inizializzato in (\texttt{\small 7}) ad un valore di approssimativamente 512 eventi.\footnote{si ricordi che la quantità di dati restituita da \textit{inotify} è variabile a causa della diversa lunghezza del nome del file restituito insieme a \struct{inotify\_event}.} In caso di -errore di lettura (\texttt{\small 35--40}) il programma esce con un messaggio -di errore (\texttt{\small 37--39}), a meno che non si tratti di una +errore di lettura (\texttt{\small 35-40}) il programma esce con un messaggio +di errore (\texttt{\small 37-39}), a meno che non si tratti di una interruzione della \textit{system call}, nel qual caso (\texttt{\small 36}) si ripete la lettura. Se la lettura è andata a buon fine invece si esegue un ciclo (\texttt{\small - 43--52}) per leggere tutti gli eventi restituiti, al solito si inizializza + 43-52}) per leggere tutti gli eventi restituiti, al solito si inizializza l'indice \var{i} a zero (\texttt{\small 42}) e si ripetono le operazioni (\texttt{\small 43}) fintanto che esso non supera il numero di byte restituiti in lettura. Per ciascun evento all'interno del ciclo si assegna\footnote{si @@ -3317,7 +3340,7 @@ comando sfruttando il fatto che i \textit{watch descriptor} vengono assegnati in ordine progressivo crescente a partire da 1. Qualora sia presente il riferimento ad un nome di file associato all'evento lo -si stampa (\texttt{\small 47--49}); si noti come in questo caso si sia +si stampa (\texttt{\small 47-49}); si noti come in questo caso si sia utilizzato il valore del campo \var{event->len} e non al fatto che \var{event->name} riporti o meno un puntatore nullo.\footnote{l'interfaccia infatti, qualora il nome non sia presente, non avvalora il campo @@ -3334,15 +3357,16 @@ aggiornare l'indice \var{i} per farlo puntare all'evento successivo. Se adesso usiamo il programma per mettere sotto osservazione una directory, e da un altro terminale eseguiamo il comando \texttt{ls} otterremo qualcosa del tipo di: -\begin{verbatim} -piccardi@gethen:~/gapil/sources$ ./inotify_monitor -a /home/piccardi/gapil/ +\begin{Console} +piccardi@gethen:~/gapil/sources$ \textbf{./inotify_monitor -a /home/piccardi/gapil/} Watch descriptor 1 Observed event on /home/piccardi/gapil/ IN_OPEN, Watch descriptor 1 Observed event on /home/piccardi/gapil/ IN_CLOSE_NOWRITE, -\end{verbatim} +\end{Console} +%$ I lettori più accorti si saranno resi conto che nel ciclo di lettura degli eventi appena illustrato non viene trattato il caso particolare in cui la @@ -4951,10 +4975,10 @@ fig.~\ref{fig:splicecp_data_flux}. \end{figure} Una volta trattate le opzioni il programma verifica che restino -(\texttt{\small 13--16}) i due argomenti che indicano il file sorgente ed il +(\texttt{\small 13-16}) i due argomenti che indicano il file sorgente ed il file destinazione. Il passo successivo è aprire il file sorgente -(\texttt{\small 18--22}), quello di destinazione (\texttt{\small 23--27}) ed -infine (\texttt{\small 28--31}) la \textit{pipe} che verrà usata come buffer. +(\texttt{\small 18-22}), quello di destinazione (\texttt{\small 23-27}) ed +infine (\texttt{\small 28-31}) la \textit{pipe} che verrà usata come buffer. \begin{figure}[!htbp] \footnotesize \centering @@ -4967,8 +4991,8 @@ infine (\texttt{\small 28--31}) la \textit{pipe} che verrà usata come buffer. \label{fig:splice_example} \end{figure} -Il ciclo principale (\texttt{\small 33--58}) inizia con la lettura dal file -sorgente tramite la prima \func{splice} (\texttt{\small 34--35}), in questo +Il ciclo principale (\texttt{\small 33-58}) inizia con la lettura dal file +sorgente tramite la prima \func{splice} (\texttt{\small 34-35}), in questo caso si è usato come primo argomento il file descriptor del file sorgente e come terzo quello del capo in scrittura della \textit{pipe} (il funzionamento delle \textit{pipe} e l'uso della coppia di file descriptor ad esse associati @@ -4983,13 +5007,13 @@ valore di uscita in \var{nread} che indica quanti byte sono stati letti, se detto valore è nullo (\texttt{\small 36}) questo significa che si è giunti alla fine del file sorgente e pertanto l'operazione di copia è conclusa e si può uscire dal ciclo arrivando alla conclusione del programma (\texttt{\small - 59}). In caso di valore negativo (\texttt{\small 37--44}) c'è stato un + 59}). In caso di valore negativo (\texttt{\small 37-44}) c'è stato un errore ed allora si ripete la lettura (\texttt{\small 36}) se questo è dovuto ad una interruzione, o altrimenti si esce con un messaggio di errore -(\texttt{\small 41--43}). +(\texttt{\small 41-43}). Una volta completata con successo la lettura si avvia il ciclo di scrittura -(\texttt{\small 45--57}); questo inizia (\texttt{\small 46--47}) con la +(\texttt{\small 45-57}); questo inizia (\texttt{\small 46-47}) con la seconda \func{splice} che cerca di scrivere gli \var{nread} byte letti, si noti come in questo caso il primo argomento faccia di nuovo riferimento alla \textit{pipe} (in questo caso si usa il capo in lettura, per i dettagli si @@ -4999,7 +5023,7 @@ del file di destinazione. Di nuovo si controlla il numero di byte effettivamente scritti restituito in \var{nwrite} e in caso di errore al solito si ripete la scrittura se questo è dovuto a una interruzione o si esce con un messaggio negli altri casi -(\texttt{\small 48--55}). Infine si chiude il ciclo di scrittura sottraendo +(\texttt{\small 48-55}). Infine si chiude il ciclo di scrittura sottraendo (\texttt{\small 57}) il numero di byte scritti a quelli di cui è richiesta la scrittura,\footnote{in questa parte del ciclo \var{nread}, il cui valore iniziale è dato dai byte letti dalla precedente chiamata a \func{splice}, @@ -5140,25 +5164,25 @@ allegati alla guida. \label{fig:tee_example} \end{figure} -La prima parte del programma (\texttt{\small 10--35}) si cura semplicemente di -controllare (\texttt{\small 11--14}) che sia stato fornito almeno un argomento -(il nome del file su cui scrivere), di aprirlo ({\small 15--19}) e che sia lo -standard input (\texttt{\small 20--27}) che lo standard output (\texttt{\small - 28--35}) corrispondano ad una \textit{pipe}. +La prima parte del programma (\texttt{\small 10-35}) si cura semplicemente di +controllare (\texttt{\small 11-14}) che sia stato fornito almeno un argomento +(il nome del file su cui scrivere), di aprirlo ({\small 15-19}) e che sia lo +standard input (\texttt{\small 20-27}) che lo standard output (\texttt{\small + 28-35}) corrispondano ad una \textit{pipe}. -Il ciclo principale (\texttt{\small 37--58}) inizia con la chiamata a +Il ciclo principale (\texttt{\small 37-58}) inizia con la chiamata a \func{tee} che duplica il contenuto dello standard input sullo standard output (\texttt{\small 39}), questa parte è del tutto analoga ad una lettura ed infatti come nell'esempio di fig.~\ref{fig:splice_example} si controlla il valore di ritorno della funzione in \var{len}; se questo è nullo significa che non ci sono più dati da leggere e si chiude il ciclo (\texttt{\small 40}), se è negativo c'è stato un errore, ed allora si ripete la chiamata se questo è -dovuto ad una interruzione (\texttt{\small 42--44}) o si stampa un messaggio -di errore e si esce negli altri casi (\texttt{\small 44--47}). +dovuto ad una interruzione (\texttt{\small 42-44}) o si stampa un messaggio +di errore e si esce negli altri casi (\texttt{\small 44-47}). Una volta completata la copia dei dati sullo standard output si possono estrarre dalla standard input e scrivere sul file, di nuovo su usa un ciclo di -scrittura (\texttt{\small 50--58}) in cui si ripete una chiamata a +scrittura (\texttt{\small 50-58}) in cui si ripete una chiamata a \func{splice} (\texttt{\small 51}) fintanto che non si sono scritti tutti i \var{len} byte copiati in precedenza con \func{tee} (il funzionamento è identico all'analogo ciclo di scrittura del precedente esempio di diff --git a/filedir.tex b/filedir.tex index 4eb9f56..c294d7d 100644 --- a/filedir.tex +++ b/filedir.tex @@ -2442,10 +2442,10 @@ la stampa della sintassi, anch'essa omessa, ma il codice completo può essere trovato coi sorgenti allegati alla guida nel file \file{myls.c}. In sostanza tutto quello che fa il programma, dopo aver controllato -(\texttt{\small 12--15}) di avere almeno un argomento, che indicherà la +(\texttt{\small 12-15}) di avere almeno un argomento, che indicherà la directory da esaminare, è chiamare (\texttt{\small 16}) la funzione \myfunc{dir\_scan} per eseguire la scansione, usando la funzione \code{do\_ls} -(\texttt{\small 22--29}) per fare tutto il lavoro. +(\texttt{\small 22-29}) per fare tutto il lavoro. Quest'ultima si limita (\texttt{\small 26}) a chiamare \func{stat} sul file indicato dalla directory entry passata come argomento (il cui nome è appunto @@ -2472,15 +2472,15 @@ Tutto il grosso del lavoro è svolto dalla funzione \myfunc{dir\_scan}, riportata in fig.~\ref{fig:file_dirscan}. La funzione è volutamente generica e permette di eseguire una funzione, passata come secondo argomento, su tutte le voci di una directory. La funzione inizia con l'aprire (\texttt{\small - 18--22}) uno \textit{stream} sulla directory passata come primo argomento, + 18-22}) uno \textit{stream} sulla directory passata come primo argomento, stampando un messaggio in caso di errore. -Il passo successivo (\texttt{\small 23--24}) è cambiare +Il passo successivo (\texttt{\small 23-24}) è cambiare \index{directory~di~lavoro} directory di lavoro (vedi sez.~\ref{sec:file_work_dir}), usando in sequenza le funzioni \func{dirfd} e \func{fchdir} (in realtà si sarebbe potuto usare direttamente \func{chdir} su \var{dirname}), in modo che durante il successivo ciclo (\texttt{\small - 26--30}) sulle singole voci dello \textit{stream} ci si trovi all'interno + 26-30}) sulle singole voci dello \textit{stream} ci si trovi all'interno della directory.\footnote{questo è essenziale al funzionamento della funzione \code{do\_ls}, e ad ogni funzione che debba usare il campo \var{d\_name}, in quanto i nomi dei file memorizzati all'interno di una struttura @@ -5931,17 +5931,17 @@ ACL di un file, passato come argomento. La sezione principale del programma, da cui si è rimossa la sezione sulla gestione delle opzioni, è riportata in fig.~\ref{fig:proc_mygetfacl}. Il -programma richiede un unico argomento (\texttt{\small 16--20}) che indica il +programma richiede un unico argomento (\texttt{\small 16-20}) che indica il file di cui si vuole leggere la ACL. Se questo è presente si usa (\texttt{\small 22}) la funzione \func{get\_acl\_file} per leggerne la ACL, e -si controlla (\texttt{\small 23--26}) se l'operazione ha successo, uscendo con +si controlla (\texttt{\small 23-26}) se l'operazione ha successo, uscendo con un messaggio di errore in caso contrario. Ottenuta la ACL la si converte in formato testuale (\texttt{\small 27}) con la funzione \func{acl\_to\_text}, controllando di nuovo se l'operazione ha -successo (\texttt{\small 28--31}) ed uscendo in caso contrario. Si provvede +successo (\texttt{\small 28-31}) ed uscendo in caso contrario. Si provvede infine a stampare la rappresentazione testuale (\texttt{\small 32}) e dopo -aver liberato (\texttt{\small 33--34}) le risorse allocate automaticamente, si +aver liberato (\texttt{\small 33-34}) le risorse allocate automaticamente, si conclude l'esecuzione. @@ -6371,11 +6371,11 @@ quote.\footnote{questi vengono passati come argomenti dalle funzioni mappate con \macro{QCMD} al comando \const{Q\_GETQUOTA} per ottenere i dati. La funzione viene eseguita all'interno di un condizionale (\texttt{\small - 5--16}) che in caso di successo provvede a costruire (\texttt{\small 6--12}) + 5-16}) che in caso di successo provvede a costruire (\texttt{\small 6-12}) opportunamente una risposta restituendo tramite la opportuna funzione di interfaccia un oggetto Python contenente i dati della struttura \struct{dqblk} relativi a uso corrente e limiti sia per i blocchi che per gli \itindex{inode} -\textit{inode}. In caso di errore (\texttt{\small 13--15}) si usa un'altra +\textit{inode}. In caso di errore (\texttt{\small 13-15}) si usa un'altra funzione dell'interfaccia per passare il valore di \var{errno} come eccezione. \begin{figure}[!htbp] @@ -6392,16 +6392,16 @@ riportata in fig.~\ref{fig:set_block_quota}, che prende gli stessi argomenti della precedente, con lo stesso significato, a cui si aggiungono i valori per il \textit{soft limit} e l'\textit{hard limit}. In questo caso occorrerà, prima di chiamare \func{quotactl}, inizializzare opportunamente -(\texttt{\small 5--7}) i campi della struttura \struct{dqblk} che si vogliono +(\texttt{\small 5-7}) i campi della struttura \struct{dqblk} che si vogliono utilizzare (quelli relativi ai limiti sui blocchi) e specificare gli stessi con \const{QIF\_BLIMITS} in \var{dq.dqb\_valid}. Fatto questo la chiamata a \func{quotactl}, stavolta con il comando \const{Q\_SETQUOTA}, viene eseguita come in precedenza all'interno di un -condizionale (\texttt{\small 9--14}). In questo caso non essendovi da +condizionale (\texttt{\small 9-14}). In questo caso non essendovi da restituire nessun dato in caso di successo si usa (\texttt{\small 10}) una apposita funzione di uscita, mentre si restituisce come prima una eccezione -con il valore di \var{errno} in caso di errore (\texttt{\small 12--13}). +con il valore di \var{errno} in caso di errore (\texttt{\small 12-13}). \subsection{La gestione delle \textit{capabilities}} @@ -7666,14 +7666,14 @@ e si basa su una condizione sulla variabile \var{pid} che se si è usato l'opzione \texttt{-p} è impostata (nella sezione di gestione delle opzioni, che si è tralasciata) al valore del \ids{PID} del processo di cui si vuole leggere le \textit{capabilities} e nulla altrimenti. Nel primo caso -(\texttt{\small 1--6}) si utilizza (\texttt{\small 2}) \func{cap\_get\_proc} +(\texttt{\small 1-6}) si utilizza (\texttt{\small 2}) \func{cap\_get\_proc} per ottenere lo stato delle capacità del processo, nel secondo (\texttt{\small - 7--13}) si usa invece \func{cap\_get\_pid} (\texttt{\small 8}) per leggere + 7-13}) si usa invece \func{cap\_get\_pid} (\texttt{\small 8}) per leggere il valore delle capacità del processo indicato. Il passo successivo è utilizzare (\texttt{\small 15}) \func{cap\_to\_text} per tradurre in una stringa lo stato, e poi (\texttt{\small 16}) stamparlo; infine -(\texttt{\small 18--19}) si libera la memoria allocata dalle precedenti +(\texttt{\small 18-19}) si libera la memoria allocata dalle precedenti funzioni con \func{cap\_free} per poi ritornare dal ciclo principale della funzione. diff --git a/ipc.tex b/ipc.tex index dcc89fd..9b10da1 100644 --- a/ipc.tex +++ b/ipc.tex @@ -258,7 +258,7 @@ trova nella directory dei sorgenti. \label{fig:ipc_barcodepage_code} \end{figure} -La prima operazione del programma (\texttt{\small 4--12}) è quella di creare +La prima operazione del programma (\texttt{\small 4-12}) è quella di creare le due \textit{pipe} che serviranno per la comunicazione fra i due comandi utilizzati per produrre il codice a barre; si ha cura di controllare la riuscita della chiamata, inviando in caso di errore un messaggio invece @@ -269,8 +269,8 @@ formattare l'uscita alla maniera dei CGI, aggiungendo l'opportuno quest'ultimo possa essere visualizzato correttamente da un browser. Una volta create le \textit{pipe}, il programma può creare (\texttt{\small - 13--17}) il primo processo figlio, che si incaricherà (\texttt{\small - 19--25}) di eseguire \cmd{barcode}. Quest'ultimo legge dallo standard input + 13-17}) il primo processo figlio, che si incaricherà (\texttt{\small + 19-25}) di eseguire \cmd{barcode}. Quest'ultimo legge dallo standard input una stringa di caratteri, la converte nell'immagine PostScript del codice a barre ad essa corrispondente, e poi scrive il risultato direttamente sullo standard output. @@ -306,7 +306,7 @@ Alla conclusione della sua esecuzione \cmd{barcode} avrà inviato l'immagine PostScript del codice a barre sul capo in scrittura della seconda \textit{pipe}; a questo punto si può eseguire la seconda conversione, da PS a JPEG, usando il programma \cmd{gs}. Per questo si crea (\texttt{\small - 30--34}) un secondo processo figlio, che poi (\texttt{\small 35--42}) + 30-34}) un secondo processo figlio, che poi (\texttt{\small 35-42}) eseguirà questo programma leggendo l'immagine PostScript creata da \cmd{barcode} dallo \textit{standard input}, per convertirla in JPEG. @@ -468,7 +468,7 @@ padre non necessita più di eseguire ulteriori operazioni sullo \textit{standard output} e può tranquillamente provvedere alla redirezione. Dato che i vari programmi devono essere lanciati in successione, si è -approntato un ciclo (\texttt{\small 15--19}) che esegue le operazioni in +approntato un ciclo (\texttt{\small 15-19}) che esegue le operazioni in sequenza: prima crea una \textit{pipe} (\texttt{\small 17}) per la scrittura eseguendo il programma con \func{popen}, in modo che essa sia collegata allo \textit{standard input}, e poi redirige (\texttt{\small 18}) lo @@ -484,7 +484,7 @@ Alla fine tutto quello che resta da fare è lanciare (\texttt{\small 21}) il primo processo della catena, che nel caso è \cmd{barcode}, e scrivere (\texttt{\small 23}) la stringa del codice a barre sulla \textit{pipe}, che è collegata al suo \textit{standard input}, infine si può eseguire -(\texttt{\small 24--27}) un ciclo che chiuda con \func{pclose}, nell'ordine +(\texttt{\small 24-27}) un ciclo che chiuda con \func{pclose}, nell'ordine inverso rispetto a quello in cui le si sono create, tutte le \textit{pipe} create in precedenza. @@ -622,7 +622,7 @@ dell'insieme delle frasi non nulla, dato che l'inizializzazione del vettore \var{fortune} avviene solo quando questa dimensione viene specificata, la presenza di un valore nullo provoca l'uscita dal programma attraverso la funzione (non riportata) che ne stampa le modalità d'uso. Dopo di che -installa (\texttt{\small 13--15}) la funzione che gestisce i segnali di +installa (\texttt{\small 13-15}) la funzione che gestisce i segnali di interruzione (anche questa non è riportata in fig.~\ref{fig:ipc_fifo_server}) che si limita a rimuovere dal filesystem la \textit{fifo} usata dal server per comunicare. @@ -634,7 +634,7 @@ dinamicamente la memoria necessaria) nel vettore di puntatori \var{fortune}. Anche il codice della funzione non è riportato, in quanto non direttamente attinente allo scopo dell'esempio. -Il passo successivo (\texttt{\small 17--22}) è quello di creare con +Il passo successivo (\texttt{\small 17-22}) è quello di creare con \func{mkfifo} la \textit{fifo} nota sulla quale il server ascolterà le richieste, qualora si riscontri un errore il server uscirà (escludendo ovviamente il caso in cui la funzione \func{mkfifo} fallisce per la precedente @@ -644,7 +644,7 @@ Una volta che si è certi che la \textit{fifo} di ascolto esiste la procedura di inizializzazione è completata. A questo punto (\texttt{\small 23}) si può chiamare la funzione \func{daemon} per far proseguire l'esecuzione del programma in background come demone. Si può quindi procedere (\texttt{\small - 24--33}) alla apertura della \textit{fifo}: si noti che questo viene fatto + 24-33}) alla apertura della \textit{fifo}: si noti che questo viene fatto due volte, prima in lettura e poi in scrittura, per evitare di dover gestire all'interno del ciclo principale il caso in cui il server è in ascolto ma non ci sono client che effettuano richieste. Si ricordi infatti che quando una @@ -667,31 +667,31 @@ una singola apertura con \const{O\_RDWR}; la doppia apertura comunque ha il vantaggio che non si può scrivere per errore sul capo aperto in sola lettura. Per questo motivo, dopo aver eseguito l'apertura in lettura (\texttt{\small - 24--28}),\footnote{di solito si effettua l'apertura del capo in lettura di + 24-28}),\footnote{di solito si effettua l'apertura del capo in lettura di una \textit{fifo} in modalità non bloccante, per evitare il rischio di uno stallo: se infatti nessuno apre la \textit{fifo} in scrittura il processo non ritornerà mai dalla \func{open}. Nel nostro caso questo rischio non esiste, mentre è necessario potersi bloccare in lettura in attesa di una richiesta.} si esegue una seconda apertura in scrittura (\texttt{\small - 29--32}), scartando il relativo file descriptor, che non sarà mai usato, in + 29-32}), scartando il relativo file descriptor, che non sarà mai usato, in questo modo però la \textit{fifo} resta comunque aperta anche in scrittura, cosicché le successive chiamate a \func{read} possono bloccarsi. A questo punto si può entrare nel ciclo principale del programma che fornisce -le risposte ai client (\texttt{\small 34--50}); questo viene eseguito +le risposte ai client (\texttt{\small 34-50}); questo viene eseguito indefinitamente (l'uscita del server viene effettuata inviando un segnale, in modo da passare attraverso la funzione di chiusura che cancella la \textit{fifo}). Il server è progettato per accettare come richieste dai client delle stringhe che contengono il nome della \textit{fifo} sulla quale deve essere inviata la -risposta. Per cui prima (\texttt{\small 35--39}) si esegue la lettura dalla +risposta. Per cui prima (\texttt{\small 35-39}) si esegue la lettura dalla stringa di richiesta dalla \textit{fifo} nota (che a questo punto si bloccherà tutte le volte che non ci sono richieste). Dopo di che, una volta terminata la stringa (\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero casuale per ricavare la frase da inviare, si procederà (\texttt{\small - 42--46}) all'apertura della \textit{fifo} per la risposta, che poi -(\texttt{\small 47--48}) vi sarà scritta. Infine (\texttt{\small 49}) si + 42-46}) all'apertura della \textit{fifo} per la risposta, che poi +(\texttt{\small 47-48}) vi sarà scritta. Infine (\texttt{\small 49}) si chiude la \textit{fifo} di risposta che non serve più. Il codice del client è invece riportato in fig.~\ref{fig:ipc_fifo_client}, @@ -714,18 +714,18 @@ principale del programma e le definizioni delle variabili. Il codice completo La prima istruzione (\texttt{\small 12}) compone il nome della \textit{fifo} che dovrà essere utilizzata per ricevere la risposta dal server. Si usa il \ids{PID} del processo per essere sicuri di avere un nome univoco; dopo di che -(\texttt{\small 13--18}) si procede alla creazione del relativo file, uscendo +(\texttt{\small 13-18}) si procede alla creazione del relativo file, uscendo in caso di errore (a meno che il file non sia già presente sul filesystem). A questo punto il client può effettuare l'interrogazione del server, per -questo prima si apre la \textit{fifo} nota (\texttt{\small 19--23}), e poi ci +questo prima si apre la \textit{fifo} nota (\texttt{\small 19-23}), e poi ci si scrive (\texttt{\small 24}) la stringa composta in precedenza, che contiene il nome della \textit{fifo} da utilizzare per la risposta. Infine si richiude la \textit{fifo} del server che a questo punto non serve più (\texttt{\small 25}). Inoltrata la richiesta si può passare alla lettura della risposta; anzitutto -si apre (\texttt{\small 26--30}) la \textit{fifo} appena creata, da cui si +si apre (\texttt{\small 26-30}) la \textit{fifo} appena creata, da cui si deve riceverla, dopo di che si effettua una lettura (\texttt{\small 31}) nell'apposito buffer; si è supposto, come è ragionevole, che le frasi inviate dal server siano sempre di dimensioni inferiori a \const{PIPE\_BUF}, @@ -1171,7 +1171,7 @@ di creazione, stampa, cancellazione. I valori di default sono per l'uso delle code di messaggi e per 5 ripetizioni del ciclo. Per questo motivo se non si utilizzano opzioni verrà eseguito per -cinque volte il ciclo (\texttt{\small 7--11}), in cui si crea una coda di +cinque volte il ciclo (\texttt{\small 7-11}), in cui si crea una coda di messaggi (\texttt{\small 8}), se ne stampa l'identificativo (\texttt{\small 9}) e la si rimuove (\texttt{\small 10}). Non stiamo ad approfondire adesso il significato delle funzioni utilizzate, che verranno esaminate nelle @@ -1699,13 +1699,13 @@ messaggi sulla base del loro tipo. Il programma, oltre alle solite variabili per il nome del file da cui leggere le \textit{fortunes} e per il vettore di stringhe che contiene le frasi, definisce due strutture appositamente per la comunicazione; con -\var{msgbuf\_read} vengono passate (\texttt{\small 8--11}) le richieste mentre -con \var{msgbuf\_write} vengono restituite (\texttt{\small 12--15}) le frasi. +\var{msgbuf\_read} vengono passate (\texttt{\small 8-11}) le richieste mentre +con \var{msgbuf\_write} vengono restituite (\texttt{\small 12-15}) le frasi. La gestione delle opzioni si è al solito omessa, essa si curerà di impostare nella variabile \var{n} il numero di frasi da leggere specificato a linea di comando ed in \var{fortunefilename} il file da cui leggerle. Dopo aver -installato (\texttt{\small 19--21}) i gestori dei segnali per trattare +installato (\texttt{\small 19-21}) i gestori dei segnali per trattare l'uscita dal server, viene prima controllato (\texttt{\small 22}) il numero di frasi richieste abbia senso (cioè sia maggiore di zero), le quali poi vengono lette (\texttt{\small 23}) nel vettore in memoria con la stessa funzione @@ -1717,11 +1717,11 @@ una chiave per identificare la coda di messaggi (si usa il nome del file dei sorgenti del server) con la quale poi si esegue (\texttt{\small 26}) la creazione della stessa (si noti come si sia chiamata \func{msgget} con un valore opportuno per l'argomento \param{flag}), avendo cura di abortire il -programma (\texttt{\small 27--29}) in caso di errore. +programma (\texttt{\small 27-29}) in caso di errore. Finita la fase di inizializzazione il server prima (\texttt{\small 32}) chiama la funzione \func{daemon} per andare in background e poi esegue in permanenza -il ciclo principale (\texttt{\small 33--40}). Questo inizia (\texttt{\small +il ciclo principale (\texttt{\small 33-40}). Questo inizia (\texttt{\small 34}) con il porsi in attesa di un messaggio di richiesta da parte di un client. Si noti infatti come \func{msgrcv} richieda un messaggio con \var{mtype} uguale a 1, questo è il valore usato per le richieste dato che @@ -1745,7 +1745,7 @@ messaggio di risposta. Si tenga conto che se la coda è piena anche questa funzione potrà bloccarsi fintanto che non venga liberato dello spazio. Si noti che il programma può terminare solo grazie ad una interruzione da -parte di un segnale; in tal caso verrà eseguito (\texttt{\small 45--48}) il +parte di un segnale; in tal caso verrà eseguito (\texttt{\small 45-48}) il gestore \code{HandSIGTERM}, che semplicemente si limita a cancellare la coda (\texttt{\small 46}) ed ad uscire (\texttt{\small 47}). @@ -1769,14 +1769,14 @@ per la comunicazione tramite le code, sono le stesse viste in fig.~\ref{fig:ipc_mq_fortune_server}. Il client in questo caso è molto semplice; la prima parte del programma -(\texttt{\small 4--9}) si occupa di accedere alla coda di messaggi, ed è +(\texttt{\small 4-9}) si occupa di accedere alla coda di messaggi, ed è identica a quanto visto per il server, solo che in questo caso \func{msgget} non viene chiamata con il flag di creazione in quanto la coda deve essere preesistente. In caso di errore (ad esempio se il server non è stato avviato) il programma termina immediatamente. Una volta acquisito l'identificatore della coda il client compone -(\texttt{\small 12--13}) il messaggio di richiesta in \var{msg\_read}, usando +(\texttt{\small 12-13}) il messaggio di richiesta in \var{msg\_read}, usando 1 per il tipo ed inserendo il proprio \ids{PID} come dato da passare al server. Calcolata (\texttt{\small 14}) la dimensione, provvede (\texttt{\small 15}) ad immettere la richiesta sulla coda. @@ -2482,20 +2482,20 @@ nullo per segnalarne l'indisponibilità. \label{fig:ipc_mutex_create} \end{figure} -La prima funzione (\texttt{\small 2--15}) è \func{MutexCreate} che data una +La prima funzione (\texttt{\small 2-15}) è \func{MutexCreate} che data una chiave crea il semaforo usato per il mutex e lo inizializza, restituendone l'identificatore. Il primo passo (\texttt{\small 6}) è chiamare \func{semget} con \const{IPC\_CREATE} per creare il semaforo qualora non esista, assegnandogli i privilegi di lettura e scrittura per tutti. In caso di errore -(\texttt{\small 7--9}) si ritorna subito il risultato di \func{semget}, +(\texttt{\small 7-9}) si ritorna subito il risultato di \func{semget}, altrimenti (\texttt{\small 10}) si inizializza il semaforo chiamando \func{semctl} con il comando \const{SETVAL}, utilizzando l'unione \struct{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 4}) ad 1 per significare che risorsa è libera. In caso di errore (\texttt{\small - 11--13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti + 11-13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti (\texttt{\small 14}) si ritorna l'identificatore del semaforo. -La seconda funzione (\texttt{\small 17--20}) è \func{MutexFind}, che, data una +La seconda funzione (\texttt{\small 17-20}) è \func{MutexFind}, che, data una chiave, restituisce l'identificatore del semaforo ad essa associato. La comprensione del suo funzionamento è immediata in quanto essa è soltanto un \textit{wrapper}\footnote{si chiama così una funzione usata per fare da @@ -2506,21 +2506,21 @@ comprensione del suo funzionamento è immediata in quanto essa è soltanto un l'identificatore associato alla chiave, il valore di ritorno di quest'ultima viene passato all'indietro al chiamante. -La terza funzione (\texttt{\small 22--25}) è \func{MutexRead} che, dato un +La terza funzione (\texttt{\small 22-25}) è \func{MutexRead} che, dato un identificatore, restituisce il valore del semaforo associato al mutex. Anche in questo caso la funzione è un \textit{wrapper} per una chiamata a \func{semctl} con il comando \const{GETVAL}, che permette di restituire il valore del semaforo. -La quarta e la quinta funzione (\texttt{\small 36--44}) sono \func{MutexLock}, +La quarta e la quinta funzione (\texttt{\small 36-44}) sono \func{MutexLock}, e \func{MutexUnlock}, che permettono rispettivamente di bloccare e sbloccare il mutex. Entrambe fanno da wrapper per \func{semop}, utilizzando le due strutture \var{sem\_lock} e \var{sem\_unlock} definite in precedenza -(\texttt{\small 27--34}). Si noti come per queste ultime si sia fatto uso +(\texttt{\small 27-34}). Si noti come per queste ultime si sia fatto uso dell'opzione \const{SEM\_UNDO} per evitare che il semaforo resti bloccato in caso di terminazione imprevista del processo. -L'ultima funzione (\texttt{\small 46--49}) della serie, è \func{MutexRemove}, +L'ultima funzione (\texttt{\small 46-49}) della serie, è \func{MutexRemove}, che rimuove il mutex. Anche in questo caso si ha un wrapper per una chiamata a \func{semctl} con il comando \const{IPC\_RMID}, che permette di cancellare il semaforo; il valore di ritorno di quest'ultima viene passato all'indietro. @@ -2971,37 +2971,37 @@ funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni più comuni; il codice, contenuto nel file \file{SharedMem.c}, è riportato in fig.~\ref{fig:ipc_sysv_shm_func}. -La prima funzione (\texttt{\small 1--16}) è \func{ShmCreate} che, data una +La prima funzione (\texttt{\small 1-16}) è \func{ShmCreate} che, data una chiave, crea il segmento di memoria condivisa restituendo il puntatore allo stesso. La funzione comincia (\texttt{\small 6}) con il chiamare \func{shmget}, usando il flag \const{IPC\_CREATE} per creare il segmento qualora non esista, ed assegnandogli i privilegi specificati dall'argomento \var{perm} e la dimensione specificata dall'argomento \var{shm\_size}. In -caso di errore (\texttt{\small 7--9}) si ritorna immediatamente un puntatore +caso di errore (\texttt{\small 7-9}) si ritorna immediatamente un puntatore nullo, altrimenti (\texttt{\small 10}) si prosegue agganciando il segmento di memoria condivisa al processo con \func{shmat}. In caso di errore -(\texttt{\small 11--13}) si restituisce di nuovo un puntatore nullo, infine +(\texttt{\small 11-13}) si restituisce di nuovo un puntatore nullo, infine (\texttt{\small 14}) si inizializza con \func{memset} il contenuto del segmento al valore costante specificato dall'argomento \var{fill}, e poi si ritorna il puntatore al segmento stesso. -La seconda funzione (\texttt{\small 17--31}) è \func{ShmFind}, che, data una +La seconda funzione (\texttt{\small 17-31}) è \func{ShmFind}, che, data una chiave, restituisce l'indirizzo del segmento ad essa associato. Anzitutto (\texttt{\small 22}) si richiede l'identificatore del segmento con -\func{shmget}, ritornando (\texttt{\small 23--25}) un puntatore nullo in caso +\func{shmget}, ritornando (\texttt{\small 23-25}) un puntatore nullo in caso di errore. Poi si prosegue (\texttt{\small 26}) agganciando il segmento al -processo con \func{shmat}, restituendo (\texttt{\small 27--29}) di nuovo un +processo con \func{shmat}, restituendo (\texttt{\small 27-29}) di nuovo un puntatore nullo in caso di errore, se invece non ci sono errori si restituisce il puntatore ottenuto da \func{shmat}. -La terza funzione (\texttt{\small 32--51}) è \func{ShmRemove} che, data la +La terza funzione (\texttt{\small 32-51}) è \func{ShmRemove} che, data la chiave ed il puntatore associati al segmento di memoria condivisa, prima lo sgancia dal processo e poi lo rimuove. Il primo passo (\texttt{\small 37}) è la chiamata a \func{shmdt} per sganciare il segmento, restituendo -(\texttt{\small 38--39}) un valore -1 in caso di errore. Il passo successivo +(\texttt{\small 38-39}) un valore -1 in caso di errore. Il passo successivo (\texttt{\small 41}) è utilizzare \func{shmget} per ottenere l'identificatore associato al segmento data la chiave \var{key}. Al solito si restituisce un -valore di -1 (\texttt{\small 42--45}) in caso di errore, mentre se tutto va +valore di -1 (\texttt{\small 42-45}) in caso di errore, mentre se tutto va bene si conclude restituendo un valore nullo. Benché la memoria condivisa costituisca il meccanismo di intercomunicazione @@ -3053,7 +3053,7 @@ sorgenti allegati nel file \file{DirMonitor.c}. \end{figure} Il programma usa delle \index{variabili!globali} variabili globali -(\texttt{\small 2--14}) per mantenere i valori relativi agli oggetti usati per +(\texttt{\small 2-14}) per mantenere i valori relativi agli oggetti usati per la comunicazione inter-processo; si è definita inoltre una apposita struttura \struct{DirProp} che contiene i dati relativi alle proprietà che si vogliono mantenere nella memoria condivisa, per l'accesso da parte dei client. @@ -3062,12 +3062,12 @@ Il programma, dopo la sezione, omessa, relativa alla gestione delle opzioni da riga di comando (che si limitano alla eventuale stampa di un messaggio di aiuto a video ed all'impostazione della durata dell'intervallo con cui viene ripetuto il calcolo delle proprietà della directory) controlla (\texttt{\small - 20--23}) che sia stato specificato l'argomento necessario contenente il nome + 20-23}) che sia stato specificato l'argomento necessario contenente il nome della directory da tenere sotto controllo, senza il quale esce immediatamente con un messaggio di errore. Poi, per verificare che l'argomento specifichi effettivamente una directory, -si esegue (\texttt{\small 24--26}) su di esso una \func{chdir}, uscendo +si esegue (\texttt{\small 24-26}) su di esso una \func{chdir}, uscendo immediatamente in caso di errore. Questa funzione serve anche per impostare la \index{directory~di~lavoro} directory di lavoro del programma nella directory da tenere sotto controllo, in vista del successivo uso della @@ -3076,11 +3076,11 @@ nonostante le indicazioni illustrate in sez.~\ref{sec:sess_daemon}, per il particolare scopo del programma, che necessita comunque di restare all'interno di una directory. -Infine (\texttt{\small 27--29}) si installano i gestori per i vari segnali di +Infine (\texttt{\small 27-29}) si installano i gestori per i vari segnali di terminazione che, avendo a che fare con un programma che deve essere eseguito come server, sono il solo strumento disponibile per concluderne l'esecuzione. -Il passo successivo (\texttt{\small 30--39}) è quello di creare gli oggetti di +Il passo successivo (\texttt{\small 30-39}) è quello di creare gli oggetti di intercomunicazione necessari. Si inizia costruendo (\texttt{\small 30}) la chiave da usare come riferimento con il nome del programma,\footnote{si è usato un riferimento relativo alla home dell'utente, supposto che i sorgenti @@ -3089,23 +3089,23 @@ chiave da usare come riferimento con il nome del programma,\footnote{si è richiede (\texttt{\small 31}) la creazione di un segmento di memoria condivisa con usando la funzione \func{ShmCreate} illustrata in precedenza (una pagina di memoria è sufficiente per i dati che useremo), uscendo (\texttt{\small - 32--35}) qualora la creazione ed il successivo agganciamento al processo non + 32-35}) qualora la creazione ed il successivo agganciamento al processo non abbia successo. Con l'indirizzo \var{shmptr} così ottenuto potremo poi accedere alla memoria condivisa, che, per come abbiamo lo abbiamo definito, sarà vista nella forma data da \struct{DirProp}. Infine (\texttt{\small - 36--39}) utilizzando sempre la stessa chiave, si crea, tramite le funzioni + 36-39}) utilizzando sempre la stessa chiave, si crea, tramite le funzioni di interfaccia già descritte in sez.~\ref{sec:ipc_sysv_sem}, anche un mutex, che utilizzeremo per regolare l'accesso alla memoria condivisa. Completata l'inizializzazione e la creazione degli oggetti di intercomunicazione il programma entra nel ciclo principale (\texttt{\small - 40--49}) dove vengono eseguite indefinitamente le attività di monitoraggio. + 40-49}) dove vengono eseguite indefinitamente le attività di monitoraggio. Il primo passo (\texttt{\small 41}) è eseguire \func{daemon} per proseguire con l'esecuzione in background come si conviene ad un programma demone; si noti che si è mantenuta, usando un valore non nullo del primo argomento, la \index{directory~di~lavoro} directory di lavoro corrente. Una volta che il programma è andato in background l'esecuzione prosegue all'interno di un ciclo -infinito (\texttt{\small 42--48}). +infinito (\texttt{\small 42-48}). Si inizia (\texttt{\small 43}) bloccando il mutex con \func{MutexLock} per poter accedere alla memoria condivisa (la funzione si bloccherà @@ -3135,7 +3135,7 @@ esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari. Il codice di quest'ultima è riportato in fig.~\ref{fig:ipc_dirmonitor_sub}. -Come si vede la funzione (\texttt{\small 2--16}) è molto semplice e si limita +Come si vede la funzione (\texttt{\small 2-16}) è molto semplice e si limita a chiamare (\texttt{\small 5}) la funzione \func{stat} sul file indicato da ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari contatori nella memoria condivisa, cui accede grazie alla @@ -3145,13 +3145,13 @@ Dato che la funzione è chiamata da \myfunc{dir\_scan}, si è all'interno del ciclo principale del programma, con un mutex acquisito, perciò non è necessario effettuare nessun controllo e si può accedere direttamente alla memoria condivisa usando \var{shmptr} per riempire i campi della struttura -\struct{DirProp}; così prima (\texttt{\small 6--7}) si sommano le dimensioni +\struct{DirProp}; così prima (\texttt{\small 6-7}) si sommano le dimensioni dei file ed il loro numero, poi, utilizzando le macro di -tab.~\ref{tab:file_type_macro}, si contano (\texttt{\small 8--14}) quanti ce +tab.~\ref{tab:file_type_macro}, si contano (\texttt{\small 8-14}) quanti ce ne sono per ciascun tipo. In fig.~\ref{fig:ipc_dirmonitor_sub} è riportato anche il codice -(\texttt{\small 17--23}) del gestore dei segnali di terminazione, usato per +(\texttt{\small 17-23}) del gestore dei segnali di terminazione, usato per chiudere il programma. Esso, oltre a provocare l'uscita del programma, si incarica anche di cancellare tutti gli oggetti di intercomunicazione non più necessari. Per questo anzitutto (\texttt{\small 19}) acquisisce il mutex con @@ -3182,12 +3182,12 @@ rigenera (\texttt{\small 7}) con \func{ftok} la stessa chiave usata dal server per identificare il segmento di memoria condivisa ed il mutex, poi (\texttt{\small 8}) richiede con \func{ShmFind} l'indirizzo della memoria condivisa agganciando al contempo il segmento al processo, Infine -(\texttt{\small 17--20}) con \func{MutexFind} si richiede l'identificatore del +(\texttt{\small 17-20}) con \func{MutexFind} si richiede l'identificatore del mutex. Completata l'inizializzazione ed ottenuti i riferimenti agli oggetti di intercomunicazione necessari viene eseguito il corpo principale del -programma (\texttt{\small 21--33}); si comincia (\texttt{\small 22}) +programma (\texttt{\small 21-33}); si comincia (\texttt{\small 22}) acquisendo il mutex con \func{MutexLock}; qui avviene il blocco del processo -se la memoria condivisa non è disponibile. Poi (\texttt{\small 23--31}) si +se la memoria condivisa non è disponibile. Poi (\texttt{\small 23-31}) si stampano i vari valori mantenuti nella memoria condivisa attraverso l'uso di \var{shmptr}. Infine (\texttt{\small 41}) con \func{MutexUnlock} si rilascia il mutex, prima di uscire. @@ -3359,8 +3359,8 @@ Un esempio dell'uso di questa funzione è mostrato dalle funzioni (sono contenute in \file{LockFile.c}, un altro dei sorgenti allegati alla guida) che permettono rispettivamente di creare e rimuovere un \textsl{file di lock}. Come si può notare entrambe le funzioni sono elementari; la prima -(\texttt{\small 4--10}) si limita ad aprire il file di lock (\texttt{\small - 9}) nella modalità descritta, mentre la seconda (\texttt{\small 11--17}) lo +(\texttt{\small 4-10}) si limita ad aprire il file di lock (\texttt{\small + 9}) nella modalità descritta, mentre la seconda (\texttt{\small 11-17}) lo cancella con \func{unlink}. \begin{figure}[!htbp] @@ -3445,7 +3445,7 @@ analoga alle precedenti funzioni che usano i semafori, anche se le due interfacce non possono essere completamente equivalenti, specie per quanto riguarda la rimozione del mutex. -La prima funzione (\texttt{\small 1--5}) è \func{CreateMutex}, e serve a +La prima funzione (\texttt{\small 1-5}) è \func{CreateMutex}, e serve a creare il mutex; la funzione è estremamente semplice, e si limita (\texttt{\small 4}) a creare, con una opportuna chiamata ad \func{open}, il file che sarà usato per il successivo \textit{file locking}, assicurandosi che @@ -3453,32 +3453,32 @@ non esista già (nel qual caso segnala un errore); poi restituisce il file descriptor che sarà usato dalle altre funzioni per acquisire e rilasciare il mutex. -La seconda funzione (\texttt{\small 6--10}) è \func{FindMutex}, che, come la +La seconda funzione (\texttt{\small 6-10}) è \func{FindMutex}, che, come la precedente, è stata definita per mantenere una analogia con la corrispondente funzione basata sui semafori. Anch'essa si limita (\texttt{\small 9}) ad aprire il file da usare per il \itindex{file~locking} \textit{file locking}, solo che in questo caso le opzioni di \func{open} sono tali che il file in questione deve esistere di già. -La terza funzione (\texttt{\small 11--22}) è \func{LockMutex} e serve per +La terza funzione (\texttt{\small 11-22}) è \func{LockMutex} e serve per acquisire il mutex. La funzione definisce (\texttt{\small 14}) e inizializza -(\texttt{\small 16--19}) la struttura \var{lock} da usare per acquisire un +(\texttt{\small 16-19}) la struttura \var{lock} da usare per acquisire un write lock sul file, che poi (\texttt{\small 21}) viene richiesto con \func{fcntl}, restituendo il valore di ritorno di quest'ultima. Se il file è libero il lock viene acquisito e la funzione ritorna immediatamente; altrimenti \func{fcntl} si bloccherà (si noti che la si è chiamata con \const{F\_SETLKW}) fino al rilascio del lock. -La quarta funzione (\texttt{\small 24--34}) è \func{UnlockMutex} e serve a +La quarta funzione (\texttt{\small 24-34}) è \func{UnlockMutex} e serve a rilasciare il mutex. La funzione è analoga alla precedente, solo che in questo -caso si inizializza (\texttt{\small 28--31}) la struttura \var{lock} per il +caso si inizializza (\texttt{\small 28-31}) la struttura \var{lock} per il rilascio del lock, che viene effettuato (\texttt{\small 33}) con la opportuna chiamata a \func{fcntl}. Avendo usato il \itindex{file~locking} \textit{file locking} in semantica POSIX (si riveda quanto detto sez.~\ref{sec:file_posix_lock}) solo il processo che ha precedentemente eseguito il lock può sbloccare il mutex. -La quinta funzione (\texttt{\small 36--39}) è \func{RemoveMutex} e serve a +La quinta funzione (\texttt{\small 36-39}) è \func{RemoveMutex} e serve a cancellare il mutex. Anche questa funzione è stata definita per mantenere una analogia con le funzioni basate sui semafori, e si limita a cancellare (\texttt{\small 38}) il file con una chiamata ad \func{unlink}. Si noti che in @@ -3488,8 +3488,8 @@ disponibili fintanto che i relativi file descriptor restano aperti. Pertanto per rilasciare un mutex occorrerà prima chiamare \func{UnlockMutex} oppure chiudere il file usato per il lock. -La sesta funzione (\texttt{\small 41--55}) è \func{ReadMutex} e serve a -leggere lo stato del mutex. In questo caso si prepara (\texttt{\small 46--49}) +La sesta funzione (\texttt{\small 41-55}) è \func{ReadMutex} e serve a +leggere lo stato del mutex. In questo caso si prepara (\texttt{\small 46-49}) la solita struttura \var{lock} come l'acquisizione del lock, ma si effettua (\texttt{\small 51}) la chiamata a \func{fcntl} usando il comando \const{F\_GETLK} per ottenere lo stato del lock, e si restituisce @@ -4339,7 +4339,7 @@ le parti essenziali in fig.~\ref{fig:ipc_posix_shmmem}, è contenuto nel file \label{fig:ipc_posix_shmmem} \end{figure} -La prima funzione (\texttt{\small 1--24}) è \func{CreateShm} che, dato un nome +La prima funzione (\texttt{\small 1-24}) è \func{CreateShm} che, dato un nome nell'argomento \var{name} crea un nuovo segmento di memoria condivisa, accessibile in lettura e scrittura, e ne restituisce l'indirizzo. Anzitutto si definiscono (\texttt{\small 8}) i flag per la successiva (\texttt{\small 9}) @@ -4347,27 +4347,27 @@ chiamata a \func{shm\_open}, che apre il segmento in lettura e scrittura (creandolo se non esiste, ed uscendo in caso contrario) assegnandogli sul filesystem i permessi specificati dall'argomento \var{perm}. -In caso di errore (\texttt{\small 10--12}) si restituisce un puntatore nullo, +In caso di errore (\texttt{\small 10-12}) si restituisce un puntatore nullo, altrimenti si prosegue impostando (\texttt{\small 14}) la dimensione del -segmento con \func{ftruncate}. Di nuovo (\texttt{\small 15--16}) si esce +segmento con \func{ftruncate}. Di nuovo (\texttt{\small 15-16}) si esce immediatamente restituendo un puntatore nullo in caso di errore. Poi si passa (\texttt{\small 18}) a mappare in memoria il segmento con \func{mmap} specificando dei diritti di accesso corrispondenti alla modalità di apertura. -Di nuovo si restituisce (\texttt{\small 19--21}) un puntatore nullo in caso di +Di nuovo si restituisce (\texttt{\small 19-21}) un puntatore nullo in caso di errore, altrimenti si inizializza (\texttt{\small 22}) il contenuto del segmento al valore specificato dall'argomento \var{fill} con \func{memset}, e se ne restituisce (\texttt{\small 23}) l'indirizzo. -La seconda funzione (\texttt{\small 25--40}) è \func{FindShm} che trova un +La seconda funzione (\texttt{\small 25-40}) è \func{FindShm} che trova un segmento di memoria condiviso esistente, restituendone l'indirizzo. In questo caso si apre (\texttt{\small 31}) il segmento con \func{shm\_open} richiedendo -che il segmento sia già esistente, in caso di errore (\texttt{\small 31--33}) +che il segmento sia già esistente, in caso di errore (\texttt{\small 31-33}) si ritorna immediatamente un puntatore nullo. Ottenuto il file descriptor del segmento lo si mappa (\texttt{\small 35}) in memoria con \func{mmap}, -restituendo (\texttt{\small 36--38}) un puntatore nullo in caso di errore, o +restituendo (\texttt{\small 36-38}) un puntatore nullo in caso di errore, o l'indirizzo (\texttt{\small 39}) dello stesso in caso di successo. -La terza funzione (\texttt{\small 40--45}) è \func{RemoveShm}, e serve a +La terza funzione (\texttt{\small 40-45}) è \func{RemoveShm}, e serve a cancellare un segmento di memoria condivisa. Dato che al contrario di quanto avveniva con i segmenti del \textit{SysV-IPC} gli oggetti allocati nel kernel vengono rilasciati automaticamente quando nessuna li usa più, tutto quello che @@ -4845,7 +4845,7 @@ una volta al secondo. Si utilizzerà un semaforo per proteggere l'accesso in lettura alla stringa, in modo che questa non possa essere modificata dall'altro programma prima di averla finita di stampare. -La parte iniziale del programma contiene le definizioni (\texttt{\small 1--8}) +La parte iniziale del programma contiene le definizioni (\texttt{\small 1-8}) del gestore del segnale usato per liberare le risorse utilizzate, delle \index{variabili!globali} variabili globali contenenti i nomi di default del segmento di memoria condivisa e del semaforo (il default scelto è @@ -4854,7 +4854,7 @@ segmento di memoria condivisa e del semaforo (il default scelto è Come prima istruzione (\texttt{\small 10}) si è provveduto ad installare un gestore di segnale che consentirà di effettuare le operazioni di pulizia (usando la funzione \func{Signal} illustrata in -fig.~\ref{fig:sig_Signal_code}), dopo di che (\texttt{\small 12--16}) si è +fig.~\ref{fig:sig_Signal_code}), dopo di che (\texttt{\small 12-16}) si è creato il segmento di memoria condivisa con la funzione \func{CreateShm} che abbiamo appena trattato in sez.~\ref{sec:ipc_posix_shm}, uscendo con un messaggio in caso di errore. @@ -4865,7 +4865,7 @@ abbia già allocato un segmento con quello stesso nome. Per semplicità di gestione si è usata una dimensione fissa pari a 256 byte, definita tramite la costante \texttt{MSGMAXSIZE}. -Il passo successivo (\texttt{\small 17--21}) è quello della creazione del +Il passo successivo (\texttt{\small 17-21}) è quello della creazione del semaforo che regola l'accesso al segmento di memoria condivisa con \func{sem\_open}; anche in questo caso si gestisce l'uscita con stampa di un messaggio in caso di errore. Anche per il semaforo, avendo specificato la @@ -4881,16 +4881,16 @@ programma. Essendo il semaforo stato creato già bloccato non ci si dovrà preoccupare di eventuali \itindex{race~condition} \textit{race condition} qualora il programma di modifica del messaggio venisse lanciato proprio in questo momento. Una volta inizializzato il messaggio occorrerà però -rilasciare il semaforo (\texttt{\small 24--27}) per consentirne l'uso; in +rilasciare il semaforo (\texttt{\small 24-27}) per consentirne l'uso; in tutte queste operazioni si provvederà ad uscire dal programma con un opportuno messaggio in caso di errore. Una volta completate le inizializzazioni il ciclo principale del programma -(\texttt{\small 29--47}) viene ripetuto indefinitamente (\texttt{\small 29}) +(\texttt{\small 29-47}) viene ripetuto indefinitamente (\texttt{\small 29}) per stampare sia il contenuto del messaggio che una serie di informazioni di -controllo. Il primo passo (\texttt{\small 30--34}) è quello di acquisire (con +controllo. Il primo passo (\texttt{\small 30-34}) è quello di acquisire (con \func{sem\_getvalue}, con uscita in caso di errore) e stampare il valore del -semaforo ad inizio del ciclo; seguito (\texttt{\small 35--36}) dal tempo +semaforo ad inizio del ciclo; seguito (\texttt{\small 35-36}) dal tempo corrente. \begin{figure}[!htb] @@ -4905,9 +4905,9 @@ corrente. \end{figure} Prima della stampa del messaggio invece si deve acquisire il semaforo -(\texttt{\small 30--33}) per evitare accessi concorrenti alla stringa da parte +(\texttt{\small 30-33}) per evitare accessi concorrenti alla stringa da parte del programma di modifica. Una volta eseguita la stampa (\texttt{\small 41}) -il semaforo dovrà essere rilasciato (\texttt{\small 42--45}). Il passo finale +il semaforo dovrà essere rilasciato (\texttt{\small 42-45}). Il passo finale (\texttt{\small 46}) è attendere per un secondo prima di eseguire da capo il ciclo. @@ -4943,16 +4943,16 @@ cui il programma si ferma tenendo bloccato il semaforo. Una volta completata la gestione delle opzioni e degli argomenti (ne deve essere presente uno solo, contenente la nuova stringa da usare come -messaggio), il programma procede (\texttt{\small 10--14}) con l'acquisizione +messaggio), il programma procede (\texttt{\small 10-14}) con l'acquisizione del segmento di memoria condivisa usando la funzione \func{FindShm} (trattata in sez.~\ref{sec:ipc_posix_shm}) che stavolta deve già esistere. Il passo -successivo (\texttt{\small 16--19}) è quello di aprire il semaforo, e a +successivo (\texttt{\small 16-19}) è quello di aprire il semaforo, e a differenza di \file{message\_getter}, in questo caso si richiede a \func{sem\_open} che questo esista, passando uno zero come secondo ed unico argomento. Una volta completate con successo le precedenti inizializzazioni, il passo -seguente (\texttt{\small 21--24}) è quello di acquisire il semaforo, dopo di +seguente (\texttt{\small 21-24}) è quello di acquisire il semaforo, dopo di che sarà possibile eseguire la sostituzione del messaggio (\texttt{\small 25}) senza incorrere in possibili \itindex{race~condition} \textit{race condition} con la stampa dello stesso da parte di \file{message\_getter}. @@ -4962,7 +4962,7 @@ di attesa impostato con l'opzione ``\texttt{-t}'' dopo di che (\texttt{\small 27}) viene eseguita la stessa, senza rilasciare il semaforo che resterà quindi bloccato (causando a questo punto una interruzione delle stampe eseguite da \file{message\_getter}). Terminato il tempo di attesa si rilascerà -(\texttt{\small 29--32}) il semaforo per poi uscire. +(\texttt{\small 29-32}) il semaforo per poi uscire. Per verificare il funzionamento dei programmi occorrerà lanciare per primo \file{message\_getter}\footnote{lanciare per primo \file{message\_setter} darà diff --git a/process.tex b/process.tex index 17481d6..9d1916f 100644 --- a/process.tex +++ b/process.tex @@ -1826,12 +1826,12 @@ comando da esso supportate. Si può notare che si è anzitutto (\texttt{\small 1}) disabilitata la stampa di messaggi di errore per opzioni non riconosciute, per poi passare al ciclo per -la verifica delle opzioni (\texttt{\small 2--27}); per ciascuna delle opzioni +la verifica delle opzioni (\texttt{\small 2-27}); per ciascuna delle opzioni possibili si è poi provveduto ad un'azione opportuna, ad esempio per le tre opzioni che prevedono un parametro si è effettuata la decodifica del medesimo, il cui indirizzo è contenuto nella variabile \var{optarg}), avvalorando la -relativa variabile (\texttt{\small 12--14}, \texttt{\small 15--17} e -\texttt{\small 18--20}). Completato il ciclo troveremo in \var{optind} +relativa variabile (\texttt{\small 12-14}, \texttt{\small 15-17} e +\texttt{\small 18-20}). Completato il ciclo troveremo in \var{optind} l'indice in \code{argv[]} del primo degli argomenti rimanenti nella linea di comando. diff --git a/prochand.tex b/prochand.tex index 8cd5634..f41aec8 100644 --- a/prochand.tex +++ b/prochand.tex @@ -383,19 +383,19 @@ distribuito insieme agli altri sorgenti degli esempi su \url{http://gapil.truelite.it/gapil_source.tgz}. Decifrato il numero di figli da creare, il ciclo principale del programma -(\texttt{\small 24--40}) esegue in successione la creazione dei processi figli +(\texttt{\small 24-40}) esegue in successione la creazione dei processi figli controllando il successo della chiamata a \func{fork} (\texttt{\small - 25--29}); ciascun figlio (\texttt{\small 31--34}) si limita a stampare il + 25-29}); ciascun figlio (\texttt{\small 31-34}) si limita a stampare il suo numero di successione, eventualmente attendere il numero di secondi specificato e scrivere un messaggio prima di uscire. Il processo padre invece -(\texttt{\small 36--38}) stampa un messaggio di creazione, eventualmente +(\texttt{\small 36-38}) stampa un messaggio di creazione, eventualmente attende il numero di secondi specificato, e procede nell'esecuzione del ciclo; alla conclusione del ciclo, prima di uscire, può essere specificato un altro periodo di attesa. Se eseguiamo il comando, che è preceduto dall'istruzione \code{export LD\_LIBRARY\_PATH=./} per permettere l'uso delle librerie dinamiche, senza -specificare attese (come si può notare in (\texttt{\small 17--19}) i valori +specificare attese (come si può notare in (\texttt{\small 17-19}) i valori predefiniti specificano di non attendere), otterremo come risultato sul terminale: \begin{Console} diff --git a/system.tex b/system.tex index 35e27f1..81315e6 100644 --- a/system.tex +++ b/system.tex @@ -3125,10 +3125,10 @@ completo del programma è allegato nel file \file{ErrCode.c} e contiene pure la gestione delle opzioni e tutte le definizioni necessarie ad associare il valore numerico alla costante simbolica. In particolare si è riportata la sezione che converte la stringa passata come argomento in un intero -(\texttt{\small 1--2}), controllando con i valori di ritorno di \funcm{strtol} -che la conversione sia avvenuta correttamente (\texttt{\small 4--10}), e poi +(\texttt{\small 1-2}), controllando con i valori di ritorno di \funcm{strtol} +che la conversione sia avvenuta correttamente (\texttt{\small 4-10}), e poi stampa, a seconda dell'opzione scelta il messaggio di errore (\texttt{\small - 11--14}) o la macro (\texttt{\small 15--17}) associate a quel codice. + 11-14}) o la macro (\texttt{\small 15-17}) associate a quel codice.