Alcuni dettagli di timerfd.

A partire dal kernel 2.6.25 è stata introdotta una interfaccia di gestione alternativa per i timer di sistema che consente la ricezione delle notifiche di scadenza attraverso dei file descriptor invece che tramite segnali o thread, chiamata convenzionalmente timerfd.

L’interfaccia è specifica di Linux e si unisce ad altre due (signalfd e eventfd) che seguono la stessa filosofia per la ricezione di segnali e di eventi dal kernel. Il grande vantaggio è che queste possono essere usate in combinazione con le funzioni dell’I/O multiplexing (poll, select ed epoll) semplificando notevolmente la gestione l’attesa contemporanea di eventi e dati.

L’interfaccia timerfd segue da vicino quella introdotta da POSIX.1-2001 che è trattata nella sezione 9.5.2 della guida, che però fa ricorso a meccanismi di notifica classici. Nel trattare la nuova interfaccia mi è sorto un dubbio relativo al funzionamento della stessa quando si esegue una fork.

Con i timer ordinari infatti un processo figlio non eredita dopo una fork nessuno dei timer del padre. La semantica Unix prevede però che un file descriptor sia duplicato attraverso una fork, e dato che in questo caso un timer viene associato ad un file descriptor la domanda su cosa accada al timer nel processo figlio sorge spontanea.

La documentazione dice che il file descriptor associato ad un timer continua a seguire la semantica ordinaria e viene duplicato nel figlio. Viene cioè preferita la semantica dei file descriptor rispetto a quella dei timer ordinari. Sorge però spontanea la domanda di cosa succede se padre e figlio iniziano a leggere entrambi da tale file descriptor per ricevere la notifica delle scadenze dei timer.

La documentazione delle pagine di manuale, almeno nella versione della mia Debian, non dice nulla, ma “a naso” ci si aspetterebbe che accada la stessa cosa che accade per un file descriptor duplicato, e cioè che chi legge per primo riceve i dati, lasciando “a bocca asciutta” l’altro processo.

Per verificarlo ho comunque scritto un programma di test, test_timerfdfork.c, che arma un timer con timerfd esegue una fork ed usa epoll per l’attesa in entrambi i processi. Il programma prevede delle opzioni per specificare i valori della struttura itimerspec che impostano prima scadenza e ripetizione del timer.

Se lo eseguiamo mettendo un tempo di prima scadenza a due secondi, ed un tempo di ripetizione ad un secondo, otterremo qualcosa del tipo:

piccardi@hain:~/gapil/sources$ gcc test_timerfdfork.c
piccardi@hain:~/gapil/sources$ ./a.out -i1 -t2
Timer interval 2 sec, timer time 1 sec
Got 1 events, pid 12513, time 1308661930
Timer expired in pid 12513:
Expired 1 times in pid 12513
Got 1 events, pid 0, time 1308661930
Timer expired in pid 0:
Got 1 events, pid 0, time 1308661931
Timer expired in pid 0:
Expired 1 times in pid 0
Got 1 events, pid 0, time 1308661932
Timer expired in pid 0:
Expired 1 times in pid 0
Got 1 events, pid 0, time 1308661933
Timer expired in pid 0:
Expired 1 times in pid 0

e come ci si aspettava viene letta una scadenza alla volta, nel caso la prima volta nel figlio e le successive nel padre (ma la cosa è casuale e rilanciandolo di possono ottenere diversi risultati), cosa che corrisponde al fatto che il primo processo che esegue una lettura sul file descriptor riceve il dato della scadenza.

Il progetto

GaPiL nasce dalla mia convinzione profonda che la “filosofia” che ispira il software libero si applichi anche ad altri campi che non siano necessariamente quelli della scrittura di programmi per computer. In particolare ritengo che possa assumere una grande rilevanza in ambiti come quelli dell’educazione e della formazione.

Ma se trovare della buona documentazione libera, specie per quanto riguarda i programmi che girano sul sistema GNU/Linux, è ormai relativamente facile, la produzione di buoni testi didattici che insegnino a programmare in questo sistema è ancora molto limitata, soprattutto se li si cercano in lingua italiana.

GaPiL è un tentativo di scrivere un manuale di programmazione di sistema in ambiente di tipo Unix, con una particolare attenzione alle caratteristiche specifiche delle interfacce fornite dal kernel Linux. Per questo motivo si parla di Linux e non di GNU/Linux.

Nonostante questa specificità, essendo la gran parte delle funzioni di sistema standardizzate, la guida dovrebbe risultare utile anche facendo riferimenti ad altri sistemi di tipo Unix come i vari *BSD; in ogni caso si sono sottolineate esplicitamente le caratteristiche specifiche di Linux.

Benché buona parte della trattazione delle funzioni di libreria sia del tutto identica, facendo riferimento a standard generali come POSIX, si è comunque prestata particolare attenzione alle funzioni delle GNU libc, che sono la versione più usata delle librerie del C, senza dimenticare, ove note, di citare le differenze con possibili alternative come le libc5 o le uclibc.

L’obiettivo resta comunque quello di riuscire a produrre un testo, rilasciato sotto GNU FDL, che possa servire a chi si accosta per la prima volta alla programmazione avanzata e di sistema su un kernel Linux, con la speranza di poter un giorno raggiungere la qualità dei lavori del compianto R. W. Stevens.

This work by Simone Piccardi is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported.