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
\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}
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
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
\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
(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
\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
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
\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.
\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.
(\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
% 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:
--- /dev/null
+/* 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 <sys/types.h> /* primitive system data types */
+#include <sys/stat.h> /* file characteristics constants and functions */
+#include <unistd.h> /* unix standard library */
+#include <stdio.h> /* standard I/O library */
+#include <stdlib.h> /* C standard library */
+#include <string.h> /* C strings library */
+#include <errno.h> /* error definitions and routines */
+#include <signal.h> /* signal constants, types and functions */
+#include <fcntl.h> /* file control functions */
+#include <sys/epoll.h> /* 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);
+}