在Linux fork期间防止文件描述符继承 [英] Prevent file descriptors inheritance during Linux fork

查看:232
本文介绍了在Linux fork期间防止文件描述符继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何防止跨fork()系统调用复制文件描述符(当然,不关闭文件描述符)?

How do you prevent a file descriptor from being copy-inherited across fork() syscalls (without closing it, of course) ?

我正在寻找一种方法来将单个文件描述符标记为不 (复制)由孩子在fork()处继承,类似于类似于FD_CLOEXEC的hack,但用于fork(如果您愿意,可以使用FD_DONTINHERIT功能). 有人这样做吗?或对此进行了调查,并给了我一些提示?

I am looking for a way to mark a single file descriptor as NOT to be (copy-)inherited by children at fork(), something like a FD_CLOEXEC-like hack but for forks (so a FD_DONTINHERIT feature if you like). Anybody did this? Or looked into this and has a hint for me to start with?

谢谢

更新:

我可以使用在fork()返回之前关闭子进程中的fds.但是,fds仍在被复制,因此对我来说这听起来像是个愚蠢的破解.问题是如何跳过不需要的fds的子项中的dup()-

to close the fds in child just before fork() returns. However, the fds are still being copied so this sounds like a silly hack to me. Question is how to skip the dup()-ing in child of unneeded fds

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

I'm thinking of some scenarios when a fcntl(fd,F_SETFL,F_DONTINHERIT) would be needed:

  • fork()将复制事件fd(例如epoll);有时这是不需要的,例如FreeBSD将kqueue()事件fd标记为KQUEUE_TYPE,并且这些fds类型不会跨派复制(如果要复制kqueue fds,则将其显式跳过.从孩子那里使用它,它必须与共享的fd表一起分叉)

  • fork() will copy an event fd (e.g. epoll); sometimes this isn't wanted, for example FreeBSD is marking the kqueue() event fd as being of a KQUEUE_TYPE and these types of fds won't be copied across forks (the kqueue fds are skipped explicitly from being copied, if one wants to use it from a child it must fork with shared fd table)

fork()将复制100k不需要的fds来分叉一个孩子来执行一些CPU密集型任务(假设对fork()的需求很低,并且程序员不希望保留一个孩子池)通常不会发生的事情)

fork() will copy 100k unneeded fds to fork a child for doing some cpu-intensive tasks (suppose the need for a fork() is probabilistically very low and programmer won't want to maintain a pool of children for something that normally wouldn't happen)

一些我们要复制的描述符(0,1,2),有些(其中大多数?)不是.我认为完整的fdtable duping的出现是出于历史原因,但我可能是错的.

Some descriptors we want to be copied (0,1,2), some (most of them?) not. I think full fdtable duping is here for historic reasons but I am probably wrong.

这听起来有多愚蠢:

  • 修补fcntl以支持文件描述符上的 dontinherit 标志(不确定是否应按fd或fdtable fd_set保留该标志,例如保留close-on-exec标志
  • 修改内核中的dup_fd()以跳过 dontinherit fds的复制,就像freebsd对kq fds所做的一样
  • patch fcntl to support the dontinherit flag on file descriptors (not sure if the flag should be kept per-fd or in a fdtable fd_set, like the close-on-exec flags are being kept
  • modify dup_fd() in kernel to skip copying of dontinherit fds, same as freebsd does for kq fds

考虑程序

#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)\n",
        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;
}

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

ofcourse, can't consider this a real bench but anyhow:

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在配备4GB内存,2.20GHz的Dell Inspiron 1520Intel®Core 2 Duo CPU T7500上运行; average_load = 0.00

forkit ran on a Dell Inspiron 1520 Intel(R) Core(TM)2 Duo CPU T7500 @ 2.20GHz with 4GB ram; average_load=0.00

推荐答案

否.自己关闭它们,因为您知道哪些需要关闭.

No. Close them yourself, since you know which ones need to be closed.

这篇关于在Linux fork期间防止文件描述符继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