Предотвращение наследования файловых дескрипторов во время ветвления Linux

Как предотвратить копирование файлового дескриптора через системные вызовы fork () (не закрывая его, конечно )?

Я ищу способ пометить один файловый дескриптор как НЕ (copy-) унаследовано дочерними элементами в fork (), что-то вроде взлома, подобного FD_CLOEXEC, но для вилок (так что функция FD_DONTINHERIT, если хотите). Кто-нибудь это сделал? Или заглянул в это и у меня есть подсказка для начала?

Спасибо

ОБНОВЛЕНИЕ:

Я мог бы использовать libc __register_atfork

 __register_atfork(NULL, NULL, fdcleaner, NULL)

, чтобы закрыть fds в дочернем элементе непосредственно перед возвратом fork () . Тем не менее, fds все еще копируются, так что для меня это звучит глупо. Вопрос в том, как пропустить dup () - ing в дочернем элементе ненужных fds

Я думаю о некоторых сценариях, когда потребуется fcntl (fd, F_SETFL, F_DONTINHERIT):

  • fork () скопирует событие fd (например, epoll); иногда это не требуется, например, FreeBSD отмечает событие fd kqueue () как принадлежащее KQUEUE_TYPE, и эти типы файловых файлов не будут копироваться между форками (fds kqueue явно пропускаются из-за копирования, если кто-то хочет использовать его от дочернего элемента, он должен выполнить вилку с общей таблицей fd)

  • fork () скопирует 100k ненужных файлов fd, чтобы выполнить вилку дочернего элемента для выполнения некоторых задач с интенсивным использованием процессора (предположим, что необходимость в fork () вероятностно очень низкий, и программист не захочет поддерживать пул потомков для чего-то, что обычно не происходит)

Некоторые дескрипторы мы хотим копировать (0,1,2), а некоторые (большинство из них?) нет. Я думаю, что полный дублирование fdtable здесь по историческим причинам, но я, вероятно, ошибаюсь.

Как глупо это звучит:

  • патч fcntl для поддержки флага dontinherit в файловых дескрипторах (не уверен, что флаг должны храниться per-fd или в fdtable fd_set, как флаги закрытия при выполнении
  • модифицируйте dup_fd () в ядре, чтобы пропустить копирование dontinherit fds, так же, как freebsd для kq fds

рассмотрите программу

#include 
#include 
#include 
#include 
#include 
#include 

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;
}

, конечно, не могу рассматривать это как настоящий стенд, но в любом случае:

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 T7500 @ 2,20 ГГц с оперативной памятью 4 ГБ; average_load = 0.00

24
задан jww 18 April 2019 в 18:05
поделиться