PID numerik menamai sebuah proses hanya selama PID tersebut masih dialokasikan kepadanya. Setelah proses berhenti dan di-reap, Linux dapat memakai kembali nomor itu untuk proses lain. PID file descriptor, atau pidfd, menyimpan referensi kernel ke task tertentu, sehingga operasi berikutnya dapat menargetkan task tersebut tanpa melakukan resolusi ulang terhadap PID numeriknya.

Perbedaan ini menghilangkan satu kelas race time-of-check/time-of-use dari pengelolaan proses. pidfd tidak membuat proses tetap hidup, tidak memberi izin tambahan, dan tidak mengubah seluruh operasi proses menjadi API descriptor yang portabel.

Penggunaan ulang PID membentuk batas identitas

Kode yang memeriksa PID lalu memanggil kill(pid, sig) menjalankan dua operasi terhadap nama numerik yang dapat dipakai kembali. Jika proses awal berhenti di antara kedua operasi dan PID tersebut didaur ulang, pemanggilan berikutnya dapat merujuk ke proses yang berbeda.

pidfd_open() mengubah bagian kedua dari model itu. Dengan PID yang masih ada, fungsi ini mengembalikan file descriptor yang terkait dengan task tersebut. Setelah diperoleh, descriptor tetap terikat ke task itu dan tidak mengikuti penggunaan ulang PID numerik di masa berikutnya.

int pidfd = syscall(SYS_pidfd_open, pid, 0);
if (pidfd == -1)
    handle_error();

Untuk child yang baru dibuat, clone() atau clone3() dengan CLONE_PIDFD dapat mengembalikan pidfd sebagai bagian dari proses pembuatan. Jalur ini menghindari interval akuisisi yang muncul ketika pemanggil lebih dulu membuat atau mengenali proses, lalu baru memanggil pidfd_open().

Signaling memakai identitas descriptor

pidfd_send_signal() mengirim signal melalui pidfd. Kernel menentukan target dari descriptor, bukan dari lookup baru terhadap PID numerik.

if (syscall(SYS_pidfd_send_signal, pidfd, SIGTERM, NULL, 0) == -1)
    handle_error();

Jika proses yang dirujuk sudah berhenti dan tidak lagi dapat menerima signal, pemanggilan gagal alih-alih mengarahkan operasi ke proses baru yang kebetulan memiliki PID numerik sama. Pemeriksaan izin signal tetap berlaku.

Sifat ini lebih sempit daripada jaminan lifetime. Memegang pidfd tidak mempertahankan eksekusi task. pidfd mempertahankan identitas target untuk interface yang menerima descriptor tersebut.

Status exit terintegrasi dengan polling descriptor

pidfd proses dapat dipantau dengan poll(), select(), atau epoll(). Tanpa PIDFD_THREAD, readiness berkaitan dengan terminasi proses yang direpresentasikan oleh thread group; implementasi Linux saat ini menampilkan EPOLLIN ketika task menjadi zombie dan EPOLLHUP setelah task di-reap.

struct pollfd pfd = {
    .fd = pidfd,
    .events = POLLIN
};

int rc = poll(&pfd, 1, -1);

Descriptor ini merupakan sumber event, bukan byte stream. read() pada pidfd bukan interface untuk mengambil status exit.

Untuk child process, waitid() menerima P_PIDFD beserta nilai pidfd. Mekanisme ini menggabungkan identitas stabil dengan mekanisme status child yang biasa.

siginfo_t si = {0};

if (waitid(P_PIDFD, pidfd, &si, WEXITED) == -1)
    handle_error();

pidfd untuk proses yang bukan child tetap dapat dipantau untuk exit, tetapi waitid(P_PIDFD, ...) tidak menghapus syarat relasi parent-child pada process waiting.

Referensi thread memiliki mode tersendiri

Linux 6.9 menambahkan PIDFD_THREAD pada pidfd_open(). Dengan flag ini, descriptor merujuk ke thread tertentu, bukan ke proses yang direpresentasikan oleh thread-group leader.

Perbedaan tersebut memengaruhi polling dan signaling. pidfd thread dapat menjadi readable ketika thread itu berhenti walaupun thread lain masih berjalan. pidfd_send_signal() juga dapat menargetkan scope yang direpresentasikan pidfd, dengan flag Linux 6.9 untuk scope thread, thread-group, dan process-group secara eksplisit.

Kode yang membutuhkan lifetime proses, bukan lifetime satu thread, tidak dapat memperlakukan kedua bentuk ini sebagai hal yang sama.

pidfd bukan jalan pintas otorisasi

Identitas descriptor dan otorisasi adalah dua sifat terpisah. Operasi seperti pidfd_send_signal() tetap menerapkan aturan izinnya, sementara interface lain yang menerima pidfd memiliki pemeriksaan masing-masing.

Mengirim pidfd melalui UNIX domain socket dapat memindahkan referensi ke task yang sama, sebagaimana descriptor passing memindahkan objek kernel lain. Penerima tidak otomatis memperoleh hak untuk menjalankan setiap operasi yang secara konsep dapat diterapkan pada task tersebut.

Flag close-on-exec dipasang pada pidfd yang dikembalikan pidfd_open(), sehingga pewarisan tidak disengaja melewati execve() dibatasi kecuali aplikasi sengaja mengubah flag descriptor.

Identitas stabil adalah sifat utama

pidfd menggantikan resolusi PID numerik berulang dengan referensi descriptor yang diperoleh pada satu titik waktu tertentu. Referensi itu dapat digunakan untuk signaling, readiness polling, child waiting, dan sejumlah API proses Linux lainnya.

Jaminan yang relevan adalah stabilitas identitas, bukan keberadaan yang terus berlangsung. Proses dapat berhenti ketika pidfd masih terbuka, lalu setiap operasi melaporkan status atau kegagalan sesuai kontraknya. Batas ini memungkinkan process supervisor memisahkan identitas task yang dituju sebuah operasi dari kondisi apakah task tersebut masih dapat memenuhi operasi itu.