timerfd periodik pada Linux dapat mengalami beberapa expiration sebelum event loop membacanya. read() berikutnya yang berhasil tidak mengembalikan satu record untuk setiap wakeup. Operasi itu mengembalikan satu uint64_t dalam byte order host yang berisi jumlah expiration yang terakumulasi sejak timer terakhir di-arm atau sejak read berhasil sebelumnya.
Count tersebut menjadikan readiness timerfd sebagai notifikasi bahwa status timer dapat dikonsumsi, bukan pemetaan satu-ke-satu antara wakeup scheduler dan periode timer.
Read mengonsumsi count expiration yang terakumulasi
timerfd yang dibuat dengan timerfd_create() merepresentasikan satu timer kernel melalui file descriptor. timerfd_settime() menetapkan expiration awal pada it_value dan, untuk timer periodik, it_interval yang bukan nol.
struct itimerspec spec = {
.it_value = { .tv_sec = 0, .tv_nsec = 100000000 },
.it_interval = { .tv_sec = 0, .tv_nsec = 100000000 },
};
int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
timerfd_settime(fd, 0, &spec, NULL);Jika empat periode 100 ms berakhir sebelum descriptor dibaca, read yang berhasil dapat mengembalikan integer 4. Aplikasi menerima sebuah count, bukan empat objek timer yang diantrekan secara terpisah.
uint64_t expirations;
ssize_t n = read(fd, &expirations, sizeof(expirations));
if (n == sizeof(expirations)) {
/* expirations may be greater than 1 */
}Buffer harus menyediakan sedikitnya delapan byte. Buffer yang lebih kecil menghasilkan EINVAL. Dengan TFD_NONBLOCK, read sebelum ada expiration yang tersedia gagal dengan EAGAIN.
Readiness tetap terkait dengan status expiration yang belum dibaca
poll(), select(), dan epoll melaporkan timerfd sebagai readable setelah satu atau lebih expiration terjadi. Kondisi readiness bertahan selama count expiration yang belum dibaca masih tersedia.
Read yang berhasil mengonsumsi count saat itu. Pada timer periodik, periode berikutnya mulai mengakumulasi count baru. Frekuensi dispatch event loop karena itu dapat berbeda dari frekuensi timer tanpa menghilangkan jumlah periode yang telah berlalu dan direpresentasikan oleh counter timerfd.
Sifat ini relevan saat proses tidak dijadwalkan, dihentikan sementara, atau sibuk dengan pekerjaan lain. Timer periodik 10 ms tidak berarti user space menerima satu callback setiap 10 ms. Jika eksekusi berlanjut setelah 70 ms, read dapat melaporkan beberapa expiration sekaligus.
Counter merepresentasikan periode, bukan work item yang tertunda
Nilai expiration mencatat periode timer yang telah berlalu. Nilai itu tidak menyatakan bahwa aplikasi memiliki work item independen untuk setiap count, dan tidak memaksa aplikasi mengulang suatu operasi sebanyak count tersebut.
Komponen sampling status dapat memperlakukan count positif sebagai pemicu untuk mengambil status terkini. Loop simulasi dapat memajukan waktu berdasarkan jumlah tick yang dilaporkan. Komponen rate control dapat memakai count untuk mendeteksi keterlambatan scheduling. Kebijakan tersebut milik aplikasi; timerfd menyediakan count expiration yang telah berlalu.
Batas ini mencegah kesalahan semantik berupa penyamaan jumlah wakeup event loop dengan jumlah timer yang telah berakhir. Satu wakeup dapat mengekspos beberapa expiration, dan scheduling dapat menggabungkan waktu observasi tanpa mengubah periode timer yang dikonfigurasi.
Rearming menetapkan konfigurasi timer baru
timerfd_settime() mengganti konfigurasi timer saat ini. it_value nol melakukan disarm. it_value bukan nol melakukan arm, sedangkan it_interval bukan nol menetapkan expiration periodik setelah event awal.
Mode relatif menafsirkan it_value dari nilai clock pada saat pemanggilan. TFD_TIMER_ABSTIME menafsirkannya sebagai nilai absolut pada clock yang dipilih.
timerfd_gettime() melaporkan sisa waktu sampai expiration berikutnya dan interval aktif. it_value yang dikembalikan selalu relatif, termasuk ketika timer di-arm memakai TFD_TIMER_ABSTIME.
Pilihan clock mengubah domain waktu
CLOCK_MONOTONIC melacak waktu berlalu secara monoton dan tidak terpengaruh perubahan wall clock yang diskontinu. CLOCK_REALTIME mengikuti wall clock sistem dan dapat bergeser ketika clock tersebut diubah secara eksplisit.
Untuk timer absolut CLOCK_REALTIME atau CLOCK_REALTIME_ALARM, TFD_TIMER_CANCEL_ON_SET dapat meminta pembatalan setelah perubahan real-time clock yang diskontinu. Read yang sedang berlangsung atau berikutnya kemudian gagal dengan ECANCELED. Perilaku ini terpisah dari akumulasi expiration biasa.
Pilihan clock dengan demikian menjadi bagian dari batas semantik timer. Count expiration menyatakan berapa banyak periode yang berlalu dalam domain clock terpilih; mekanisme tersebut tidak menyamakan clock yang berbeda.
Berbagi descriptor juga berbagi objek timer
Setelah fork(), descriptor yang diwariskan merujuk pada objek timer dasar yang sama. File descriptor hasil duplikasi juga merujuk pada open file description dan status timer yang sama. Read yang berhasil melalui salah satu referensi mengonsumsi count expiration terakumulasi yang terlihat melalui timer bersama tersebut.
Kondisi ini membuat beberapa reader saling bersaing, bukan menjadi subscriber. Count expiration tidak disalin untuk setiap descriptor atau proses yang dapat mengakses timerfd.
Saat seluruh descriptor yang terkait dengan objek timer ditutup, kernel melakukan disarm dan melepaskan resource timer. TFD_CLOEXEC mencegah descriptor yang baru dibuat bertahan melewati execve() yang berhasil.
Kontrak akhirnya tetap sempit: timerfd mengubah status expiration timer menjadi readiness file descriptor, sedangkan setiap read yang berhasil memindahkan count expiration terakumulasi dan mengosongkan status yang dapat dikonsumsi untuk interval observasi berikutnya.