防止 Linux fork 期间文件描述符继承

2024-11-13 08:36:00
admin
原创
181
摘要:问题描述:如何防止文件描述符在fork()系统调用之间被复制继承(当然,不关闭它)?我正在寻找一种方法来将单个文件描述符标记 为不被子进程 (复制) 继承fork(),类似于 FD_CLOEXEC 之类的 hack,但适用于 fork(因此如果您愿意,可以使用 FD_DONTINHERIT 功能)。有人这样做...

问题描述:

如何防止文件描述符在fork()系统调用之间被复制继承(当然,不关闭它)?

我正在寻找一种方法来将单个文件描述符标记 为被子进程 (复制) 继承fork(),类似于 FD_CLOEXEC 之类的 hack,但适用于 fork(因此如果您愿意,可以使用 FD_DONTINHERIT 功能)。有人这样做过吗?或者有人研究过这个并给我一些提示?

谢谢

更新:

我可以使用libc 的 __register_atfork

 __register_atfork(NULL, NULL, fdcleaner, NULL)

在返回之前关闭 child 中的 fds fork()。但是,FD 仍在被复制,所以这对我来说听起来像是一个愚蠢的 hack。问题是如何跳过dup()child 中不需要的 FD 的 -ing。

我正在考虑一些fcntl(fd, F_SETFL, F_DONTINHERIT)需要的情况:

  • fork()将复制事件 FD(例如epoll());有时这并不是想要的,例如 FreeBSD 将 kqueue() 事件 FD 标记为 KQUEUE_TYPE,并且这些类型的 FD 不会在分叉之间复制(明确跳过 kqueue FD 的复制,如果想从子进程使用它,则必须使用共享 FD 表进行分叉)

  • fork()将复制 100k 个不需要的 FD,以便派生一个子进程来执行一些 CPU 密集型任务(假设对 a 的需求fork()概率很低,并且程序员不想为通常不会发生的事情维护一个子进程池)

有些描述符我们希望被复制(0、1、2),有些(大多数?)则不希望被复制。我认为完整的 FD 表复制是出于历史原因,但我可能错了。

这听起来有多傻呢:

  • 补丁程序fcntl()支持文件描述符上的dontinherit标志(不确定该标志是否应保留在每个 FD 中或保留在 FD 表 fd_set 中,就像保留 close-on-exec 标志一样

  • 在内核中进行修改dup_fd()以跳过dontinherit FD 的复制,就像 FreeBSD 对 kq FD 所做的一样

考虑一下这个程序

#include <stdio.h>
#include <unistd.h>
#include <err.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>

static int fds[NUMFDS];
clock_t t1;

static void cleanup(int i)
{
    while(i-- >= 0) close(fds[i]);
}
void clk_start(void)
{
    t1 = clock();
}
void clk_end(void)
{  

    double tix = (double)clock() - t1;
    double sex = tix/CLOCKS_PER_SEC;
    printf("fork_cost(%d fds)=%fticks(%f seconds)
",
        NUMFDS,tix,sex);
}
int main(int argc, char **argv)
{
    pid_t pid;
    int i;
    __register_atfork(clk_start,clk_end,NULL,NULL);
    for (i = 0; i < NUMFDS; i++) {
        fds[i] = open("/dev/null",O_RDONLY);
        if (fds[i] == -1) {
            cleanup(i);
            errx(EXIT_FAILURE,"open_fds:");
        }
    }
    t1 = clock();
    pid = fork();
    if (pid < 0) {
        errx(EXIT_FAILURE,"fork:");
    }
    if (pid == 0) {
        cleanup(NUMFDS);
        exit(0);
    } else {
        wait(&i);
        cleanup(NUMFDS);
    }
    exit(0);
    return 0;
}

当然,不能认为这是一个真正的长凳,但无论如何:

root@pinkpony:/home/cia/dev/kqueue# time ./forkit
fork_cost(100 fds)=0.000000ticks(0.000000 seconds)

real    0m0.004s
user    0m0.000s
sys     0m0.000s
root@pinkpony:/home/cia/dev/kqueue# gcc -DNUMFDS=100000 -o forkit forkit.c
root@pinkpony:/home/cia/dev/kqueue# time ./forkit
fork_cost(100000 fds)=10000.000000ticks(0.010000 seconds)

real    0m0.287s
user    0m0.010s
sys     0m0.240s
root@pinkpony:/home/cia/dev/kqueue# gcc -DNUMFDS=100 -o forkit forkit.c
root@pinkpony:/home/cia/dev/kqueue# time ./forkit
fork_cost(100 fds)=0.000000ticks(0.000000 seconds)

real    0m0.004s
user    0m0.000s
sys     0m0.000s

forkit 在 Dell Inspiron 1520 Intel(R) Core(TM)2 Duo CPU T7500 @ 2.20GHz 和 4GB RAM 上运行;average_load=0.00


解决方案 1:

如果您的fork目的是调用一个exec函数,那么您可以使用fcntlwithFD_CLOEXEC来关闭文件描述符exec

int fd = open(...);
fcntl(fd, F_SETFD, FD_CLOEXEC);

这样的文件描述符将保留下来fork,但不会保留该exec系列的功能。

解决方案 2:

不。你自己关闭它们,因为你知道哪些需要关闭。

解决方案 3:

据我所知,没有标准的方法可以做到这一点。

如果您希望正确实现它,那么最好的方法可能是添加一个系统调用来将文件描述符标记为 close-on-fork,并sys_fork在调用原始系统调用后拦截系统调用(系统调用编号 2)以对这些标志采取行动sys_fork

如果您不想添加新的系统调用,您可能能够拦截sys_ioctl(系统调用编号 54)并只向其添加一个新命令来标记文件描述 close-on-fork。

当然,如果您可以控制应用程序正在做什么,那么最好维护您想要在 fork 时关闭的所有文件描述符的用户级表,然后调用您自己的表myfork。这将 fork,然后通过用户级表关闭那些标记的文件描述符。

那么您不必在 Linux 内核中摆弄,这个解决方案可能仅在您无法控制 fork 进程时才是必要的(例如,如果第三方库正在进行调用fork())。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用