From 511c7621872e959e05b79920b09c6e45590f1706 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Mon, 4 Apr 2011 10:02:30 +0000 Subject: [PATCH] Materiale scritto in treno --- fileadv.tex | 93 ++++++++++++++++++++++++++++++-------- prochand.tex | 5 +- sources/FifoReporter.c | 2 +- sources/test_timerfdfork.c | 63 ++++++++++++++++++++++++-- 4 files changed, 136 insertions(+), 27 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index b1cb348..312c36f 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -2114,16 +2114,16 @@ timer.\footnote{in realtà per questo sarebbe già sufficiente \func{signalfd} 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)} @@ -2180,18 +2180,71 @@ tab.~\ref{tab:timerfd_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 diff --git a/prochand.tex b/prochand.tex index 07af836..76b68e2 100644 --- a/prochand.tex +++ b/prochand.tex @@ -659,8 +659,9 @@ Le differenze fra padre e figlio dopo la \func{fork} invece sono:\footnote{a \item i \textit{lock} sui file (vedi sez.~\ref{sec:file_locking}) e sulla memoria (vedi sez.~\ref{sec:proc_mem_lock}), che non vengono ereditati dal figlio; -\item gli allarmi (vedi sez.~\ref{sec:sig_alarm_abort}) ed i segnali pendenti - (vedi sez.~\ref{sec:sig_gen_beha}), che per il figlio vengono cancellati. +\item gli allarmi, i timer (vedi sez.~\ref{sec:sig_alarm_abort}) ed i segnali + pendenti (vedi sez.~\ref{sec:sig_gen_beha}), che per il figlio vengono + cancellati. \item le operazioni di I/O asincrono in corso (vedi sez.~\ref{sec:file_asyncronous_io}) che non vengono ereditate dal figlio; \item gli aggiustamenti fatti dal padre ai semafori con \func{semop} (vedi diff --git a/sources/FifoReporter.c b/sources/FifoReporter.c index eecdb12..4e35cba 100644 --- a/sources/FifoReporter.c +++ b/sources/FifoReporter.c @@ -169,7 +169,7 @@ int main(int argc, char *argv[]) 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 */ + /* loop on epoll events */ for (i=0; i /* standard I/O library */ #include /* C strings library */ #include /* timerfd */ +#include /* Linux epoll interface */ // #include +#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 @@ -83,15 +93,53 @@ int main(int argc, char *argv[]) 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