From 9562f11ab8163e83cbd02c6dffa342629e230ca5 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Tue, 4 Jan 2011 00:56:15 +0000 Subject: [PATCH] Revisione di epoll in vista dell'esempio di FifoReporter.c --- fileadv.tex | 92 +++++++++++++++++++-------- fileunix.tex | 5 +- ipc.tex | 23 ++++--- sources/FifoReporter.c | 140 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 39 deletions(-) create mode 100644 sources/FifoReporter.c diff --git a/fileadv.tex b/fileadv.tex index 9bd8e16..fdf2946 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -1494,36 +1494,59 @@ 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 una apposita \textit{system call}. Il -primo passo per usare l'interfaccia di \textit{epoll} è pertanto quello di -chiamare la funzione \funcd{epoll\_create}, il cui prototipo è: -\begin{prototype}{sys/epoll.h} - {int epoll\_create(int size)} + 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} + + \funcdecl{int epoll\_create(int size)} + \funcdecl{int epoll\_create1(int flags)} Apre un file descriptor per \textit{epoll}. - \bodydesc{La funzione restituisce un file descriptor in caso di successo, o - $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: + \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{errlist} \item[\errcode{EINVAL}] si è specificato un valore di \param{size} non - positivo. + 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 + \procfile{/proc/sys/fs/epoll/max\_user\_instances}. \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel per creare l'istanza. \end{errlist} } -\end{prototype} +\end{functions} -La funzione restituisce 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; l'argomento \param{size} serve a dare -l'indicazione del numero di file descriptor che si vorranno tenere sotto -controllo, ma costituisce solo un suggerimento per semplificare l'allocazione -di risorse sufficienti, non un valore massimo. +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 tab.~\ref{tab:file_open_flags}), 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 @@ -1549,6 +1572,9 @@ controllare, per questo si deve usare la seconda funzione dell'interfaccia, \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 osservere imposto da + \procfile{/proc/sys/fs/epoll/max\_user\_watches}. \end{errlist} } \end{prototype} @@ -1597,8 +1623,10 @@ di tipo \struct{epoll\_event}, ed ha significato solo con le operazioni indicare quale tipo di evento relativo ad \param{fd} si vuole che sia tenuto sotto controllo. L'argomento viene ignorato con l'operazione \const{EPOLL\_CTL\_DEL}.\footnote{fino al kernel 2.6.9 era comunque richiesto - che questo fosse un puntatore valido, anche se poi veniva ignorato, a - partire dal 2.6.9 si può specificare anche un valore \texttt{NULL}.} + che questo fosse un puntatore valido, anche se poi veniva ignorato; a + partire dal 2.6.9 si può specificare anche un valore \texttt{NULL} ma se si + vuole mantenere la compatibilità con le versioni precedenti occorre usare un + puntatore valido.} \begin{figure}[!htb] \footnotesize \centering @@ -1624,7 +1652,8 @@ deve essere specificato come OR aritmetico delle costanti riportate in tab.~\ref{tab:epoll_events}. Il secondo campo, \var{data}, serve ad indicare a quale file descriptor si intende fare riferimento, ed in astratto può contenere un valore qualsiasi che permetta di identificarlo, di norma comunque -si usa come valore lo stesso \param{fd}. +si usa come valore lo stesso argomento \param{fd}, che ha un significato +immediato. \begin{table}[htb] \centering @@ -1641,7 +1670,8 @@ si usa come valore lo stesso \param{fd}. \const{EPOLLRDHUP} & L'altro capo di un socket di tipo \const{SOCK\_STREAM} (vedi sez.~\ref{sec:sock_type}) ha chiuso la connessione o il capo in scrittura - della stessa (vedi sez.~\ref{sec:TCP_shutdown}).\\ + della stessa (vedi + sez.~\ref{sec:TCP_shutdown}).\footnotemark\\ \const{EPOLLPRI} & Ci sono \itindex{out-of-band} dati urgenti disponibili in lettura (analogo di \const{POLLPRI}); questa condizione viene comunque @@ -1651,7 +1681,9 @@ si usa come valore lo stesso \param{fd}. (analogo di \const{POLLERR}); questa condizione viene comunque riportata in uscita, e non è necessaria impostarla in ingresso.\\ - \const{EPOLLHUP} & Si è verificata una condizione di hung-up.\\ + \const{EPOLLHUP} & Si è verificata una condizione di hung-up; questa + condizione viene comunque riportata in uscita, e non + è necessaria impostarla in ingresso.\\ \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 @@ -1663,7 +1695,12 @@ si usa come valore lo stesso \param{fd}. \label{tab:epoll_events} \end{table} -\footnotetext{questa modalità è disponibile solo a partire dal kernel 2.6.2.} +\footnotetext{questa modalità è disponibile solo a partire dal kernel 2.6.17, + 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.} Le modalità di utilizzo di \textit{epoll} prevedono che si definisca qual'è l'insieme dei file descriptor da tenere sotto controllo tramite un certo @@ -1781,9 +1818,10 @@ restituiti meno dati di quelli richiesti. Come già per \func{select} e \func{poll} anche per l'interfaccia di \textit{epoll} si pone il problema di gestire l'attesa di segnali e di dati -contemporaneamente, per far questo di nuovo è necessaria una variante della -funzione di attesa che consenta di reimpostare all'uscita una maschera di -segnali, analoga alle precedenti estensioni \func{pselect} e \func{ppoll} di +contemporaneamente per le osservazioni fatte in sez.~\ref{sec:file_select}, +per fare questo di nuovo è necessaria una variante della funzione di attesa +che consenta di reimpostare all'uscita una 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 introdotta a partire dal kernel 2.6.19, ed è come tutta l'interfaccia di \textit{epoll}, specifica di diff --git a/fileunix.tex b/fileunix.tex index fe6f46d..0bcc5fe 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -350,7 +350,8 @@ ritorno il file descriptor con il valore pi alle dimensioni dei blocchi del filesystem; per il kernel 2.6 basta che siano allineati a multipli di 512 byte.\\ - \const{O\_CLOEXEC} & Attiva la modalità di \textit{close-on-exec} (vedi + \const{O\_CLOEXEC} & Attiva la modalità di \itindex{close-on-exec} + \textit{close-on-exec} (vedi sez.~\ref{sec:file_sharing} e \ref{sec:file_fcntl}).\footnotemark\\ \hline @@ -1067,7 +1068,7 @@ sull'altro (dato che quello che viene modificato della \textit{file table} a cui entrambi fanno riferimento). L'unica differenza fra due file descriptor duplicati è che ciascuno avrà il suo \textit{file descriptor flag}; a questo proposito va specificato che nel caso -di \func{dup} il flag di \textit{close-on-exec}\itindex{close-on-exec} (vedi +di \func{dup} il flag di \textit{close-on-exec} \itindex{close-on-exec} (vedi sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre cancellato nella copia. diff --git a/ipc.tex b/ipc.tex index d22c3ba..91c6ff3 100644 --- a/ipc.tex +++ b/ipc.tex @@ -4449,10 +4449,10 @@ corrente. \label{fig:ipc_posix_sem_shm_message_server_handler} \end{figure} -Prima della stampa del messaggio invece si deve aquisire il semaforo +Prima della stampa del messaggio invece si deve acquisire il semaforo (\texttt{\small 31--34}) per evitare accessi concorrenti alla stringa da parte del programma di modifica. Una volta eseguita la stampa (\texttt{\small 41}) -il semforo 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. @@ -4461,7 +4461,7 @@ il break da tastiera (\texttt{C-c}), che corrisponde all'invio del segnale \const{SIGINT}, per il quale si è installato (\texttt{\small 10}) una opportuna funzione di gestione, riportata in fig.~\ref{fig:ipc_posix_sem_shm_message_server_handler}. La funzione è molto -semplice e richiame le funzioni di rimozione sia per il segmento di memoria +semplice e richiama le funzioni di rimozione sia per il segmento di memoria condivisa che per il semaforo, garantendo così che possa essere riaperto ex-novo senza errori in un futuro riutilizzo del comando. @@ -4510,9 +4510,9 @@ eseguite da \file{message\_getter}). Terminato il tempo di attesa si rilascer (\texttt{\small 29--32}) il semaforo per poi uscire. Per verificare il funzionamento dei programmi occorrerà lanciare per primo -\file{message\_getter}\footnote{lanciando per primo \file{message\_setter} - darà luogo ad un errore, non essendo stati creati il semaforo ed il segmento - di memoria condivisa.} che inizierà a stampare una volta al secondo il +\file{message\_getter}\footnote{lanciare per primo \file{message\_setter} darà + luogo ad un errore, non essendo stati creati il semaforo ed il segmento di + memoria condivisa.} che inizierà a stampare una volta al secondo il contenuto del messaggio ed i suoi dati, con qualcosa del tipo: \begin{Verbatim} piccardi@hain:~/gapil/sources$ ./message_getter messaggio @@ -4610,17 +4610,20 @@ testo alla terminazione di quest'ultimo. % LocalWords: SHARED ANONYMOUS thread patch names strace system call userid Di % LocalWords: groupid Michal Wronski Krzysztof Benedyczak wrona posix mqueue % LocalWords: lmqueue gcc mount mqd name oflag attr maxmsg msgsize receive ptr -% LocalWords: send WRONLY NONBLOCK close mqdes EBADF getattr setattr mqstat +% LocalWords: send WRONLY NONBLOCK close mqdes EBADF getattr setattr mqstat to % LocalWords: omqstat curmsgs flags timedsend len prio timespec abs EMSGSIZE % LocalWords: ETIMEDOUT timedreceive getaddr notify sigevent notification l'I % LocalWords: EBUSY sigev SIGNAL signo value sigval siginfo all'userid MESGQ % LocalWords: Konstantin Knizhnik futex tmpfs ramfs cache shared swap CONFIG % LocalWords: lrt blocks PAGECACHE TRUNC CLOEXEC mmap ftruncate munmap FindShm -% LocalWords: CreateShm RemoveShm LIBRARY Library libmqueue FAILED EACCESS +% LocalWords: CreateShm RemoveShm LIBRARY Library libmqueue FAILED EACCESS has % LocalWords: ENAMETOOLONG qualchenome RESTART trywait XOPEN SOURCE timedwait -% LocalWords: process getvalue sval execve pshared ENOSYS heap PAGE destroy +% LocalWords: process getvalue sval execve pshared ENOSYS heap PAGE destroy it % LocalWords: xffffffff Arrays owner perms Queues used bytes messages device -% LocalWords: Cannot find such Segments getter Signal MSGMAXSIZE +% LocalWords: Cannot find such Segments getter Signal MSGMAXSIZE been stable +% LocalWords: for now it's break Berlin sources Let's an accidental feature +% LocalWords: Larry Wall Escape the Hell William ipctestid Identifier segment +% LocalWords: violation dell'I SIGINT setter Fri Dec Sleeping seconds %%% Local Variables: diff --git a/sources/FifoReporter.c b/sources/FifoReporter.c new file mode 100644 index 0000000..631c56e --- /dev/null +++ b/sources/FifoReporter.c @@ -0,0 +1,140 @@ +/* FifoReporter.c + * + * Copyright (C) 2011 Simone Piccardi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/**************************************************************** + * + * Program reporterd + * FIFO, signal, event and alarm reporter + * an example program for I/O multiplexing with signalfd and Co. + * + * Author: Simone Piccardi + * Jan. 2011 + * + * Usage: reporterd -h give all info + * + ****************************************************************/ +/* + * Include needed headers + */ +#include /* primitive system data types */ +#include /* file characteristics constants and functions */ +#include /* unix standard library */ +#include /* standard I/O library */ +#include /* C standard library */ +#include /* C strings library */ +#include /* error definitions and routines */ +#include /* signal constants, types and functions */ +#include /* file control functions */ +#include /* Linux epoll interface */ + +#include "macros.h" +#include "Gapil.h" + +/* Subroutines declaration */ +void usage(void); + +/* default name for the input fifo */ +char *fifoname = "/tmp/reporter.fifo"; + +int main(int argc, char *argv[]) +{ +/* Variables definition */ + int i, t = 1; + char buffer[4096]; + int fifofd, epfd; + struct epoll_event epev; + int nread; + /* + * Input section: decode parameters passed in the calling + * Use getopt function + */ + opterr = 0; /* don't want writing to stderr */ + while ( (i = getopt(argc, argv, "ht:f:")) != -1) { + switch (i) { + /* + * Handling options + */ + case 'h': + printf("Wrong -h option use\n"); + usage(); + return(0); + break; + case 'f': + fifoname = optarg; + break; + case 't': + t = strtol(optarg, NULL, 10); + break; + case '?': /* unrecognized options */ + printf("Unrecognized options -%c\n",optopt); + usage(); + default: /* should not reached */ + usage(); + } + } + /* *********************************************************** + * + * Options processing completed + * + * Main code beginning + * + * ***********************************************************/ + /* + * Initial setup + */ + if (mkfifo(fifoname, 0622)) { // create well known fifo if does't exist + if (errno!=EEXIST) { + perror("Cannot create well known fifo"); + exit(1); + } + } + if ((fifo = open(fifoname, O_RDONLY)) < 0) { // open fifo + perror("Cannot open read only well known fifo"); + exit(1); + } + epfd = epoll_create(5); // initialize epoll + if (epfd < 0) { + perror("Failing on epoll_create"); + exit(1); + } + /* Main body: loop over requests */ + while (1) { + + } + debug("Exiting for unknown reasons\n"); +} +/* + * routine to print usage info and exit + */ +void usage(void) { + printf("Elementary fortune server\n"); + printf("Usage:\n"); + printf(" fortuned [-h] [-f] -n XXX \n"); + printf(" -h print this help\n"); + printf(" -t filename set fifo file\n"); + printf(" -n XXX set pool depth\n"); + exit(1); +} +/* + * Signal Handler to manage termination + */ +void HandSIGTERM(int signo) { + debug("Terminated by %s\n", strsignal(signo)); + unlink(fifoname); + exit(0); +} -- 2.30.2