Descriptor eventfd menjadi readable saat counter yang dipelihara kernel bernilai lebih besar dari nol. Sebuah write tidak memasukkan pesan dengan panjang variabel ke antrean. Operasi itu menambahkan nilai unsigned 64-bit ke counter, sehingga status notifikasi yang terakumulasi tampil sebagai readiness file descriptor biasa.

Batas ini berguna ketika thread atau fasilitas kernel perlu membangunkan event loop tanpa membentuk protokol byte stream. Status yang dibawa descriptor sengaja sempit: sebuah counter, kondisi readiness, dan dua pilihan semantik konsumsi.

Write mengakumulasi status counter

eventfd() membuat objek eventfd dengan nilai awal counter dan mengembalikan file descriptor yang merujuk ke objek tersebut. Counter dipelihara kernel sebagai integer unsigned 64-bit.

write() yang berhasil mentransfer tepat delapan byte dalam host byte order lalu menambahkan nilainya ke counter. Nilai UINT64_MAX ditolak. Nilai normal terbesar untuk counter adalah UINT64_MAX - 1.

uint64_t increment = 3;
ssize_t n = write(event_fd, &increment, sizeof(increment));

Jika penambahan nilai akan melewati batas maksimum, write blocking menunggu sampai sebuah read menyediakan kapasitas counter yang cukup. Dengan EFD_NONBLOCK, kondisi yang sama menghasilkan EAGAIN.

Perilaku ini berbeda dari pipe yang hanya dipakai sebagai kanal wakeup. Tiga write bernilai 1 dapat melebur menjadi counter bernilai 3; tidak ada tiga record payload independen yang harus dipertahankan.

Read default menguras nilai yang terakumulasi

Tanpa EFD_SEMAPHORE, read() yang berhasil mengembalikan nilai counter saat itu sebagai satu integer delapan byte lalu mereset counter menjadi nol.

uint64_t pending;
ssize_t n = read(event_fd, &pending, sizeof(pending));
if (n == sizeof(pending)) {
    process_notifications(pending);
}

Misalkan producer menulis 2, 4, dan 1 sebelum consumer melakukan read. Tanpa read di antaranya, counter mencapai 7. Consumer menerima 7 dan counter kembali menjadi nol.

Hasil tersebut merepresentasikan kuantitas yang terakumulasi, bukan identitas atau urutan producer. Aplikasi yang memerlukan metadata per event membutuhkan struktur data atau transport lain. eventfd dapat memberi sinyal bahwa data tersebut tersedia, tetapi counternya tidak menyimpan data itu.

EFD_SEMAPHORE mengubah granularitas konsumsi

Pembuatan descriptor dengan EFD_SEMAPHORE mempertahankan perilaku write yang aditif, tetapi mengubah read yang berhasil. Setiap read mengembalikan nilai 1 dan mengurangi counter sebesar satu.

Untuk counter bernilai 7, tujuh read yang berhasil dapat mengonsumsi status satu unit demi satu unit. Descriptor memperoleh semantik konsumsi bergaya semaphore sambil mempertahankan readiness descriptor dan batas penyimpanan counter yang sama.

int event_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE);

Flag tersebut tidak membuat POSIX semaphore dan tidak menambahkan jaminan ownership atau fairness bagi waiter. Perubahannya terbatas pada operasi read eventfd, dari menguras seluruh nilai menjadi mengurangi satu unit.

Readiness mengikuti status dan kapasitas counter

poll(), select(), dan epoll() dapat memantau eventfd bersama socket dan descriptor lain. Readable berarti counter lebih besar dari nol. Writable berarti setidaknya nilai 1 dapat ditambahkan tanpa blocking.

Pemetaan tersebut memberi event loop transisi status yang ringkas:

counter = 0        -> not readable
counter > 0        -> readable
successful drain   -> counter = 0

Dengan EFD_SEMAPHORE, read yang berhasil dapat menyisakan counter di atas nol, sehingga descriptor tetap readable sampai cukup banyak read mengonsumsi unit yang pending.

Readiness dengan demikian merupakan status level pada objek eventfd, terlepas dari event loop yang memakai epoll level-triggered atau edge-triggered. Consumer edge-triggered tetap perlu mengonsumsi status yang tersedia sampai operasi nonblocking melaporkan bahwa progres lebih lanjut belum tersedia.

Salinan descriptor merujuk ke objek yang sama

Descriptor yang diwariskan melalui fork() merujuk ke objek eventfd yang sama. Duplikasi descriptor memberi konsekuensi serupa: operasi melalui descriptor tersebut bekerja pada satu counter bersama, bukan salinan privat.

Objek tetap hidup selama masih ada referensi terbuka. Menutup satu duplikat tidak membuang status counter jika descriptor lain masih merujuk ke objek tersebut.

Model referensi ini membuat eventfd cocok untuk koordinasi dengan cakupan sempit antar-thread atau proses yang berkerabat, tetapi transfer dan pewarisan descriptor menjadi bagian dari rancangan sinkronisasi. EFD_CLOEXEC mencegah referensi yang tidak diinginkan bertahan setelah execve() berhasil.

Semantik counter menetapkan batas mekanisme

eventfd bukan message queue serbaguna. Mekanisme ini mempertahankan agregat numerik dan mengekspos apakah agregat tersebut dapat dikonsumsi atau ditambah tanpa blocking. Read default menukar detail batching dengan bentuk yang ringkas melalui pengurasan agregat dalam satu operasi; EFD_SEMAPHORE mengganti perilaku itu dengan konsumsi satu unit per read.

Properti utamanya adalah konversi status counter menjadi file-descriptor readiness. Producer dapat mem-post status numerik, consumer dapat mengamatinya melalui interface multiplexing yang sama dengan I/O, dan kernel menjaga transisi antara status nol dan bukan nol pada satu objek berbasis descriptor.