2015-09-10 3 views
1

В реализации GLibC из popen(), он указывает, что функцияPOPEN() реализация, FD протечек и vfork()

POPEN() должен гарантировать, что любые потоки от предыдущего POPEN() вызовы, которые остаются открытыми в родительском процессе закрыты в новом дочернем процессе.

Почему? Если цель состоит в том, чтобы избежать утечек fd, почему бы не просто закрыть все открытые fds?

Выполнение glibc popen() использует fork(). Хотя есть dup2() и close() звонки между fork() и exec(), можно ли заменить fork() на vfork(), чтобы улучшить производительность?

Является ли реализация Linux popen() на основе fork(), а не vfork()? Почему или почему нет)?

Я собираюсь написать двунаправленную версию popen(), которая возвращает два FILE*: один для чтения и один для записи. Как правильно его реализовать? Он должен быть потокобезопасным и не содержать никаких утечек. Лучше, если это быстро.

ответ

1

vfork(2) является устаревшим (удалено из POSIX2008) и fork(2) довольно эффективно, так как он использует методы copy-on-write.

popen(3) не может закрыть все открытые файлы, потому что они не знают их и не могут знать, какие они актуальны. Представьте себе программу, которая получает socket и передает ее файловый дескриптор в качестве аргумента для команды popen (или просто popen("time cat /etc/issue >&9; date","r") ....). Смотрите также fcntl(2) с FD_CLOEXEC, open(2) с O_CLOEXEC, execve(2)

Файловые дескрипторы в рамках всей программы и процесса в масштабах отпугивают ресурсов, и это ее ответственность управлять ими правильно. Вы должны знать, какие fd-s должны быть закрыты в вашем дочернем процессе до execve. Если вы знаете, какая программа execve -d и какие файлы вам нужны, вы можете close все остальные fds (или большинство из них, возможно, с for (int i=STDERR_FILENO+1; i<64; i++) (void) close(i);) до execve.

Если вы кодирования многоразовый библиотеки, документ его политики в отношении файловых дескрипторов (и любых других глобальных процессов в масштабах ресурсов) и, возможно, использовать FD_CLOEXEC на любых файловых дескрипторов это получение себя (не в качестве явного аргумента или данные), например для внутреннего использования.

Похоже, вы заново изобретать p2open (тогда вы, вероятно, нужно, чтобы понять детали реализации Вашего FILE в вашей стандартной C библиотеки, либо использовать fdopen(3) с заботой и осторожностью); вы можете найти его реализацию. Помните, что при использовании этого процесса, вероятно, должно быть около event loop (например, выше poll(2) ...), чтобы избежать потенциального тупика (с блокированием родительских и дочерних процессов при чтении).

Вы рассмотрели возможность использования какой-либо существующей инфраструктуры цикла событий (например, libevent, libev, glib от GTK и т. Д.)?

BTW Linux имеет несколько версий free software для своих C standard library. GNU libc довольно распространен, но есть musl-libc и несколько других. Изучите исходный код вашего libc.

+1

Является ли vfork() более быстрой версией fork()? vfork() не нужно копировать таблицы страниц родительского процесса. Когда родительский процесс использует много памяти, fork() может вызвать ошибку OOM, если только ОС не настроена так, чтобы позволить overcommit памяти. – user3547691

+0

На самом деле, и родительский процесс, использующий * лот * памяти, не должен использовать 'system' или' popen' (но код тщательно использует 'fork' и, возможно, unmapping память раньше) ... Лучше всего иметь достаточно swap которое сегодня нецелесообразно. –

+0

Я не знаю о p2open. Мне не нужен цикл событий, потому что операции чтения и записи выполняются в отдельных потоках. – user3547691