Linux timerfd periodik dapat mengalami beberapa expiration sebelum event loop kembali berjalan. read() berhasil berikutnya tidak sekadar melaporkan bahwa timer telah aktif; operasi itu mengembalikan hitungan unsigned 64-bit untuk expiration yang terakumulasi sejak read berhasil sebelumnya atau sejak timer terakhir dikonfigurasi. Dispatch yang tertunda dengan demikian terlihat sebagai hitungan, bukan rangkaian record timer yang diantrekan.
Kontrak tersebut memisahkan jadwal timer dari eksekusi consumer. Sebuah proses dapat kehilangan jatah CPU untuk sementara, event loop dapat menghabiskan waktu pada descriptor lain, atau beberapa periode dapat berlalu sebelum timerfd dikonsumsi. Kernel melacak expiration, sedangkan kode aplikasi menentukan arti beberapa expiration bagi pekerjaan yang terkait dengannya.
Readiness merepresentasikan status expiration yang pending
timerfd_create() membuat objek timer yang diekspos melalui file descriptor. Clock yang dipilih menentukan domain waktu timer. Pilihan umum mencakup CLOCK_MONOTONIC untuk penjadwalan berbasis durasi dan CLOCK_REALTIME untuk jadwal yang terikat pada wall clock yang dapat diubah.
timerfd_settime() mengaktifkan atau menonaktifkan timer. it_value nonzero menetapkan expiration pertama. it_interval nonzero membuat expiration berikutnya periodik; interval nol menghasilkan timer one-shot.
Setelah satu atau beberapa expiration pending, descriptor menjadi readable melalui interface seperti poll(), select(), dan epoll. Readiness tetap terkait dengan status timer yang pending sampai read berhasil mengonsumsi hitungan terakumulasi.
int fd = timerfd_create(CLOCK_MONOTONIC,
TFD_NONBLOCK | TFD_CLOEXEC);
struct itimerspec spec = {
.it_value = { .tv_sec = 1, .tv_nsec = 0 },
.it_interval = { .tv_sec = 1, .tv_nsec = 0 },
};
timerfd_settime(fd, 0, &spec, NULL);Contoh ini meminta expiration pertama setelah satu detik dan interval satu detik setelahnya. Konfigurasi tersebut tidak menjamin kode user space berjalan tepat pada setiap batas waktu. Expiration timer dan penjadwalan proses adalah peristiwa terpisah.
Read mengembalikan expiration yang terakumulasi
Read timerfd memakai buffer delapan byte dan mengembalikan uint64_t dalam host byte order. Jika lima expiration terjadi sebelum read, nilai yang dikembalikan dapat berupa lima. Read tersebut mengonsumsi hitungan expiration yang pending.
uint64_t expirations;
ssize_t n = read(fd, &expirations, sizeof(expirations));Jika tidak ada expiration pending, descriptor blocking menunggu expiration berikutnya. Descriptor yang dibuat dengan TFD_NONBLOCK sebaliknya gagal dengan EAGAIN. Buffer yang lebih kecil dari delapan byte menghasilkan EINVAL.
Hitungan ini penting untuk pekerjaan periodik. Memperlakukan setiap notifikasi readiness sebagai tepat satu periode yang berlalu dapat menghilangkan informasi jadwal ketika consumer tertinggal. Sebaliknya, menjalankan operasi terkait sekali untuk setiap expiration yang dikembalikan merupakan kebijakan aplikasi, bukan persyaratan timerfd. Sebagian sistem dapat menggabungkan pekerjaan yang terlambat menjadi satu refresh state; sistem lain mungkin perlu memajukan counter logis sebesar nilai yang dikembalikan.
timerfd mempertahankan hitungan expiration, bukan riwayat eksekusi. Interface ini tidak merekam timestamp untuk setiap periode yang terlewat, durasi keterlambatan consumer, atau penyebab keterlambatan tersebut.
Arming relatif dan absolut menetapkan batas yang berbeda
Tanpa TFD_TIMER_ABSTIME, it_value ditafsirkan relatif terhadap clock yang dipilih pada saat timerfd_settime() dipanggil. Mengaktifkan ulang timer relatif karena itu menetapkan deadline baru dari nilai clock saat call berlangsung.
Dengan TFD_TIMER_ABSTIME, it_value merupakan nilai absolut dalam domain clock yang dipilih. Perbedaan ini penting ketika jadwal harus tetap tertambat pada posisi clock, bukan pada waktu selesainya pekerjaan sebelumnya.
Untuk timer periodik, interval terus menentukan titik expiration berikutnya setelah expiration awal. Read yang terlambat tidak menggeser batas periodik yang sudah dikonfigurasi hanya karena user space terlambat mengonsumsi hitungannya.
Perbedaan tersebut memengaruhi model drift. Kode yang berulang kali menjalankan pekerjaan lalu mengaktifkan timer one-shot relatif baru memasukkan durasi pekerjaan dan keterlambatan dispatch ke deadline berikutnya. Timer periodik atau deadline absolut yang dihitung secara eksplisit dapat menjaga batas expiration tetap terikat pada jadwal terpisah. Keduanya tidak menjamin eksekusi user space segera setelah expiration.
Pemilihan clock menentukan paparan terhadap perubahan waktu
CLOCK_MONOTONIC tidak dapat diubah dan tidak meloncat ketika wall clock sistem diubah secara administratif. Clock ini sesuai untuk banyak deadline berbasis durasi. CLOCK_REALTIME merepresentasikan wall-clock time dan dapat berubah secara diskontinu.
Timer absolut berbasis CLOCK_REALTIME mengikuti nilai clock tersebut. Memindahkan real-time clock akibatnya dapat mengubah saat deadline absolut tercapai. Ini adalah properti domain clock, bukan artefak event loop.
Linux menyediakan TFD_TIMER_CANCEL_ON_SET untuk kontrak yang lebih sempit. Ketika digunakan bersama TFD_TIMER_ABSTIME pada CLOCK_REALTIME atau CLOCK_REALTIME_ALARM, perubahan diskontinu pada real-time clock menandai timer sehingga read saat ini atau berikutnya dapat gagal dengan ECANCELED.
Kegagalan tersebut mengekspos diskontinuitas clock alih-alih menyajikan peristiwa itu sebagai hitungan expiration biasa. Aplikasi yang memakai deadline civil-time kemudian dapat memperlakukan perubahan clock administratif sebagai transisi state terpisah.
Hitungan expiration bukan kapasitas backlog
Hitungan timerfd dapat menunjukkan bahwa batas periodik berlalu ketika consumer tertunda, tetapi hitungan itu tidak membuat penyimpanan bagi pekerjaan yang terkait dengan batas tersebut. Jika setiap periode berkaitan dengan sample eksternal, network request, atau transisi state, timerfd tidak menyimpan payload tersebut.
Misalnya, timer satu detik mengembalikan hitungan expiration enam setelah event loop terhenti sementara. Kernel telah melaporkan enam expiration timer. Kernel tidak merekonstruksi enam snapshot state aplikasi pada saat-saat tersebut. Pemetaan expiration ke pekerjaan domain bergantung pada state yang dipertahankan di tempat lain.
Batas ini mencegah penyamaan dua konsep berbeda: counter expiration adalah pembukuan temporal, bukan task queue yang durable. Queue dapat mempertahankan payload per item dan ordering sesuai kontraknya sendiri; timerfd mempertahankan hitungan yang terkait dengan expiration timer.
Descriptor bersama juga berbagi konsumsi
Setelah fork(), descriptor yang diwariskan merujuk ke objek timer yang sama. File descriptor hasil duplikasi juga merujuk ke state timer bersama. Read berhasil melalui satu referensi mengonsumsi hitungan expiration terakumulasi yang terlihat melalui referensi lainnya.
Beberapa reader karena itu bersaing, bukan berlangganan secara independen. Jika dua event loop memantau referensi duplikat ke satu timerfd, keduanya tidak masing-masing menerima salinan setiap hitungan expiration.
Objek tetap aktif selama referensi masih terbuka. Ketika semua file descriptor yang merujuk ke objek timer ditutup, kernel menonaktifkan timer dan melepaskan resource-nya. TFD_CLOEXEC mencegah retensi descriptor secara tidak sengaja melewati execve() yang berhasil ketika batas tersebut diinginkan.
State timer masuk ke event loop tanpa menjadi message stream
timerfd menempatkan readiness berbasis waktu bersama socket, pipe, eventfd, signalfd, dan descriptor pollable lain. Bentuk ini menghilangkan kebutuhan menerjemahkan timer menjadi signal asinkron hanya untuk membangunkan event loop yang berorientasi descriptor.
Integrasi tersebut tidak mengubah waktu menjadi record. Readiness menyatakan bahwa expiration sedang pending, dan read() menukar state pending itu dengan hitungan agregat. Consumer yang lambat dapat melihat bahwa beberapa periode telah berlalu, tetapi tetap harus menerapkan aturan catch-up yang sesuai dengan domain aplikasi.
Batas semantik yang sempit itulah properti utamanya: konfigurasi timer menetapkan titik expiration dalam domain clock yang dipilih, readiness file descriptor mengekspos status expiration yang pending, dan read delapan byte melaporkan expiration terakumulasi tanpa mengklaim bahwa pekerjaan user space berjalan pada waktu-waktu tersebut.