Linux eventfd dapat menggabungkan banyak notifikasi ke dalam satu counter yang dikelola kernel sambil tetap dapat digunakan dengan poll(), select(), dan epoll. Writer menambahkan nilai unsigned 64-bit ke counter; readiness menyatakan apakah status tersebut dapat dikonsumsi. Interface ini membawa status aritmetika, bukan byte stream atau antrean pesan individual.
Perbedaan tersebut penting pada batas proses dan thread. Sebuah wakeup menyatakan bahwa counter bukan nol. Wakeup itu tidak mempertahankan jumlah operasi write, identitas writer, atau urutan di antara sumber notifikasi yang terpisah.
Write menambahkan nilai, bukan record
eventfd() membuat objek eventfd yang berisi counter unsigned 64-bit. Argumen initval memberikan nilai awalnya. EFD_NONBLOCK menerapkan semantik I/O nonblocking, sedangkan EFD_CLOEXEC memasang close-on-exec pada descriptor yang dikembalikan.
write() yang berhasil memasok tepat satu integer delapan byte dalam host byte order. Nilai tersebut ditambahkan ke counter saat ini. Menulis UINT64_MAX tidak valid, dan write biasa dari user space tidak dapat menaikkan counter tersimpan melewati UINT64_MAX - 1.
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
uint64_t n = 3;
ssize_t written = write(efd, &n, sizeof(n));Write tersebut menyumbang tiga unit status counter. Operasi itu tidak menambahkan record delapan byte yang dapat diambil kembali tanpa perubahan oleh read berikutnya. Jika writer lain menyumbang lima sebelum read, semantik read default dapat mengekspos nilai agregat delapan.
Agregasi ini membuat eventfd ringkas untuk count notifikasi, tetapi juga menghilangkan batas pesan. Komponen yang memerlukan payload per event, identitas sumber, atau urutan record yang ketat memerlukan transport lain atau status terpisah di luar counter eventfd.
Read default menukar status terakumulasi menjadi nol
Tanpa EFD_SEMAPHORE, read() yang berhasil mengembalikan counter nonzero saat ini sebagai satu integer delapan byte dalam host byte order lalu mereset counter menjadi nol.
uint64_t value;
ssize_t nread = read(efd, &value, sizeof(value));Jika counter berisi delapan, read mengembalikan delapan dan mengonsumsi status terakumulasi tersebut dalam satu operasi. Read berikutnya tidak melihat nilai counter yang tersedia sampai ada kontribusi baru.
Saat counter bernilai nol, read blocking menunggu sampai nilainya menjadi nonzero. Dengan EFD_NONBLOCK, kondisi yang sama menghasilkan EAGAIN. Buffer yang lebih kecil dari delapan byte menghasilkan EINVAL.
Unit semantiknya adalah agregat saat ini, bukan satu notifikasi. Aplikasi yang memperlakukan setiap event readiness sebagai tepat satu tindakan producer dapat membuang informasi secara diam-diam walaupun kernel telah mempertahankan total count.
Mode semaphore mengubah konsumsi, bukan produksi
EFD_SEMAPHORE mengubah perilaku read yang berhasil tetapi tetap mempertahankan write aditif. Saat counter nonzero, setiap read mengembalikan nilai satu dan mengurangi counter sebesar satu, bukan mengembalikan seluruh agregat lalu meresetnya.
Jika writer menyumbang tiga dan lima, counter dapat mencapai delapan pada kedua mode. Mode default memungkinkan satu read mengonsumsi delapan. Mode semaphore memungkinkan delapan read berhasil yang masing-masing mengonsumsi satu, dengan asumsi tidak ada write concurrent yang mengubah status.
Ini adalah kontrak konsumsi, bukan mekanisme pemulihan record. Mode semaphore tetap tidak menunjukkan apakah delapan berasal dari delapan write bernilai satu, satu write bernilai delapan, atau kombinasi lain. Mode ini mempertahankan unit dalam counter sambil tetap menghilangkan batas operasi producer.
Beberapa reader juga bersaing atas status yang sama. Read yang berhasil oleh satu thread atau proses mengubah counter yang diamati oleh semua referensi lain ke objek eventfd tersebut.
Readiness mengikuti aritmetika counter
eventfd bersifat readable ketika counter lebih besar dari nol. eventfd bersifat writable ketika setidaknya nilai satu dapat ditambahkan tanpa blocking. Kondisi ini membuat status counter terlihat oleh mekanisme multiplexing file descriptor tanpa mengubahnya menjadi data stream.
Kondisi writable memiliki batas yang jarang ditemui tetapi presisi. Jika sebuah penambahan akan melewati UINT64_MAX - 1, write blocking menunggu sampai read mengurangi counter. Pada I/O nonblocking, write gagal dengan EAGAIN.
Readiness merupakan status level-sensitive pada interface eventfd: counter nonzero tetap readable sampai read mengonsumsinya. epoll edge-triggered menambahkan aturan notifikasinya sendiri, tetapi tidak mengubah aritmetika counter eventfd. Kode event loop tetap harus memperhitungkan status yang tersisa setelah setiap read.
Notifikasi readiness juga dapat menjadi usang sebelum consumer bertindak. Reader lain dapat mengonsumsi counter setelah event loop mengamati readiness. Mode nonblocking membuat race semacam ini berakhir sebagai EAGAIN, bukan berubah menjadi penantian yang tidak diperkirakan.
Duplikasi descriptor berbagi satu counter
Descriptor yang diwariskan melalui fork() merujuk ke objek eventfd yang sama. Descriptor hasil duplikasi juga merujuk ke objek bersama tersebut. Write melalui referensi mana pun menambah counter yang sama, dan read melalui referensi mana pun mengonsumsi darinya.
Sifat ini membuat eventfd cocok sebagai primitive koordinasi yang sempit di antara thread atau proses yang berhubungan, tetapi jumlah descriptor tidak menciptakan jumlah subscriber. Dua reader tidak masing-masing menerima salinan nilai terakumulasi.
Lifetime mengikuti objek kernel bersama. Setelah semua descriptor yang merujuk ke objek eventfd ditutup, kernel dapat melepaskan resource-nya. EFD_CLOEXEC penting ketika channel notifikasi tidak boleh melewati batas execve() yang berhasil.
Status counter dan status aplikasi tetap terpisah
eventfd dapat memberi sinyal bahwa work tersedia tanpa menyimpan work itu sendiri. Sebuah queue dapat menyimpan work item sementara eventfd menyediakan indikasi pollable bahwa producer telah mengubah status queue. Correctness kemudian bergantung pada aturan sinkronisasi queue sekaligus kontrak eventfd.
Kontribusi counter tidak dengan sendirinya memublikasikan arbitrary user-space memory menurut memory model C atau C++. Sinkronisasi thread tetap memerlukan operasi yang aturan ordering pada level bahasanya mencakup data bersama tersebut. Di antara proses, mekanisme shared memory dan protokol sinkronisasinya membawa batasannya sendiri. eventfd menyediakan notifikasi yang dimediasi kernel dan operasi counter; eventfd bukan pengganti kontrak memory ordering untuk data terpisah.
Batas yang sama berlaku pada counting. Jika setiap producer menulis satu hanya setelah berhasil memasukkan satu item ke queue, nilai eventfd dapat dipakai sebagai count yang terkait dengan protokol tersebut. Jika producer melakukan batching nilai, mengulangi write, membuang entry queue, atau memperbarui queue dan counter dengan aturan kegagalan berbeda, kesetaraan antara unit counter dan entry queue merupakan invariant aplikasi, bukan jaminan eventfd.
eventfd paling tepat ketika kontrak sempit tersebut dinyatakan secara eksplisit: write mengakumulasi status numerik, read mengonsumsinya menurut salah satu dari dua mode, readiness mencerminkan apakah status saat ini dapat dikonsumsi, dan setiap descriptor yang merujuk ke objek tersebut berpartisipasi dalam counter yang sama.