Как вы предотвращаете наследование файлового дескриптора через системные вызовы fork () (конечно, не закрывая его)?
Я ищу способ пометить дескриптор одного файла как НЕ для наследования (copy-) дочерними объектами fork (), что-то вроде FD_CLOEXEC-подобного хака, но для вилок (так что, если хотите, функция FD_DONTINHERIT).Кто-нибудь делал это?Или посмотрел на это и у меня есть подсказка для начала?
Спасибо
ОБНОВЛЕНИЕ:
Я мог бы использовать libc's __register_atfork
__register_atfork(NULL, NULL, fdcleaner, NULL)
, чтобы закрыть fds в child перед возвратом fork ().Тем не менее, fds все еще копируются, так что это звучит глупо для меня.Вопрос в том, как пропустить dup () - в дочернем элементе ненужных fds
. Я думаю о некоторых сценариях, когда потребуется fcntl (fd, F_SETFL, F_DONTINHERIT):
fork () скопирует событие fd (например, epoll);иногда это не нужно, например, FreeBSD помечает событие kqueue () fd как KQUEUE_TYPE, и эти типы fds не будут копироваться на вилки (fque kqueue пропускается явно из-за копирования, если кто-то хочетиспользуйте его от дочернего элемента, он должен быть разветвлен с общей таблицей fd)
fork () скопирует 100 000 ненужных fds для разветвления дочернего элемента для выполнения некоторых ресурсоемких задач (предположим, что требуетсяfork () очень маловероятно, и программисту не захочется поддерживать пул дочерних элементов для чего-то, что обычно не происходит)
Некоторые дескрипторы, которые мы хотим скопировать (0,1,2), некоторые (большинство из них?) Нет.Я думаю, что полное дублирование fdtable здесь по историческим причинам, но я, вероятно, ошибаюсь.
Как глупо звучит этот звук:
- патч fcntl для поддержки флага dontinherit в файловых дескрипторах (не уверен, следует ли хранить флаг per-fd или в fdtable fd_set, например, флаги close-on-exec сохраняются
- , изменяют dup_fd () в ядре, чтобы пропустить копирование dontinherit fds, так же, как и freebsd для 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;
}
курса, не могу считать это реальной скамейкой, но так или иначе:
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® Core ™ 2 Duo T7500 @ 2,20 ГГц с 4 ГБ ОЗУ; средняя загрузка = 0,00