Linux eventfd mengekspos counter 64-bit yang dikelola kernel melalui file descriptor. Interface yang ringkas ini memiliki pilihan semantik penting: read normal menguras nilai counter saat itu, sedangkan read dengan EFD_SEMAPHORE hanya mengambil satu unit. Jalur write tetap menambahkan nilai ke counter yang sama.
Perbedaan tersebut mengubah objek dari counter notifikasi agregat menjadi sumber unit yang dapat dikonsumsi satu per satu melalui descriptor. Model readiness tetap dapat dipakai bersama poll, epoll, dan mekanisme multiplexing descriptor lain, sehingga satu objek dapat menghubungkan accounting producer dengan event loop tanpa payload pipe terpisah.
Counter adalah state bersama di balik descriptor
Objek eventfd menyimpan unsigned counter 64-bit yang dikelola kernel. eventfd(initval, flags) membuat objek dan mengembalikan descriptor yang merujuk padanya. Write yang sukses memasok integer delapan byte dan menambahkan nilainya ke counter, dengan tetap mengikuti batas counter pada interface.
Secara konseptual:
counter = 2
write(fd, 3)
counter = 5Descriptor ini bukan byte stream. Read yang sukses mentransfer satu integer delapan byte, sedangkan buffer yang lebih kecil dari delapan byte ditolak. Integer memakai byte order host.
Protocol fixed-width ini penting karena readiness dan accounting merujuk pada counter, bukan pada record write yang diantrikan. Dua write bernilai 2 dan 3 menghasilkan state counter yang sama dengan satu write bernilai 5 sebelum reader mengonsumsi nilainya.
Read normal menguras akumulasi
Tanpa EFD_SEMAPHORE, read yang sukses mengembalikan nilai counter nonzero saat itu lalu meresetnya menjadi nol.
counter = 5
read -> 5
counter = 0Mode ini cocok untuk coalescing notifikasi. Beberapa producer dapat menaikkan counter, lalu satu consumer bangun dan mengambil jumlah yang terakumulasi dalam satu operasi. Nilai yang dikembalikan dapat merepresentasikan jumlah action, completion, atau unit lain sesuai kontrak aplikasi.
Kernel tidak mempertahankan batas antar-producer di dalam nilai tersebut. Jika consumer memerlukan message terpisah, metadata ordering, atau payload dengan ukuran bervariasi, eventfd saja tidak menyediakan properti itu.
EFD_SEMAPHORE hanya mengubah konsumsi pada read
Membuat objek dengan EFD_SEMAPHORE mengubah hasil read yang sukses. Saat counter nonzero, read mengembalikan 1 dan mengurangi counter satu unit.
counter = 5
read -> 1
counter = 4
read -> 1
counter = 3Write tetap menambahkan nilai yang diberikan. Producer dapat mempublikasikan beberapa unit dengan satu write, sementara consumer mengambil unit tersebut satu per satu.
Flag ini tidak mengubah objek menjadi POSIX semaphore atau mutex umum. Ia memberi eventfd semantik read yang menyerupai semaphore di atas counter. Tidak ada konsep ownership yang melekat pada satu unit, dan interface ini tidak membawa protected data bersama decrement.
Nilai nol menentukan blocking dan readiness
Read dapat berjalan saat counter nonzero. Jika counter nol, descriptor blocking menunggu sampai counter menjadi nonzero. Dengan EFD_NONBLOCK, kondisi yang sama membuat read() gagal dengan EAGAIN.
Batas readiness menjadi langsung:
counter == 0 -> tidak ada unit tersedia
counter > 0 -> readablePada mode normal, satu reader dapat menguras counter terakumulasi dan segera membuat objek tidak readable. Pada mode semaphore, satu read sukses hanya mengambil satu unit. Jika counter masih di atas nol, unit tambahan tetap tersedia.
Perbedaan ini relevan pada banyak consumer. Readiness menunjukkan bahwa suatu konsumsi dapat berhasil; readiness tidak mencadangkan unit untuk thread tertentu hanya karena thread tersebut melihat event. Consumer tetap perlu menangani race antara observasi readiness dan read aktual, terutama pada descriptor nonblocking.
Saturasi write memberi backpressure pada batas counter
Counter tidak menerima nilai 64-bit all-ones melalui interface write biasa. Write yang akan melampaui maksimum yang diizinkan akan block sampai read menyediakan ruang yang cukup, atau gagal dengan EAGAIN jika descriptor bersifat nonblocking.
Dengan demikian eventfd memiliki state accounting terbatas walaupun tidak mengantrikan record individual. Increment besar tetap membutuhkan penanganan error seperti operasi descriptor nonblocking lain.
Nilai UINT64_MAX bukan nilai write biasa yang valid. Nilai read all-ones yang didokumentasikan untuk overflow sisi kernel berkaitan dengan kasus overflow dari jalur signaling kernel; write userspace normal tidak dapat membuat state tersebut hanya dengan menambahkan nilai melewati maksimum.
Semantik descriptor membuat counter mudah dikomposisikan
Karena eventfd direpresentasikan sebagai file descriptor, objek ini dapat masuk ke infrastruktur berbasis descriptor. Event loop dapat menempatkan eventfd bersama socket, pipe, timer descriptor, atau signal descriptor dalam satu set epoll.
Properti ini sering lebih berarti daripada aritmetika counter itu sendiri. Thread yang perlu membangunkan event loop dapat menulis ke eventfd tanpa membuat jalur condition variable terpisah di luar primitive wait milik loop.
EFD_CLOEXEC dapat menetapkan close-on-exec saat pembuatan sehingga tidak memerlukan transisi fcntl() terpisah. EFD_NONBLOCK juga menetapkan status nonblocking pada saat pembuatan. Kedua flag tersebut mengatur lifecycle descriptor dan perilaku I/O; EFD_SEMAPHORE mengatur konsumsi counter.
Agregasi dan konsumsi satu unit membentuk kontrak berbeda
Mode normal dan semaphore mengekspos counter dasar yang sama, tetapi kontrak consumer-nya berbeda.
Mode normal meminta consumer mengambil nilai terakumulasi sebagai satu observasi. Mode ini cocok ketika coalescing dapat diterima dan magnitude counter sendiri membawa informasi accounting yang berguna.
Mode semaphore meminta setiap read sukses mengambil satu unit. Mode ini cocok ketika counter merepresentasikan pool permit atau unit kerja yang dapat dipertukarkan dan setiap consumer hanya boleh mengurangi satu unit per read.
Kedua mode tidak menyediakan queue payload. Aplikasi tetap membutuhkan storage terpisah ketika setiap unit memiliki data terkait. Salah satu desain yang umum adalah menyimpan data di queue dan memakai eventfd hanya sebagai sinyal readiness atau accounting, dengan aturan sinkronisasi yang menjaga state queue dan update counter tetap konsisten.
Batas utamanya bukan sekadar I/O blocking versus nonblocking. Batasnya adalah apakah satu read mengonsumsi seluruh count yang terakumulasi atau hanya satu unit. EFD_SEMAPHORE memindahkan kebijakan itu ke operasi descriptor yang terlihat kernel sambil mempertahankan counter ringkas dan integrasi event-loop milik eventfd.