Sebuah eventfd Linux dapat menerima beberapa write sebelum consumer berjalan, tetapi descriptor tersebut tidak menyimpan setiap write sebagai pesan terpisah. Setiap write yang diterima menambahkan nilai unsigned 64-bit ke counter yang dikelola kernel. Tanpa EFD_SEMAPHORE, satu read yang berhasil mengembalikan nilai counter saat itu lalu meresetnya menjadi nol.

Perilaku tersebut membuat eventfd menjadi primitive notifikasi berbasis counter, bukan message queue. Readiness menyatakan bahwa counter tidak nol; readiness tidak mempertahankan jumlah operasi write, urutan, atau boundary setiap write.

Write mengakumulasi nilai numerik

eventfd() membuat objek eventfd dengan nilai awal counter yang diberikan sebagai unsigned integer. Sebuah write harus memberikan representasi integer delapan byte yang diharapkan interface. Nilai yang ditulis ditambahkan ke counter, bukan dimasukkan sebagai record baru.

int fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);

uint64_t a = 2;
uint64_t b = 5;

write(fd, &a, sizeof(a));
write(fd, &b, sizeof(b));

Jika tidak ada read di antara kedua write tersebut, counter menjadi 7. Read berikutnya dalam mode default dapat mengembalikan 7 sebagai satu nilai delapan byte dan mereset counter menjadi nol.

Boundary aritmetiknya eksplisit. Nilai counter biasa terbesar adalah UINT64_MAX - 1. Write dari user space dengan nilai UINT64_MAX ditolak dengan EINVAL. Jika penambahan akan melewati maksimum yang diizinkan, descriptor blocking menunggu sampai read menyediakan kapasitas; descriptor nonblocking mengembalikan EAGAIN.

Artinya, writability juga bergantung pada state. poll() dan interface setara dapat melaporkan descriptor writable ketika setidaknya nilai 1 masih dapat ditambahkan tanpa blocking.

Readability merepresentasikan state counter

Eventfd bersifat readable selama counternya lebih besar dari nol. poll(), select(), dan epoll dapat mengintegrasikan objek ini ke readiness loop yang sama dengan socket, pipe, timerfd, dan descriptor lain.

Event readiness tidak membawa nilai counter. Nilai tersebut diperoleh dengan membaca descriptor.

uint64_t value;
ssize_t n = read(fd, &value, sizeof(value));

if (n == sizeof(value)) {
    /* value adalah counter terakumulasi dalam mode default */
}

Dalam mode default, read yang berhasil mengonsumsi seluruh nilai counter saat itu. Jika producer kembali melakukan write setelahnya, readability dapat aktif lagi. Beberapa aksi producer yang terjadi sebelum consumer membaca dapat menghasilkan satu interval readiness dan satu read agregat.

Buffer yang lebih kecil dari delapan byte menghasilkan EINVAL. Jika counter bernilai nol, read blocking menunggu; dengan EFD_NONBLOCK, kondisi yang sama menghasilkan EAGAIN.

Penggabungan menghilangkan boundary write

Misalkan tiga producer menulis 1, 1, dan 1 sebelum consumer mendapat waktu CPU. Counter yang dapat diamati bernilai 3, tetapi eventfd tidak menyimpan metadata yang menyatakan adanya tiga producer atau tiga pemanggilan terpisah.

Nilai counter yang sama juga dapat berasal dari satu producer yang menulis 3. Dari hasil read saja, kedua riwayat tersebut tidak dapat dibedakan.

Hilangnya boundary ini berguna ketika signal hanya berarti bahwa pekerjaan tersedia di tempat lain. Producer dapat memperbarui queue terpisah lalu menulis ke eventfd agar event loop menjadi runnable. Beberapa notifikasi dapat bergabung sementara queue tetap menyimpan item pekerjaan sebenarnya.

Pemisahan tersebut juga membentuk boundary correctness. Jika semantik aplikasi memerlukan payload per pesan, urutan antar-payload, atau record delivery independen, counter eventfd tidak menyediakan properti itu. Payload harus berada pada struktur data lain atau mekanisme IPC yang berorientasi pesan.

EFD_SEMAPHORE mengubah konsumsi, bukan penyimpanan

Pembuatan descriptor dengan EFD_SEMAPHORE mengubah perilaku read yang berhasil. Objek tetap memelihara satu counter, dan write tetap menambahkan nilai ke counter tersebut. Satu read yang berhasil mengembalikan 1 dan mengurangi counter sebesar satu, alih-alih mengembalikan seluruh nilai lalu meresetnya menjadi nol.

Untuk counter bernilai 7, tujuh read mode semaphore dapat masing-masing mengembalikan 1, dengan asumsi tidak ada write concurrent yang mengubah state.

Mode ini mengubah cara unit counter dikonsumsi. Mode tersebut tidak mengembalikan boundary write asli. Satu write bernilai 7 dan tujuh write bernilai 1 tetap menghasilkan state counter yang setara sebelum read dimulai.

Perbedaan ini relevan pada desain yang memakai eventfd sebagai sumber token wakeup. Mode semaphore dapat membagikan unit yang tersedia melalui read terpisah, tetapi objeknya tetap merupakan primitive sinkronisasi numerik, bukan transport record.

Duplikasi descriptor berbagi objek yang sama

Descriptor eventfd hasil duplikasi merujuk ke objek eventfd dasar yang sama. Hal yang sama berlaku untuk descriptor yang diwariskan melalui fork(). Read dan write melalui referensi tersebut bekerja pada satu counter bersama.

Akibatnya, read melalui satu duplikat mengonsumsi state yang terlihat melalui duplikat lain. Duplikasi descriptor tidak menyalin counter saat ini menjadi channel notifikasi independen.

Objek tetap hidup selama setidaknya satu file descriptor terkait masih terbuka. EFD_CLOEXEC mengatur apakah descriptor baru otomatis ditutup saat execve(); flag tersebut tidak mengubah semantik counter.

Overflow counter memiliki kasus terpisah dari kernel

Pemanggilan write() biasa dari user space tidak dapat mendorong counter melewati maksimum yang diizinkan karena write akan blocking atau gagal sebelum kondisi itu terjadi. Linux mendokumentasikan kondisi overflow terpisah untuk kasus teoretis ketika asynchronous I/O kernel melakukan 2^64 eventfd signal post tanpa read.

Dalam state tersebut, API readiness mengekspos indikasi error dan read mengembalikan UINT64_MAX. Jalur overflow ini terpisah dari aturan penambahan user space dan tidak dapat disimpulkan dari EAGAIN akibat counter yang hampir penuh.

Perbedaan itu menjaga dua boundary tetap jelas: write dari user space diperiksa terhadap kapasitas, sedangkan signal post dari kernel memiliki representasi overflow yang terdokumentasi.

Semantik counter membentuk kontrak event loop

Event loop yang menganggap satu dispatch readiness sebagai satu event producer menetapkan properti yang tidak diberikan eventfd. Delay scheduling, batching, dan writer concurrent dapat menggabungkan aktivitas notifikasi ke state counter nonzero yang sama.

Kontrak yang sesuai memberi makna pada counter itu sendiri atau hanya memakainya sebagai indikasi wakeup untuk state yang disimpan di tempat lain. Read default memberikan nilai numerik agregat; read semaphore mengonsumsi satu unit setiap kali. Kedua mode tidak mempertahankan stream record write.

Kontrak yang sempit itu menjadi sumber kegunaan eventfd. Primitive ini mengekspos counter kernel kecil melalui readiness file descriptor biasa, sehingga state notifikasi dapat bergabung dengan event loop berbasis descriptor sementara semantik payload dan ordering yang lebih kaya tetap menjadi tanggung jawab sistem di sekitarnya.