semplifica notevolmente la gestione e consente di fare tutto con una sola
\textit{system call}.}
-Le funzioni di questa interfaccia ricalcano da vicino la struttura di quelle
-introdotte da POSIX.1-2001, che abbiamo illustrato in
-sez.~\ref{sec:sig_timer_adv}.\footnote{questa interfaccia è stata introdotta
- in forma considerata difettosa con il kernel 2.6.22, per cui è stata
- immediatamente tolta nel successivo 2.6.23 e 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 non è supportata e non deve essere usata.} La prima funzione
-prevista, che consente di creare un \textit{timer}, è \funcd{timerfd\_create},
-il cui prototipo è:
+Le funzioni di questa interfaccia ricalcano da vicino la struttura delle
+analoghe versioni ordinarie introdotte con lo standard POSIX.1-2001, che
+abbiamo già illustrato in sez.~\ref{sec:sig_timer_adv}.\footnote{questa
+ interfaccia è stata introdotta in forma considerata difettosa con il kernel
+ 2.6.22, per cui è stata immediatamente tolta nel successivo 2.6.23 e
+ 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 non è supportata e non deve essere
+ usata.} La prima funzione prevista, quella che consente di creare un
+\textit{timer}, è \funcd{timerfd\_create}, il cui prototipo è:
\begin{prototype}{sys/timerfd.h}
{int timerfd\_create(int clockid, int flags)}
\label{tab:timerfd_flags}
\end{table}
-In caso di successo la funzione restituisce un file descriptor che può essere
-usato per leggere le notifiche delle 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}
-(a meno che non si sia impostato il flag di \textit{close-on exex} con
-\const{TFD\_CLOEXEC}) e viene duplicato attraverso una \func{fork}, mantenendo
-il riferimento allo stesso \textit{timer}, così che anche il processo figlio
+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 exex} 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}.}
+
+Una volta creato il timer con \funcd{timerfd\_create} per poterlo utilizzare
+occorre \textsl{armarlo} impostandone un tempo di scadenza ed una eventuale
+periodicità di ripetizione, per farlo su usa la funzione omologa di
+\func{timer\_settime} per la nuova interfaccia; questa è
+\func{timerfd\_settime}; 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.
+
+ \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:
+ \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 inode associati al file
+ descriptor.
+ \end{errlist}
+ ed inoltre \errval{EMFILE} e \errval{ENFILE}.
+}
+\end{prototype}
+
+
+
+
+.\footnote{si otterranno in entrambi i casi gli stessi
+ risultati, il file descriptor risulterà pronto in lettura e in entrambi i
+ processi si potranno leggere il numero di scadenze.}
+
+
+
+
+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},
-per cui
-anche un processo figlio potrà ricevere informazioni sulla scadenza di un
-timer attraverso
% TODO trattare qui eventfd, timerfd introdotte con il 2.6.22
#include <stdio.h> /* standard I/O library */
#include <string.h> /* C strings library */
#include <sys/timerfd.h> /* timerfd */
+#include <sys/epoll.h> /* Linux epoll interface */
// #include <time.h>
+#include "macros.h"
+#include "Gapil.h"
+
/* Help printing routine */
void usage(void);
+void die(char *);
+
+#define MAX_EPOLL_EV 10
int main(int argc, char *argv[])
{
/*
* Variables definition
*/
- int i, fd;
+ int i, n, nread, fd, epfd;
+ pid_t pid;
+ struct epoll_event epev, events[MAX_EPOLL_EV];
struct itimerspec expiring;
+ uint64_t expirated;
/*
* Input section: decode command line parameters
* Use getopt function
printf("From %d arguments, removed %d options\n", argc, optind);
usage();
}
-
+ /* timerfd setup */
fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
expiring.it_interval.tv_sec=1;
expiring.it_interval.tv_nsec=0;
expiring.it_value.tv_sec=5;
expiring.it_value.tv_nsec=0;
- if (timerfd_settime(fd, 0, expiring, NULL)) {
- perror("Cannot set timer");
+ if (timerfd_settime(fd, 0, &expiring, NULL)) {
+ die("Cannot set timer");
}
+ pid = fork();
+ /* epoll setup */
+ if ((epfd=epoll_create(5)) < 0)
+ die("Failing on epoll_create");
+ epev.data.fd = fd;
+ epev.events = EPOLLIN;
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epev))
+ die("Failing in epoll_ctl");
+ /* main loop */
+ //while (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 epoll events */
+ for (i=0; i<n; i++) {
+ if (events[i].data.fd == fd) { // if timer expired
+ printf("Timer expired:\n");
+ while(nread=read(fd, &expirated, sizeof(expirated))) {
+ if (nread < 0) {
+ if (errno != EAGAIN)
+ die("signalfd read error");
+ else
+ break;
+ }
+ if (nread != sizeof(expirated)) {
+ printf("Error on timer data read, '\n");
+ continue;
+ }
+ printf("Expired %llu times\n", expirated);
+ if (pid == 0) {
+ printf("in child\n");
+ } else {
+ printf("in father\n");
+ }
+ }
+ }
+ }
+ // }
return 0;
}
/*
exit(1);
}
+/*
+ * Print error message and exit routine
+ */
+void die(char * mess) {
+ perror(mess);
+ exit(-1);
+}