EPOLLEXCLUSIVE mengubah waiter epoll mana yang dibangunkan saat beberapa instance epoll memantau target yang sama. Tanpa flag ini, sebuah readiness event dapat dikirim ke setiap instance epoll yang terpasang. Dengan registrasi eksklusif, Linux dapat membangunkan subset yang lebih kecil sehingga scheduling redundan berkurang pada konfigurasi yang jika tidak demikian dapat memicu thundering herd.

Flag ini mengubah distribusi wakeup. Ia tidak memberikan kepemilikan permanen atas target descriptor, tidak menserialisasi I/O, dan tidak menjamin tepat satu thread aplikasi mengonsumsi setiap unit pekerjaan.

Eksklusivitas melekat pada registrasi

Sebuah instance epoll memelihara interest list berisi target yang dipantau dan ready list yang diisi oleh aktivitas I/O kernel. epoll_ctl() menambahkan target ke interest list tersebut bersama event flag dan user data.

EPOLLEXCLUSIVE ditentukan saat target ditambahkan:

struct epoll_event ev = {
    .events = EPOLLIN | EPOLLEXCLUSIVE,
    .data.fd = listen_fd,
};

if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev) == -1) {
    /* handle registration failure */
}

Flag ini tersedia di Linux sejak 4.5. Efeknya berlaku pada relasi antara instance epoll tersebut dan file target. Ia bukan mode yang dipasang secara global pada target descriptor.

Perbedaan ini penting ketika beberapa proses masing-masing membuat instance epoll lalu mendaftarkan listening socket yang sama setelah diwariskan. Setiap registrasi dapat meminta perilaku exclusive wakeup secara independen.

Exclusive wakeup tidak berarti tepat satu

Ketika target menghasilkan event dan beberapa file descriptor epoll terpasang dengan EPOLLEXCLUSIVE, satu atau lebih instance epoll tersebut menerima event. Kontrak terdokumentasi sengaja mengizinkan lebih dari satu exclusive waiter untuk terbangun.

Batas ini mencegah interpretasi API yang terlalu kuat. EPOLLEXCLUSIVE adalah mekanisme untuk membatasi wakeup, bukan mutex atas pengiriman readiness.

Server karena itu tidak dapat menurunkan invariant satu-event-ke-satu-worker dari flag ini:

socket menjadi ready
        |
registrasi epoll eksklusif
        |
satu atau lebih instance epoll bangun
        |
worker mencoba operasi I/O aktual

Operasi I/O tetap menjadi otoritas akhir. Pada listening socket nonblocking, misalnya, worker yang bangun tetap perlu menangani hasil accept() atau accept4() sesuai semantik nonblocking normal. Worker lain dapat lebih dahulu mengonsumsi koneksi yang tersedia, atau readiness state dapat berubah sebelum worker tertentu menjalankan operasi.

Registrasi nonexclusive tetap menerima event

Registrasi eksklusif dan biasa dapat hidup bersamaan untuk target yang sama. Jika beberapa instance epoll mendaftarkan target tanpa EPOLLEXCLUSIVE, event dikirim ke semua instance nonexclusive tersebut dan ke setidaknya satu instance eksklusif.

Karena itu, flag ini tidak cocok diperlakukan sebagai switch global tersembunyi yang menekan semua observer lain. Komponen monitoring dengan registrasi biasa dapat terus menerima readiness notification meskipun worker pool memakai registrasi eksklusif.

Topologi hasilnya dapat digambarkan sebagai:

                 target fd
                /    |    \
               /     |     \
        normal epoll  |  normal epoll
                      |
             grup epoll eksklusif

readiness -> kedua registrasi normal
          -> satu atau lebih registrasi eksklusif

Correctness perlu memperhitungkan setiap kelas registrasi yang ada, bukan hanya worker pool.

Flag memiliki semantik epoll_ctl yang terbatas

EPOLLEXCLUSIVE hanya dapat diberikan bersama EPOLL_CTL_ADD. Memberikannya bersama EPOLL_CTL_MOD gagal dengan EINVAL. Setelah target ditambahkan menggunakan flag tersebut, EPOLL_CTL_MOD berikutnya untuk pasangan epoll-target yang sama juga gagal.

Event mask juga dibatasi. Linux mengizinkan EPOLLIN, EPOLLOUT, EPOLLWAKEUP, dan EPOLLET bersama EPOLLEXCLUSIVE. EPOLLHUP dan EPOLLERR dilaporkan seperti biasa dan tidak perlu diminta. Kombinasi flag yang tidak didukung menghasilkan EINVAL.

