Futex wait tradisional menunjuk satu futex word. Model itu cocok untuk mutex atau condition yang blocking state-nya direpresentasikan oleh satu nilai shared 32-bit. Beberapa desain sinkronisasi memiliki kebutuhan berbeda: satu thread perlu sleep sampai salah satu dari beberapa state independen berubah.

futex_waitv() menyediakan vector wait tersebut. Caller mengirim array wait descriptor yang masing-masing memuat alamat futex dan expected value. Kernel memeriksa vector dan hanya melakukan block selama semua entry masih cocok dengan state yang diharapkan.

Setiap entry membawa expected value sendiri

Wait descriptor menghubungkan alamat dengan nilai yang membuat sleep masih valid:

struct futex_waitv waiters[2] = {
    {
        .val = state_a,
        .uaddr = (uintptr_t)&futex_a,
        .flags = FUTEX2_SIZE_U32 | FUTEX2_PRIVATE,
    },
    {
        .val = state_b,
        .uaddr = (uintptr_t)&futex_b,
        .flags = FUTEX2_SIZE_U32 | FUTEX2_PRIVATE,
    },
};

Expected-value check menutup race antara observasi state di userspace dan masuknya thread ke kernel untuk sleep. Jika salah satu futex tidak lagi sama dengan nilai yang diberikan, futex_waitv() langsung gagal dengan EAGAIN alih-alih tidur pada state yang sudah stale.

Properti ini penting untuk vector. Caller tidak meminta kernel menunggu activity apa pun; caller menyatakan bahwa sleep hanya valid selama seluruh predicate yang dicantumkan masih berlaku.

Satu wake mengidentifikasi posisi vector

Ketika wait berhasil selesai, return value menunjukkan index futex yang memicu wake. Caller dapat memakai index tersebut sebagai petunjuk state mana yang sebaiknya diperiksa lebih dahulu.

waiters[0] -> queue state
waiters[1] -> shutdown state
waiters[2] -> configuration state

return 1 -> periksa shutdown state lebih dahulu

Index tidak menggantikan pemeriksaan ulang shared state. Futex wake merupakan notifikasi sinkronisasi, sedangkan correctness aplikasi tetap bergantung pada atomic state transition dan memory-ordering protocol di sekitarnya. Thread lain dapat mengubah state lagi sebelum thread yang bangun mendapat waktu CPU.

Pola yang aman tetap berbasis state: load atomic yang relevan, tentukan apakah progress dapat dilakukan, bentuk expected value untuk kondisi blocked, lakukan wait, lalu evaluasi ulang setelah return.

Mismatch mencegah thread masuk sleep

Misalkan worker melihat dua queue kosong lalu menyiapkan vector wait. Producer dapat memublikasikan work setelah observasi tersebut tetapi sebelum system call dijalankan.

Tanpa expected-value check yang terikat dengan proses masuk ke wait, worker dapat kehilangan transisi lalu sleep walaupun work sudah tersedia. futex_waitv() membandingkan setiap futex word dengan val yang sesuai sebelum block. Mismatch menghasilkan EAGAIN dan worker kembali ke pemeriksaan state di userspace.

userspace melihat A=4, B=9
          |
producer mengubah B=10
          |
          v
futex_waitv mengharapkan A=4, B=9
          |
          `--> EAGAIN, jangan sleep

Ini merupakan invariant inti yang sama dengan single-word futex wait, tetapi diterapkan pada beberapa kandidat sumber wake.

Timeout berupa absolute deadline

futex_waitv() menerima timespec deadline opsional dan clock identifier. Linux mendukung CLOCK_MONOTONIC dan CLOCK_REALTIME pada interface ini.

Timeout merupakan deadline terhadap clock yang dipilih, bukan durasi sleep relatif. Saat caller melakukan retry setelah EAGAIN, satu absolute deadline dapat dipakai kembali tanpa menghitung ulang sisa waktu pada setiap loop.

CLOCK_MONOTONIC sesuai ketika deadline mewakili elapsed runtime dan tidak boleh mengikuti perubahan wall clock. CLOCK_REALTIME mengikat deadline pada real-time clock sistem.

Vector wait tidak menggabungkan objek sinkronisasi

Futex word tetap independen. futex_waitv() tidak menggabungkan ownership rule, tidak membuat total order di antara futex tersebut, dan tidak menjalankan transaction aplikasi secara atomic terhadap semua state yang direpresentasikan.

Yang berubah adalah blocking primitive: satu thread dapat mendaftarkan minat terhadap beberapa kondisi futex melalui satu wait. Aplikasi tetap menentukan arti setiap word dan cara transisi dipublikasikan.

Perbedaan ini penting untuk komposisi lock. Menunggu salah satu dari dua lock berubah tidak sama dengan memperoleh keduanya secara atomic. Wake hanya memberi thread kesempatan baru untuk memeriksa state dan mencoba protokolnya.

Flag per entry menjelaskan representasi futex

Setiap wait descriptor memiliki flag sendiri. Size flag menyatakan representasi futex word yang digunakan interface, dan mode process-private dapat dinyatakan ketika futex hanya dipakai antar-thread dalam satu process.

Reserved field harus tetap bernilai nol. Menggunakan reserved space sebagai metadata aplikasi dapat merusak kompatibilitas dengan extension kernel pada masa depan.

Jumlah entry vector juga memiliki batas. Dependency set dinamis yang sangat besar tetap memerlukan strategi pada level lebih tinggi, bukan menganggap satu system call dapat mewakili wait set tanpa batas.

Vector wait mengurangi kebutuhan agregasi sintetis

Tanpa multi-futex wait, desain yang membutuhkan kondisi “A atau B berubah” sering menambahkan shared word lain sebagai agregator notifikasi. Setiap producer kemudian harus memperbarui atau melakukan wake pada objek bersama tersebut selain state utamanya.

futex_waitv() dapat menghilangkan notification point sintetis itu ketika kondisi sebenarnya sudah berada pada futex word terpisah. Kernel dapat memblokir waiter langsung terhadap vector.

Manfaatnya bersifat struktural. Producer tetap melakukan state transition dan wake normal, consumer tetap memeriksa state setelah bangun, dan memory ordering tetap menjadi bagian desain sinkronisasi userspace. System call ini membuat wait terhadap beberapa kondisi futex yang sudah ada menjadi operasi langsung.

Referensi