KCMP - Linux手册页
Linux程序员手册 第2部分
更新日期: 2020-06-09
名称
kcmp-比较两个进程以确定它们是否共享内核资源
语法
#include <linux/kcmp.h> int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2);
注意:此系统调用没有glibc包装器。请参阅注释。
说明
kcmp()系统调用可用于检查pid1和pid2标识的两个进程是否共享内核资源,例如虚拟内存,文件描述符等。
使用kcmp()的权限由ptrace访问模式PTRACE_MODE_READ_REALCREDS对pid1和pid2进行检查来控制;参见ptrace(2)。
类型参数指定在两个进程中要比较的资源。它具有以下值之一:
- KCMP_FILE
- 检查进程pid1中的文件描述符idx1是否引用与进程pid2中的文件描述符idx2相同的打开文件描述(请参阅open(2))。 dup(2)(和类似的结果)fork(2)或通过域套接字传递文件描述符(参见unix(7))的结果可能是存在两个引用同一打开文件描述的文件描述符。
- KCMP_FILES
- 检查进程是否共享同一组打开文件描述符。参数idx1和idx2被忽略。请参阅对clone(2)中的CLONE_FILES标志的讨论。
- KCMP_FS
- 检查进程是否共享相同的文件系统信息(即文件模式创建掩码,工作目录和文件系统根目录)。参数idx1和idx2被忽略。请参阅对clone(2)中的CLONE_FS标志的讨论。
- KCMP_IO
- 检查进程是否共享I / O上下文。参数idx1和idx2被忽略。请参阅对clone(2)中CLONE_IO标志的讨论。
- KCMP_SIGHAND
- 检查进程是否共享相同的信号处理表。参数idx1和idx2被忽略。请参阅对clone(2)中的CLONE_SIGHAND标志的讨论。
- KCMP_SYSVSEM
- 检查进程是否共享相同的System V信号量撤消操作列表。参数idx1和idx2被忽略。请参阅对clone(2)中的CLONE_SYSVSEM标志的讨论。
- KCMP_VM
- 检查进程是否共享相同的地址空间。参数idx1和idx2被忽略。请参阅对clone(2)中的CLONE_VM标志的讨论。
- KCMP_EPOLL_TFD(since Linux 4.13)
- 检查进程pid2的idx2描述的epoll(7)实例中是否存在进程pid1的文件描述符idx1。参数idx2是指向描述目标文件的结构的指针。该结构的形式为:
struct kcmp_epoll_slot { __u32 efd; __u32 tfd; __u64 toff; };
在此结构中,efd是从epoll_create(2)返回的epoll文件描述符,tfd是目标文件描述符编号,并且toff是从零开始计数的目标文件偏移量。可以使用相同的文件描述符编号注册多个不同的目标,并且设置特定的偏移量有助于调查每个目标。
请注意,如果进程当前正在运行,则不会保护kcmp()免受误报。在通过此系统调用进行检查之前,应通过发送SIGSTOP(请参见signal(7))来停止进程,以获得有意义的结果。
返回值
成功调用kcmp()的返回值只是内核指针的算术比较的结果(当内核比较资源时,它将使用其内存地址)。
解释的最简单方法是考虑一个例子。假设v1和v2是适当资源的地址,则返回值为以下之一:
- 0
- v1等于v2;换句话说,两个进程共享资源。
- 1
- v1小于v2。
- 2
- v1大于v2。
- 3
- v1不等于v2,但是订购信息不可用。
如果出错,则返回-1,并正确设置errno。
kcmp()设计为返回适合排序的值。如果需要比较大量的文件描述符,这特别方便。
错误说明
版本
kcmp()系统调用首先出现在Linux 3.5中。
遵循规范
kcmp()是特定于Linux的,不应在旨在可移植的程序中使用。
备注
Glibc不为该系统调用提供包装器;使用syscall(2)调用它。
仅当内核配置了CONFIG_CHECKPOINT_RESTORE时,此系统调用才可用。系统调用的主要用途是用于用户空间中的检查点/还原(CRIU)功能。该系统调用的替代方法是通过proc(5)文件系统公开合适的过程信息;出于安全原因,这被认为是不合适的。
有关此页面上引用的共享资源的一些背景信息,请参见clone(2)。
示例
下面的程序使用kcmp()测试文件描述符对是否引用相同的打开文件描述。程序将测试文件描述符对的不同情况,如程序输出中所述。该程序的示例运行如下:
$ ./a.out Parent PID is 1144 Parent opened file on FD 3 PID of child of fork() is 1145 Compare duplicate FDs from different processes: kcmp(1145, 1144, KCMP_FILE, 3, 3) ==> same Child opened file on FD 4 Compare FDs from distinct open()s in same process: kcmp(1145, 1145, KCMP_FILE, 3, 4) ==> different Child duplicated FD 3 to create FD 5 Compare duplicated FDs in same process: kcmp(1145, 1145, KCMP_FILE, 3, 5) ==> same
Program source
#define _GNU_SOURCE #include <sys/syscall.h> #include <sys/wait.h> #include <sys/stat.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <linux/kcmp.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { return syscall(SYS_kcmp, pid1, pid2, type, idx1, idx2); } static void test_kcmp(char *msg, id_t pid1, pid_t pid2, int fd_a, int fd_b) { printf("\t%s\n", msg); printf("\t\tkcmp(%ld, %ld, KCMP_FILE, %d, %d) ==> %s\n", (long) pid1, (long) pid2, fd_a, fd_b, (kcmp(pid1, pid2, KCMP_FILE, fd_a, fd_b) == 0) ? "same" : "different"); } int main(int argc, char *argv[]) { int fd1, fd2, fd3; char pathname[] = "/tmp/kcmp.test"; fd1 = open(pathname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (fd1 == -1) errExit("open"); printf("Parent PID is %ld\n", (long) getpid()); printf("Parent opened file on FD %d\n\n", fd1); switch (fork()) { case -1: errExit("fork"); case 0: printf("PID of child of fork() is %ld\n", (long) getpid()); test_kcmp("Compare duplicate FDs from different processes:", getpid(), getppid(), fd1, fd1); fd2 = open(pathname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (fd2 == -1) errExit("open"); printf("Child opened file on FD %d\n", fd2); test_kcmp("Compare FDs from distinct open()s in same process:", getpid(), getpid(), fd1, fd2); fd3 = dup(fd1); if (fd3 == -1) errExit("dup"); printf("Child duplicated FD %d to create FD %d\n", fd1, fd3); test_kcmp("Compare duplicated FDs in same process:", getpid(), getpid(), fd1, fd3); break; default: wait(NULL); } exit(EXIT_SUCCESS); }
另外参见
克隆(2),取消共享(2)
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。