PIDFD_OPEN - Linux手册页

时间:2019-08-20 17:59:07  来源:igfitidea点击:

Linux程序员手册 第2部分
更新日期: 2020-08-13

名称

pidfd_open-获取引用进程的文件描述符

语法

#include <sys/types.h>

int pidfd_open(pid_t pid, unsigned int flags);

说明

pidfd_open()系统调用创建一个文件描述符,该文件描述符引用其PID在pid中指定的进程。文件描述符作为函数结果返回;在文件描述符上设置close-on-exec标志。

flags参数保留供将来使用。当前,此参数必须指定为0。

返回值

成功后,pidfd_open()返回文件描述符(非负整数)。发生错误时,将返回-1并将errno设置为指示错误原因。

错误说明

EINVAL
标志不为0。
EINVAL
pid无效。
EMFILE
已达到打开文件描述符数量的每个进程限制(请参阅getrlimit(2)中RLIMIT_NOFILE的描述)。
ENFILE
已达到系统范围内打开文件总数的限制。
ENODEV
匿名inode文件系统在此内核中不可用。
ENOMEM
内核内存不足。
ESRCH
pid指定的进程不存在。

版本

pidfd_open()最早出现在Linux 5.3中。

遵循规范

pidfd_open()是Linux特定的。

备注

当前,此系统调用没有glibc包装器。使用syscall(2)调用它。

以下代码序列可用于获取fork(2)的子代的文件描述符:

pid = fork();
if (pid > 0) {     /* If parent */
    pidfd = pidfd_open(pid, 0);
    ...
}

即使子进程在pidfd_open()调用之前已经终止,其PID也不会被回收,并且返回的文件描述符将引用生成的僵尸进程。但是请注意,只有在满足以下条件时才能保证:

*
尚未将SIGCHLD的处置明确设置为SIG_IGN(请参见sigaction(2));
*
在为SIGCHLD建立处理程序或将该信号的处置方式设置为SIG_DFL时,未指定SA_NOCLDWAIT标志(请参见sigaction(2));和
*
僵尸进程未在程序中的其他地方收获(例如,通过异步执行的信号处理程序或通过wait(2)或另一个线程中的类似操作)。

如果这些条件中的任何一个不成立,则应使用带有CLONE_PIDFD标志的clone(2)创建子进程(以及引用该子进程的PID文件描述符)。

Use cases for PID file descriptors

pidfd_open()(或带有CLONE_PID标志的clone(2))返回的PID文件描述符可用于以下目的:

*
pidfd_send_signal(2)系统调用可用于将信号发送到PID文件描述符所引用的进程。
*
可以使用poll(2),select(2)和epoll(7)监视PID文件描述符。当它所引用的过程终止时,这些接口会将文件描述符指示为可读的。但是请注意,在当前实现中,无法从文件描述符读取任何内容(文件描述符上的read(2)失败,错误为EINVAL)。
*
如果PID文件描述符引用了调用过程的子进程,则可以使用waitid(2)等待它。
*
pidfd_getfd(2)系统调用可用于获取PID文件描述符所引用的另一个进程的文件描述符的副本。
*
PID文件描述符可以用作setns(2)的参数,以便进入与文件描述符所引用的过程相同的名称空间中的一个或多个。

pidfd_open()系统调用是为已经存在的进程获取PID文件描述符的首选方法。另一种方法是通过打开/ proc / [pid]目录来获取文件描述符。但是,只有在安装了proc(5)文件系统的情况下,后一种技术才可行。此外,以这种方式获得的文件描述符不是可轮询的,无法通过waitid(2)等待。

示例

下面的程序为该进程打开PID文件描述符,该进程的PID被指定为其命令行参数。然后,它使用poll(2)监视文件描述符的进程退出,如EPOLLIN事件所示。

Program source

#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <poll.h>
#include <stdlib.h>
#include <stdio.h>

#ifndef __NR_pidfd_open
#define __NR_pidfd_open 434   /* System call # on most architectures */
#endif

static int
pidfd_open(pid_t pid, unsigned int flags)
{
    return syscall(__NR_pidfd_open, pid, flags);
}

int
main(int argc, char *argv[])
{
    struct pollfd pollfd;
    int pidfd, ready;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
        exit(EXIT_SUCCESS);
    }

    pidfd = pidfd_open(atoi(argv[1]), 0);
    if (pidfd == -1) {
        perror("pidfd_open");
        exit(EXIT_FAILURE);
    }

    pollfd.fd = pidfd;
    pollfd.events = POLLIN;

    ready = poll(&pollfd, 1, -1);
    if (ready == -1) {
        perror("poll");
        exit(EXIT_FAILURE);
    }

    printf("Events (0x%x): POLLIN is %sset\n", pollfd.revents,
            (pollfd.revents & POLLIN) ? "" : "not ");

    close(pidfd);
    exit(EXIT_SUCCESS);
}

另外参见

clone(2),kill(2),pidfd_getfd(2),pidfd_send_signal(2),poll(2),select(2),setns(2),waitid(2),epoll(7)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/