Satu request io_uring multishot accept di Linux dapat menghasilkan beberapa completion queue entry dari satu submission queue entry. Kernel mempertahankan operasi accept setelah completion yang sukses ketika CQE membawa IORING_CQE_F_MORE, sehingga server tidak perlu mengirim SQE accept baru untuk setiap koneksi.
Perilaku ini mengubah kontrak lifetime antara submission dan completion. Request oneshot normal selesai setelah CQE-nya. Multishot accept dapat tetap in-flight melewati banyak koneksi yang diterima, dan flag pada CQE menentukan apakah request tersebut masih ada.
Satu SQE dapat menghasilkan banyak CQE
io_uring_prep_multishot_accept() menyiapkan operasi accept yang aktivitas suksesnya dapat dilaporkan berulang kali. Setiap koneksi yang diterima menghasilkan CQE, dengan file descriptor yang terpasang dikembalikan melalui cqe->res.
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_multishot_accept(
sqe,
listen_fd,
NULL,
NULL,
SOCK_CLOEXEC
);
sqe->user_data = ACCEPT_TOKEN;Setelah submission, beberapa koneksi masuk dapat menghasilkan completion yang terkait dengan user_data yang sama.
SQE user_data = ACCEPT_TOKEN
CQE 1: res = 12, flags = IORING_CQE_F_MORE
CQE 2: res = 15, flags = IORING_CQE_F_MORE
CQE 3: res = 18, flags = IORING_CQE_F_MORECQE yang berulang tidak merepresentasikan submission SQE yang berulang. Semuanya merupakan hasil terpisah dari satu request yang tetap aktif.
IORING_CQE_F_MORE menentukan lifetime request
Untuk request multishot, IORING_CQE_F_MORE merupakan sinyal utama bagi lifetime. Ketika flag ini ada, completion berikutnya masih dapat muncul dari request yang sama. Ketika sebuah CQE datang tanpa flag tersebut, request multishot telah berakhir dan CQE berikutnya tidak lagi diharapkan darinya.
Completion loop karena itu perlu memperlakukan hasil dan flag lifetime sebagai dua state terpisah.
struct io_uring_cqe *cqe;
io_uring_wait_cqe(&ring, &cqe);
int res = cqe->res;
bool active = cqe->flags & IORING_CQE_F_MORE;
if (res >= 0) {
int client_fd = res;
/* hand client_fd to connection state */
}
if (!active) {
/* this multishot accept request is finished */
}File descriptor hasil accept yang sukses tidak dengan sendirinya membuktikan bahwa request masih aktif. Informasi tersebut dibawa oleh flag.
Completion final membentuk batas rearm
Multishot menghapus kebutuhan resubmission per koneksi selama request masih hidup, tetapi tidak membuat accept bersifat permanen. Error, cancellation eksplisit, atau kondisi terminasi lain dapat mengakhiri request. CQE final tidak membawa IORING_CQE_F_MORE.
Jika listener harus terus menerima koneksi setelah terminasi, user space harus mengirim request accept baru. Kondisi ini membentuk batas operasional yang jelas:
submit multishot accept
|
+-- CQE + MORE
+-- CQE + MORE
+-- final CQE
|
+-- request no longer active
+-- submit replacement if service continuesKode yang menganggap SQE awal akan tetap armed selamanya dapat berhenti menerima koneksi setelah completion terminal tanpa tanda lain pada jalur aplikasi.
Cancellation mengakhiri request persisten
Karena request dapat hidup melewati banyak completion individual, logika shutdown harus menargetkan request itu sendiri. Operasi IORING_OP_ASYNC_CANCEL dapat membatalkan request multishot, lazimnya dengan mencocokkan user_data.
Setelah cancellation berhasil, operasi multishot menghasilkan completion terminal tanpa IORING_CQE_F_MORE; perilaku cancellation yang didokumentasikan melaporkan -ECANCELED sebagai hasil final tersebut.
Identitas request dengan demikian penting lebih dari sekadar mengorelasikan satu submission dengan satu completion. Identitas itu dapat mewakili operasi kernel berumur panjang yang tetap dapat dibatalkan di antara kedatangan koneksi.
Direct accept mengubah penempatan descriptor
io_uring_prep_multishot_accept_direct() menggabungkan perilaku multishot dengan fixed-file table milik io_uring. Alih-alih memasang setiap socket hasil accept ke tabel file descriptor proses, kernel dapat mengalokasikan slot direct descriptor yang kosong untuk setiap koneksi.
Fixed-file table harus sudah memiliki ruang yang sesuai. Pada alokasi dinamis, kehabisan slot dilaporkan melalui hasil CQE, misalnya -ENFILE ketika tidak ada direct slot yang bebas.
Varian ini mengubah lokasi pemasangan socket hasil accept, bukan aturan lifetime multishot. IORING_CQE_F_MORE tetap menunjukkan apakah request accept awal dapat menghasilkan completion berikutnya.
Kapasitas completion menjadi bagian dari backpressure
Satu request accept yang aktif dapat menghasilkan CQE seiring koneksi datang. Hilangnya submission SQE berulang tidak menghapus batas kapasitas pada sisi completion. Aplikasi tetap harus mengonsumsi CQE dengan segera dan mengukur jalur completion sesuai pola trafiknya.
Unit accounting yang relevan bukan lagi satu SQE yang berpasangan dengan tepat satu CQE. SQE multishot berumur panjang dapat memiliki relasi satu-ke-banyak dengan CQE.
Sifat ini memengaruhi bookkeeping. State per-request tidak dapat dibebaskan setelah completion sukses pertama jika completion berikutnya masih merujuk identitas request yang sama. Cleanup berada pada CQE terminal, sedangkan setiap descriptor hasil accept memperoleh lifetime koneksinya sendiri.
Multishot mengubah biaya submission, bukan semantik accept
Setiap hasil sukses tetap merepresentasikan koneksi berbeda yang telah diterima. Multishot terutama mengubah cara operasi accept di-arm dan cara completion dikirim: satu SQE dapat tetap resident dan melaporkan banyak socket hasil accept.
Interface ini memisahkan dua lifetime yang sering dianggap identik oleh kode oneshot. Socket hasil accept memulai lifetime koneksi masing-masing, sedangkan request accept asal dapat tetap aktif melintasi semuanya. IORING_CQE_F_MORE menjadi batas yang mencegah kedua lifetime tersebut tercampur.