Objek eventfd menggabungkan counter unsigned 64-bit yang dikelola kernel dengan readiness file descriptor. Sebuah write menambahkan nilai ke counter ketika penambahan itu diizinkan; sebuah read mengonsumsi state counter. Karena objek yang sama dapat dipakai oleh poll(), select(), dan epoll(), transisi counter juga dapat menjadi notifikasi event loop tanpa byte stream atau lapisan framing pesan.
Antarmuka ringkas ini memiliki semantik yang tegas. Read default menguras nilai saat ini menjadi nol, read dengan EFD_SEMAPHORE mengonsumsi satu unit, write dapat blocking saat counter mendekati batas, dan readiness menunjukkan operasi yang dapat berjalan, bukan jumlah event logis yang dipetakan aplikasi ke counter.
State yang disimpan adalah counter, bukan antrean byte
eventfd() membuat objek dengan state awal dari nilai unsigned int yang diberikan. Read dan write memakai antarmuka integer delapan byte: transfer yang berhasil berukuran tepat sizeof(uint64_t). Buffer dengan ukuran lain tidak mengubah objek ini menjadi stream dengan partial transfer.
Write normal menafsirkan delapan byte sebagai integer unsigned 64-bit lalu menambahkan nilai tersebut ke counter saat ini. Nilai UINT64_MAX tidak diterima sebagai nilai input. Counter dibatasi sehingga write userspace biasa tidak dapat menaikkannya melewati UINT64_MAX - 1.
uint64_t increment = 3;
ssize_t n = write(efd, &increment, sizeof(increment));Semantik penambahan ini berbeda dari pipe. Tiga write tidak membuat tiga record yang dapat dialamatkan secara terpisah. Ketiganya menyumbang state numerik. Jika nilai 2, 3, dan 5 diterima sebelum read default, read tersebut dapat mengembalikan 10.
Perbedaan ini penting ketika aplikasi memetakan unit counter ke pekerjaan. eventfd mempertahankan akumulasi aritmetika, bukan batas antar-producer.
Read default menukar state terakumulasi menjadi nol
Tanpa EFD_SEMAPHORE, read yang berhasil mengembalikan nilai counter nonzero saat ini dan mereset counter menjadi nol sebagai satu operasi konsumsi.
uint64_t value;
ssize_t n = read(efd, &value, sizeof(value));Jika producer menambahkan pekerjaan ketika consumer aktif, nilai dari sebuah read mencerminkan state counter pada titik sinkronisasi operasi tersebut. Increment yang terjadi setelahnya tetap tersedia bagi read berikutnya, bukan diam-diam masuk ke nilai yang sudah dikonsumsi.
Mode default cocok untuk coalescing notifikasi. Beberapa producer dapat memberi signal ke consumer yang sama, lalu consumer menerima satu nilai terakumulasi alih-alih satu objek kernel per notifikasi. Aplikasi tetap harus menentukan arti nilai numerik tersebut. Nilai 7 yang dikembalikan hanya berarti tujuh unit pekerjaan jika setiap producer mengikuti kontrak itu.
Dengan EFD_NONBLOCK, read saat counter bernilai nol gagal dengan EAGAIN. Tanpa mode nonblocking, read menunggu sampai counter menjadi nonzero.
Mode semaphore mengubah konsumsi, bukan produksi
Pembuatan objek dengan EFD_SEMAPHORE mengubah read yang berhasil. Setiap read mengembalikan 1 dan mengurangi counter sebesar 1. Write tetap memiliki perilaku aditif.
Mode ini membuat counter bertindak seperti counting gate pada batas read:
counter = 3
read -> 1, counter = 2
read -> 1, counter = 1
read -> 1, counter = 0Kernel tetap tidak menyimpan identitas write individual. Satu write bernilai 3 dan tiga write bernilai 1 dapat menghasilkan urutan read semaphore yang sama. Jika identitas producer, urutan payload, atau metadata per pesan diperlukan, queue atau mekanisme IPC lain dibutuhkan.
EFD_SEMAPHORE mengubah granularitas konsumsi tanpa mengubah objek menjadi channel record.
Readability dan writability mengekspos batas counter
Descriptor eventfd bersifat readable ketika counter lebih besar dari nol. Descriptor bersifat writable ketika setidaknya nilai 1 dapat ditambahkan tanpa melewati nilai counter maksimum yang diizinkan bagi write biasa.
State readiness tersebut menggambarkan kelayakan operasi. Readability tidak melaporkan nilai counter secara tepat. Event loop yang menerima notifikasi readable harus melakukan read untuk mengonsumsi state dan memperoleh nilai sesuai mode yang dipilih.
Writability memiliki batas serupa. Indikasi writable berarti suatu penambahan valid dapat berjalan; itu tidak menjamin setiap increment 64-bit yang diajukan akan muat. Write bernilai besar masih dapat blocking atau gagal dengan EAGAIN pada mode nonblocking jika penambahan nilai spesifik tersebut melewati batas.
Pemisahan ini juga muncul pada banyak API readiness: readiness adalah predikat atas I/O yang mungkin dilakukan, bukan reservasi untuk operasi arbitrer di masa berikutnya.
Saturasi menghasilkan backpressure pada batas write
Jika penambahan akan membuat counter melewati UINT64_MAX - 1, write blocking menunggu sampai read menurunkan counter. Dengan EFD_NONBLOCK, kondisi yang sama menghasilkan EAGAIN.
Untuk signaling userspace normal, aturan ini memberi counter kapasitas terbatas meski batasnya sangat besar. Kode tidak dapat memperlakukan write sebagai increment yang tidak terbatas secara matematis.
Linux juga mendokumentasikan state overflow khusus ketika subsistem kernel memberi signal ke counter eventfd cukup banyak hingga counter 64-bit overflow. Dalam kondisi tersebut, poll() melaporkan status readable sekaligus error, dan read mengembalikan UINT64_MAX. Pemanggilan write() userspace biasa tidak dapat menciptakan overflow tersebut karena penambahan yang melewati batas userspace akan diblokir atau ditolak.
Perbedaan itu merupakan perilaku Linux pada tingkat implementasi, bukan properti generik counter yang diekspos sistem operasi lain.
Lifetime file descriptor memungkinkan jalur notifikasi bersama
Objek eventfd mengikuti aturan lifetime file descriptor Linux. Descriptor hasil duplikasi mengacu pada objek dasar yang sama, dan descriptor yang diwariskan melalui fork() juga mengacu pada objek tersebut. Counter dibagi melalui referensi itu, bukan disalin menjadi counter independen.
EFD_CLOEXEC dapat mencegah descriptor yang tidak diinginkan bertahan melewati execve(). EFD_NONBLOCK menetapkan status nonblocking pada open file description dasar yang dipakai descriptor.
Descriptor juga dapat dikirim melalui UNIX domain socket. Hal ini memungkinkan process yang diatur secara terpisah berbagi objek counter yang sama setelah transfer descriptor. Kontrak sinkronisasinya tetap numerik: berbagi descriptor tidak menambahkan kepemilikan pesan atau identitas producer.
Kernel melepaskan objek setelah semua file descriptor yang mengacunya ditutup. Pekerjaan tingkat aplikasi yang direpresentasikan counter tidak memiliki kontrak persistensi terpisah; penutupan descriptor terakhir menghilangkan akses ke objek kernel tersebut.
Event loop memerlukan kebijakan drain yang sesuai mode
Dengan epoll level-triggered, eventfd mode default tetap readable sampai sebuah read menguras counter nonzero. Pada mode semaphore, descriptor tetap readable selama setidaknya satu unit tersisa, sehingga consumer mungkin memerlukan read berulang untuk mengonsumsi semua unit yang tersedia saat itu.
Dengan notifikasi edge-triggered, consumer biasanya menggabungkan I/O nonblocking dengan drain loop sampai EAGAIN. Berhenti ketika state counter masih dapat dikonsumsi dapat membuat descriptor tetap readable tanpa transisi readiness baru yang segera memicu pekerjaan.
Bentuk loop yang diperlukan mengikuti semantik konsumsi yang dipilih. Mode default sering selesai dalam satu read berhasil karena read itu mereset counter menjadi nol. Mode semaphore dapat memerlukan banyak read karena setiap pemanggilan berhasil menghapus tepat satu unit.
Perilaku ini juga membatasi arti sebuah notifikasi event. Menerima satu event epoll tidak berarti satu aksi producer, dan tidak adanya edge baru tidak membuktikan counter bernilai nol jika consumer sebelumnya berhenti sebelum drain selesai.
Kontrak utamanya adalah sinkronisasi numerik
eventfd paling tepat ketika program memerlukan objek sinkronisasi kernel kecil yang dapat di-increment sekaligus terlihat oleh mekanisme waiting berbasis descriptor. Objek ini dapat menghubungkan notifikasi worker, penghitungan completion, atau jalur wakeup ke event loop tanpa parsing stream.
Batasnya berasal dari bentuk yang ringkas itu. Kernel menyimpan angka, bukan riwayat. Mode default menggabungkan unit terakumulasi ke satu read; mode semaphore membagikan unit tersebut satu per satu; readiness mengekspos state operasi, bukan jumlah pesan. Desain yang mempertahankan batas ini dapat memakai eventfd sebagai kontrak sinkronisasi numerik yang presisi, bukan sebagai message queue berukuran mini.