Sinyal yang masuk ke mask signalfd dapat membuat file descriptor menjadi readable alih-alih menjalankan handler asinkron, selama sinyal tersebut diblokir dari delivery biasa. read() yang berhasil kemudian mengonsumsi status sinyal pending dan mengembalikan satu atau beberapa record signalfd_siginfo.
Perubahan ini mengganti antarmuka penerimaan untuk sinyal terpilih, tetapi tidak mengganti semantik signal Linux. Signal mask, delivery yang diarahkan ke process atau thread, penggabungan standard signal, serta status khusus SIGKILL dan SIGSTOP tetap menentukan batas perilaku descriptor.
Blocking membentuk jalur menuju descriptor
signalfd() mengaitkan sebuah signal set dengan file descriptor. Pada pemakaian normal, signal yang sama diblokir dengan sigprocmask() pada process single-threaded atau pthread_sigmask() pada process multithreaded.
Blocking penting karena signal yang masih memenuhi syarat untuk delivery biasa dapat mengikuti disposition yang telah dikonfigurasi, bukan bertahan sebagai pending untuk dikonsumsi lewat descriptor. Jadi, descriptor ini bukan lapisan intersepsi global yang berada di depan signal delivery. Ia adalah antarmuka read untuk signal pending yang cocok dengan mask.
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGHUP);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
int sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);Pada process multithreaded, memblokir signal hanya pada thread yang membuat descriptor tidak cukup untuk process-directed signal. Thread lain yang tidak memblokir signal tersebut dapat dipilih untuk delivery biasa. Desain yang umum memblokir signal set terpilih sebelum worker thread dibuat sehingga mask ikut diwariskan.
Readiness berarti signal yang cocok sedang pending
Descriptor menjadi readable ketika setidaknya satu signal dalam mask-nya sedang pending dan tersedia bagi thread yang melakukan read. Karena itu, poll(), select(), dan epoll() dapat menempatkan penerimaan signal bersama socket, pipe, timerfd, dan sumber event berbasis descriptor lainnya.
Satu read mengembalikan struktur signalfd_siginfo secara utuh. Jika buffer mampu menampung beberapa record, satu pemanggilan dapat mengembalikan beberapa signal pending.
struct signalfd_siginfo info[8];
ssize_t n = read(sfd, info, sizeof(info));
if (n > 0) {
size_t count = (size_t)n / sizeof(info[0]);
for (size_t i = 0; i < count; i++) {
dispatch_signal(&info[i]);
}
}Mengonsumsi record juga mengonsumsi occurrence signal pending tersebut. Signal itu tidak lagi pending untuk handler atau antarmuka seperti sigwaitinfo().
Dengan SFD_NONBLOCK, read tanpa signal pending yang cocok gagal dengan EAGAIN. Tanpa mode nonblocking, read menunggu sampai signal yang cocok tersedia.
Record membawa metadata signal
signalfd_siginfo memuat nomor signal beserta field yang analog dengan sebagian siginfo_t, termasuk identifier pengirim dan data khusus signal. Field yang bermakna bergantung pada signal serta nilai ssi_code.
Struktur tersebut merupakan record ABI Linux, bukan bentuk serialisasi siginfo_t. Kode perlu memeriksa field yang didefinisikan untuk event terkait dan tidak menganggap setiap member valid untuk semua sumber signal.
Representasi ini berguna di event loop karena dispatch berjalan dalam control flow biasa. Callback tidak berjalan di bawah pembatasan asynchronous signal handler hanya karena event asalnya berupa signal.
Standard signal tetap mengalami coalescing
signalfd tidak mengubah standard signal menjadi queue tanpa batas. Standard signal Linux mempertahankan semantik pending normal: jika beberapa instance signal standar yang sama dibuat saat signal itu sudah pending, hanya satu instance yang tetap pending.
Properti ini membedakan readiness dari penghitungan event. Sepuluh SIGHUP yang muncul cepat tidak berarti tersedia sepuluh record signalfd_siginfo. Aplikasi yang memerlukan queue per occurrence membutuhkan mekanisme dengan semantik queue yang sesuai, misalnya real-time signal bila cocok, atau channel IPC lain.
Real-time signal mengikuti aturan queue miliknya sendiri; signalfd mengekspos status signal pending tanpa mendefinisikan ulang aturan tersebut.
Thread-directed signal tetap mempertahankan target
Target signal juga tetap berlaku. Thread yang membaca signalfd dapat mengonsumsi signal yang diarahkan kepadanya sendiri serta process-directed signal yang tersedia baginya. Read pada descriptor tersebut tidak dapat mengambil signal yang secara khusus diarahkan ke thread lain.
Hal ini penting ketika process menggabungkan pthread_kill() atau tgkill() dengan event-loop thread terpusat. Signal yang ditargetkan ke worker tidak berubah menjadi event process generik hanya karena process tersebut memiliki signalfd.
Untuk loop signal terpusat, control signal yang diarahkan ke process dan mask yang diblokir secara konsisten di seluruh thread lebih sesuai dengan model ini.
SIGKILL dan SIGSTOP tetap berada di luar mekanisme
Upaya memasukkan SIGKILL atau SIGSTOP ke mask signalfd diabaikan. Linux tidak mengizinkan kedua signal ini diblokir, ditangkap, atau dialihkan ke jalur penerimaan berbasis descriptor.
Synchronous fault signal merupakan batas lain. Fault seperti akses memori invalid yang menghasilkan SIGSEGV terikat pada execution context yang mengalami fault dan bukan target pengganti yang praktis untuk signalfd; dokumentasi Linux menyatakan synchronous fault signal memerlukan signal handler ketika hendak ditangkap.
Model descriptor paling sesuai untuk control signal dan notification signal asinkron yang delivery-nya dapat sengaja diblokir lalu diterima dalam control flow program biasa.
Lifecycle descriptor mengikuti aturan file descriptor
signalfd baru dapat memakai SFD_CLOEXEC dan SFD_NONBLOCK saat dibuat. Flag pertama mencegah inheritance yang tidak disengaja melewati execve(); flag kedua sesuai untuk event loop yang menguras readiness tanpa blocking.
Setelah fork(), child mewarisi descriptor, tetapi status pending dan target signal tetap mengikuti aturan signal. Descriptor juga dapat dikirim melalui UNIX domain socket. Read pada process penerima berkaitan dengan signal yang pending untuk process penerima tersebut, bukan stream portabel berisi event signal yang ditangkap dari pengirim.
Dengan demikian, objek ini berbentuk descriptor pada batas API tetapi tetap terikat pada semantik signal pada batas delivery.
Batas utamanya adalah penerimaan sinkron
Efek utama signalfd bukan mengubah signal menjadi byte biasa. Notification asinkron terpilih menjadi record yang dapat dikonsumsi secara sinkron, sementara descriptor readiness memberi tahu event loop saat record tersedia.
Susunan ini dapat menghilangkan asynchronous handler dari jalur control signal dan menyatukan dispatch di bawah epoll(). Namun, signal mask, targeting, coalescing, dan signal yang tidak dapat ditangkap tetap berlaku. Desain yang mempertahankan batas tersebut memperoleh control path berorientasi descriptor tanpa memberikan jaminan yang lebih kuat daripada semantik Linux.