%% fileadv.tex
%%
-%% Copyright (C) 2000-2010 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2011 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
\textit{edge triggered} nel caso del precedente esempio il file descriptor
diventato pronto da cui si sono letti solo 1000 byte non verrà nuovamente
notificato come pronto, nonostante siano ancora disponibili in lettura 1000
-byte. Solo una volta che si saranno esauriti tutti i byte disponibili, e che
+byte. Solo una volta che si saranno esauriti tutti i dati disponibili, e che
il file descriptor sia tornato non essere pronto, si potrà ricevere una
ulteriore notifica qualora ritornasse pronto.
Il primo campo, \var{events}, è una maschera binaria in cui ciascun bit
corrisponde o ad un tipo di evento, o una modalità di notifica; detto campo
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 argomento \param{fd}, che ha un significato
-immediato.
+tab.~\ref{tab:epoll_events}. Il secondo campo, \var{data}, è una \ctyp{union}
+che serve a identificare il file descriptor a cui si intende fare riferimento,
+ed in astratto può contenere un valore qualsiasi (specificabile in diverse
+forme) che ne permetta una indicazione univoca. Il modo più comune di usarlo
+però è quello in cui si specifica il terzo argomento di \func{epoll\_ctl}
+nella forma \var{event.data.fd}, assegnando come valore di questo campo lo
+stesso valore dell'argomento \param{fd}, cosa che permette una immediata
+identificazione del file descriptor.
\begin{table}[htb]
\centering
% http://lwn.net/Articles/245533/
% http://lwn.net/Articles/267331/
+\begin{figure}[!phtb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/FifoReporter.c}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione principale del codice del programma \file{FifoReporter.c}.}
+ \label{fig:fiforeporter_code}
+\end{figure}
+
\section{L'accesso \textsl{asincrono} ai file}
--- /dev/null
+...
+#include <sys/epoll.h> /* Linux epoll interface */
+#include <sys/signalfd.h>/* Linux signalfd interface */
+
+/* Subroutines declaration */
+void usage(void);
+void die(char *);
+
+/* default name for the input fifo */
+char *fifoname = "/tmp/reporter.fifo";
+
+#define MAX_EPOLL_EV 10
+
+int main(int argc, char *argv[])
+{
+/* Variables definition */
+ int i, n, nread, t = 10;
+ char buffer[4096];
+ int fifofd, epfd, sigfd;
+ sigset_t sigmask;
+ struct epoll_event epev, events[MAX_EPOLL_EV];
+ struct signalfd_siginfo siginf;
+ ...
+ /* Initial setup */
+ if ((epfd=epoll_create(5)) < 0) // epoll init
+ die("Failing on epoll_create");
+ /* Signal setup for signalfd and epoll use */
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGINT);
+ sigaddset(&sigmask, SIGQUIT);
+ sigaddset(&sigmask, SIGTERM);
+ if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) // block signals
+ die("Failing in sigprocmask");
+ if ((sigfd=signalfd(-1, &sigmask, SFD_NONBLOCK)) == -1) // take a signalfd
+ die("Failing in signalfd");
+ epev.data.fd = sigfd; // add fd to epoll
+ epev.events = EPOLLIN;
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &epev))
+ die("Failing in signal epoll_ctl");
+ /* Fifo setup for epoll use */
+ if (mkfifo(fifoname, 0622)) { // create well known fifo if does't exist
+ if (errno!=EEXIST)
+ die("Cannot create well known fifo");
+ }
+ if ((fifofd = open(fifoname, O_RDWR|O_NONBLOCK)) < 0) // open fifo
+ die("Cannot open read only well known fifo");
+ epev.data.fd = fifofd; // add fifofd to epoll
+ epev.events = EPOLLIN;
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, fifofd, &epev))
+ die("Failing in fifo epoll_ctl");
+ /* Main body: wait something to report */
+ ...
+}
#include <signal.h> /* signal constants, types and functions */
#include <fcntl.h> /* file control functions */
#include <sys/epoll.h> /* Linux epoll interface */
+#include <sys/signalfd.h>/* Linux signalfd interface */
#include "macros.h"
#include "Gapil.h"
/* Subroutines declaration */
void usage(void);
+void die(char *);
/* default name for the input fifo */
char *fifoname = "/tmp/reporter.fifo";
+#define MAX_EPOLL_EV 10
+
int main(int argc, char *argv[])
{
/* Variables definition */
- int i, nread, t = 1;
+ int i, n, nread, t = 10;
char buffer[4096];
int fifofd, epfd, sigfd;
- struct epoll_event epev;
sigset_t sigmask;
- char buffer[1024];
+ struct epoll_event epev, events[MAX_EPOLL_EV];
+ struct signalfd_siginfo siginf;
+ char *sig_names[] = { // signal name declaration from bits/signum.h
+ "------- ", /*0 Filler for signal names array */
+ "SIGHUP ", /*1 Hangup (POSIX). */
+ "SIGINT ", /*2 Interrupt (ANSI). */
+ "SIGQUIT ", /*3 Quit (POSIX). */
+ "SIGILL ", /*4 Illegal instruction (ANSI). */
+ "SIGTRAP ", /*5 Trace trap (POSIX). */
+ "SIGABRT ", /*6 Abort (ANSI). */
+ "SIGBUS ", /*7 BUS error (4.2 BSD). */
+ "SIGFPE ", /*8 Floating-point exception (ANSI). */
+ "SIGKILL ", /*9 Kill, unblockable (POSIX). */
+ "SIGUSR1 ", /*10 User-defined signal 1 (POSIX). */
+ "SIGSEGV ", /*11 Segmentation violation (ANSI). */
+ "SIGUSR2 ", /*12 User-defined signal 2 (POSIX). */
+ "SIGPIPE ", /*13 Broken pipe (POSIX). */
+ "SIGALRM ", /*14 Alarm clock (POSIX). */
+ "SIGTERM ", /*15 Termination (ANSI). */
+ "SIGSTKFLT ", /*16 Stack fault. */
+ "SIGCHLD ", /*17 Child status has changed (POSIX). */
+ "SIGCONT ", /*18 Continue (POSIX). */
+ "SIGSTOP ", /*19 Stop, unblockable (POSIX). */
+ "SIGTSTP ", /*20 Keyboard stop (POSIX). */
+ "SIGTTIN ", /*21 Background read from tty (POSIX). */
+ "SIGTTOU ", /*22 Background write to tty (POSIX). */
+ "SIGURG ", /*23 Urgent condition on socket (4.2 BSD). */
+ "SIGXCPU ", /*24 CPU limit exceeded (4.2 BSD). */
+ "SIGXFSZ ", /*25 File size limit exceeded (4.2 BSD). */
+ "SIGVTALRM ", /*26 Virtual alarm clock (4.2 BSD). */
+ "SIGPROF ", /*27 Profiling alarm clock (4.2 BSD). */
+ "SIGWINCH ", /*28 Window size change (4.3 BSD, Sun). */
+ "SIGIO ", /*29 I/O now possible (4.2 BSD). */
+ "SIGPWR ", /*30 Power failure restart (System V). */
+ "SIGSYS " /*31 Bad system call. */
+ };
/*
* Input section: decode parameters passed in the calling
* Use getopt function
/*
* 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);
- }
- }
- epfd = epoll_create(5); // initialize epoll
- if (epfd < 0) {
- perror("Failing on epoll_create");
- exit(1);
- }
- if ((fifofd = open(fifoname, O_RDONLY|O_NONBLOCK)) < 0) { // open fifo
- perror("Cannot open read only well known fifo");
- exit(1);
- }
- epev.data.fd = fifofd; /* add fifofd to epoll */
- epev.events = EPOLLIN;
- if (epoll_ctl(epfd, EPOLL_CTL_ADD, fifofd, &epev)) {
- perror("Failing in epoll_ctl");
- exit(-1);
- }
+ if ((epfd=epoll_create(5)) < 0) // epoll init
+ die("Failing on epoll_create");
+ /* Signal setup for signalfd and epoll use */
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGINT);
sigaddset(&sigmask, SIGQUIT);
sigaddset(&sigmask, SIGTERM);
- // blocking signal treated by signalfd to avoid default action
- if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) {
- perror("Failing in sigprocmask");
- exit(1);
- }
- if ((sigfd=signalfd(-1, &sigmask, SFD_NONBLOCK)) == -1) {
- perror("Failing in signalfd");
- exit(-1);
- }
- epev.data.fd = sigfd; /* add sigfd to epoll */
+ if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) // block signals
+ die("Failing in signalfd");
+ if ((sigfd=signalfd(-1, &sigmask, SFD_NONBLOCK)) == -1) // take a signalfd
+ die("Failing in signalfd");
+ epev.data.fd = sigfd; // add fd to epoll
epev.events = EPOLLIN;
- if (epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &epev)) {
- perror("Failing in epoll_ctl");
- exit(-1);
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &epev))
+ die("Failing in signal epoll_ctl");
+ /* Fifo setup for epoll use */
+ if (mkfifo(fifoname, 0622)) { // create well known fifo if does't exist
+ if (errno!=EEXIST)
+ die("Cannot create well known fifo");
}
-
- /* Main body: loop over requests */
+ if ((fifofd = open(fifoname, O_RDWR|O_NONBLOCK)) < 0) // open fifo
+ die("Cannot open read only well known fifo");
+ epev.data.fd = fifofd; // add fd to epoll
+ epev.events = EPOLLIN;
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, fifofd, &epev))
+ die("Failing in fifo epoll_ctl");
+ /*
+ * Main body: wait something to report
+ */
while (1) {
- if ((i = epoll_wait(epfd, &epev, 1, -1)) < 0) {
- perror("error on epoll_wait");
- exit(-1);
- }
- switch (epev.fd) {
- /*
- * Handling options
- */
- case sigfd:
- // signals
- break;
- case fifofd:
- // fifo
- break;
- default: /* should not reached */
- printf("something wrong, epoll activity on unknown %i file descriptor\n", epev.data.fd);
- exit(-1);
+ if ((n=epoll_wait(epfd, events, MAX_EPOLL_EV, -1)) < 0)
+ die("error on epoll_wait");
+ debug("Got %i events\n", n);
+ /* loop on eppol events */
+ for (i=0; i<n; i++) {
+ if (events[i].data.fd == sigfd) { // if signalfd ready
+ printf("Signal received:\n");
+ while(nread=read(sigfd, &siginf, sizeof(siginf))) {
+ if (nread < 0) {
+ if (errno != EAGAIN)
+ die("signalfd read error");
+ else
+ break;
+ }
+ if (nread != sizeof(siginf)) {
+ printf("Error on signal data read, '\n");
+ continue;
+ }
+ printf("Got %s\n", sig_names[siginf.ssi_signo]);
+ if(siginf.ssi_signo == SIGINT) { // SIGINT is exit
+ unlink(fifoname);
+ exit(0);
+ }
+ }
+ } else if (events[i].data.fd == fifofd) { // if fifofd ready
+ printf("Message from fifo:\n");
+ while ((nread = read(fifofd, buffer, 5000))) {
+ debug("read %i from fifofd %i, event %i\n",
+ nread, fifofd, events[i].data.fd );
+ if (nread < 0) {
+ if (errno != EAGAIN)
+ die("fifo read error");
+ else
+ printf("end message\n");
+ break;
+ }
+ buffer[nread] = 0;
+ if (fputs(buffer, stdout) == EOF)
+ die("Errore in scrittura su terminale");
+ }
+ } else { // anything else is an error
+ printf("epoll activity on unknown %i file descriptor\n",
+ epev.data.fd);
+ exit(-1);
+ }
}
-
}
debug("Exiting for unknown reasons\n");
}
* routine to print usage info and exit
*/
void usage(void) {
- printf("Elementary fortune server\n");
+ printf("Elementary event reporter\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(" reporterd [-h] [-f] -n XXX \n");
+ printf(" -h\t print this help\n");
+ printf(" -f\t filename set fifo file\n");
exit(1);
}
/*
- * Signal Handler to manage termination
+ * Print error message and exit routine
*/
-void HandSIGTERM(int signo) {
- debug("Terminated by %s\n", strsignal(signo));
- unlink(fifoname);
- exit(0);
+void die(char * mess) {
+ perror(mess);
+ exit(-1);
}