Constraint ini membuat strategi registrasi menjadi bagian dari setup, bukan properti yang bebas diubah saat entry tetap terpasang. Software yang perlu mengganti konfigurasi eksklusif harus memperhitungkan lifecycle entry pada interest list, bukan mengasumsikan operasi MOD biasa dapat mengubah mode tersebut.

Target tidak dapat berupa instance epoll

Linux menolak registrasi eksklusif jika target descriptor itu sendiri merujuk pada instance epoll. Dengan demikian EPOLLEXCLUSIVE tidak dapat digunakan pada topologi epoll bertingkat.

Nesting epoll biasa memiliki constraint tersendiri, tetapi exclusive wakeup mode secara khusus didefinisikan untuk target non-epoll yang dipasang pada instance epoll. Memperlakukan flag ini sebagai properti generik untuk setiap graph descriptor yang pollable melampaui kontrak API-nya.

Readiness dan kepemilikan pekerjaan tetap terpisah

Epoll melaporkan bahwa operasi I/O mungkin dapat berjalan tanpa blocking sesuai semantik readiness target. Epoll tidak mencadangkan byte, koneksi, packet, atau transisi state terkait untuk thread yang menerima event.

Perbedaan itu makin terlihat dengan banyak consumer. Pertimbangkan beberapa proses yang berbagi listening socket nonblocking. Exclusive wakeup dapat mengurangi jumlah proses yang dijadwalkan untuk koneksi baru, tetapi proses yang kembali dari epoll_wait() tetap bersaing pada saat accept4() dengan aktor lain yang diizinkan menerima dari socket tersebut.

Aplikasi dapat menambahkan aturan kepemilikan yang lebih kuat jika arsitekturnya memerlukan hal tersebut. Aturan itu dapat melibatkan partitioning queue, assignment descriptor, lock, atau fasilitas kernel dengan semantik distribusi berbeda. Semua itu terpisah dari pengurangan wakeup yang diberikan EPOLLEXCLUSIVE.

Edge-triggered mode tetap memiliki kewajiban drain

EPOLLET dapat digabungkan dengan EPOLLEXCLUSIVE. Kedua flag memengaruhi dimensi berbeda: EPOLLEXCLUSIVE memengaruhi distribusi antar-instance epoll, sedangkan EPOLLET memilih perilaku notifikasi edge-triggered untuk registrasi.

Consumer edge-triggered tetap memerlukan I/O nonblocking dan state machine yang menguras pekerjaan tersedia sampai operasi melaporkan bahwa saat itu tidak ada progres tambahan yang dapat dilakukan. Exclusive wakeup tidak mengubah edge-triggered readiness menjadi notifikasi satu-item.

Menggabungkan kedua flag karena itu tidak menyederhanakan semantik I/O target. Kombinasi tersebut mengubah waiter yang kemungkinan dijalankan sambil mempertahankan kewajiban pemrosesan edge-triggered.

Instance epoll bersama adalah topologi yang berbeda

Ada perbedaan penting antara beberapa thread yang menunggu pada satu file descriptor epoll dan beberapa instance epoll yang memantau satu target. EPOLLEXCLUSIVE menangani topologi registrasi yang kedua.

Linux sudah memiliki perilaku wakeup khusus untuk thread yang blocking pada descriptor epoll yang sama, termasuk kasus edge-triggered. Menerapkan kesimpulan dari topologi itu ke beberapa instance epoll yang dibuat secara independen dapat menghasilkan asumsi scheduling yang keliru.

Deskripsi desain yang tepat menyebut kedua relasi secara eksplisit:

Topologi A:
thread -> satu instance epoll -> target

Topologi B:
thread/proses -> instance epoll A \
thread/proses -> instance epoll B  -> target yang sama
thread/proses -> instance epoll C /

EPOLLEXCLUSIVE relevan untuk registrasi pada topologi B.

Wakeup yang berkurang adalah properti scheduling, bukan primitive correctness

Nilai utama EPOLLEXCLUSIVE adalah mengurangi wakeup yang tidak diperlukan ketika banyak instance epoll independen bersaing atas readiness target yang sama. Lebih sedikit worker yang dibangunkan dapat berarti aktivitas scheduler dan contention sia-sia yang lebih rendah pada workload yang rentan terhadap thundering herd.

API ini sengaja berhenti sebelum memberikan jaminan single-consumer. Lebih dari satu instance epoll eksklusif dapat menerima event, observer nonexclusive tetap menerima event mereka, dan operasi target menentukan worker mana yang benar-benar membuat progres.

Batas tersebut menjaga mekanismenya tetap sempit: EPOLLEXCLUSIVE membentuk fan-out wakeup. Kepemilikan resource, serialisasi I/O, fairness, dan dispatch pada level aplikasi tetap menjadi properti desain concurrency di sekelilingnya.