Sistemato programma FifoReporter.c
authorSimone Piccardi <piccardi@gnulinux.it>
Thu, 20 Jan 2011 22:55:25 +0000 (22:55 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Thu, 20 Jan 2011 22:55:25 +0000 (22:55 +0000)
fileadv.tex
listati/FifoReporter-init.c [new file with mode: 0644]
listati/FifoReporter-main.c [new file with mode: 0644]
sources/FifoReporter.c

index fdf294698312d9d9f307039e954d642d88b27569..ba81956bd189bb94ead8b7aa6bb4e5bd88d62106 100644 (file)
@@ -1,6 +1,6 @@
 %% 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",
@@ -1474,7 +1474,7 @@ vengano notificati solo i file descriptor che hanno subito una transizione da
 \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.
 
@@ -1649,11 +1649,14 @@ definizione 
 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
@@ -2013,6 +2016,16 @@ di dimensione maggiore potranno essere letti in unica soluzione
 %       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}
diff --git a/listati/FifoReporter-init.c b/listati/FifoReporter-init.c
new file mode 100644 (file)
index 0000000..e46342a
--- /dev/null
@@ -0,0 +1,53 @@
+...
+#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 */
+    ...
+}
diff --git a/listati/FifoReporter-main.c b/listati/FifoReporter-main.c
new file mode 100644 (file)
index 0000000..dcf3901
--- /dev/null
@@ -0,0 +1,45 @@
+    /* Main body: wait something to report */
+    while (1) {
+        if ((n=epoll_wait(epfd, events, MAX_EPOLL_EV, -1)) < 0) 
+           die("error on epoll_wait");
+       for (i=0; i<n; i++) {    // loop on ready file descriptors             
+           if (events[i].data.fd == sigfd) {  // look 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 stop program
+                       unlink(fifoname);
+                       exit(0);
+                   }
+               }
+           } else if (events[i].data.fd == fifofd) { // look if fifofd ready 
+               printf("Message from fifo:\n");
+               while ((nread = read(fifofd, buffer, 5000))) {
+                   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);
+           }
+       }
+    }
index 5062e84c63143823c18c3cb774dc5c9454b98a4a..49b328aafe3489a267f75f2ffc85d79ead98a713 100644 (file)
 #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
@@ -98,68 +136,82 @@ int main(int argc, char *argv[])
     /* 
      * 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");
 }
@@ -167,18 +219,17 @@ int main(int argc, char *argv[])
  * 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);
 }