Вызов вилки перед основным
Позволяет ли стандарт POSIX вызывать fork()
до main()
- например, в экземпляре С++ static
или в функции __attribute__((constructor))
C?
Ответы
Ответ 1
В управляющей странице fork
нет указаний, которые запрещены, и я не могу думать о причине, чтобы это было.
В самом деле, нет ничего особенного в отношении main
в отношении POSIX; это просто, что C решает начать свои программы в функции с этим именем, а С++ почти почти то же самое. Но что касается POSIX, то, как только ваш процесс завершен, ваш процесс завершен. Это могло быть написано на любом старом языке, и fork
все равно придется работать.
В C (не С++!) Это невозможно для вас, чтобы написать код, который выполняется перед main
(потому что инициализаторов для static
переменные должны быть постоянными в этом контексте), так что для C это немного спорный вопрос, Однако, выходя за пределы абстракции C на мгновение, в POSIX по-прежнему нет ничего, что помешало бы вашему компилятору включить код во время выполнения C, который выполняет fork
перед входом main
. Напомним, что "истинная" точка входа на самом деле не является main
; "истинная" точка входа выполняет некоторые инициализации библиотеки и еще до вызова main
, чтобы начать вашу часть программы.
Ответ 2
Позволяет ли стандарт POSIX вызывать fork()
до main()
[...]?
Это зависит от того, что вы имеете в виду.
Программы C
POSIX посредством включения стандарта C указывает, что запуск программы C происходит, когда среда (операционная система) вызывает main()
. Определенная POSIX семантика программы C начинается с этой точки; по определению, они не включают предварительные вызовы любой другой функции. Если такие вызовы действительно происходят, то они не являются частью "программы" в этом смысле, поэтому программа не может вызывать fork()
до main()
.
С другой стороны, POSIX явно не запрещает процесс, в котором программа C запускает выполнение fork()
или любую другую функцию до начала определенной семантики C. В том смысле, что то, что запрещено, разрешено POSIX. Если ваш вопрос о том, нарушают ли GCC __attribute__((constructor))
или подобные объекты POSIX, то нет, они не делают, хотя их поведение не определяется POSIX.
С другой стороны, POSIX не дает утвердительного разрешения и не указывает, каким образом исходный код C указывает, что это должно произойти. Если ваш вопрос касается того, определяет ли POSIX конкретное средство, которое __attribute__((constructor))
или аналогичные средства используют для обеспечения своего рекламируемого поведения, или требует ли оно, чтобы соответствующие системы должны обеспечивать механизм, с помощью которого такие объекты могут работать, тогда нет, это не, Не предоставление такого механизма не по своей сути приведет к тому, что система не сможет соответствовать POSIX.
Программы на С++
POSIX определяется в терминах командного языка оболочки и ISO C. Он не требует реализаций для поддержки любой поддержки на С++, но, конечно же, это не запрещает. Таким образом, второй и третий параграфы предыдущего раздела относятся ко всем аспектам программ на С++.
Для того, что стоит, однако, как C, С++ указывает, что программы начинаются с main()
. Это имеет аналогичный смысл в С++, как в C, но в отличие от C, С++-реализации могут предоставить механизмы, с помощью которых пользовательский код может быть запущен до первого оператора main()
. В частности, конструктор переменной со статической продолжительностью может работать до того, как будет выполнен первый оператор main()
, но независимо от того, выполняет ли он его выполнение (С++ 11, 3.6.2/4). Поэтому в этом смысле определяется реализация, независимо от того, может ли семантика программы С++ включать вызов fork()
перед первым выражением main()
.
Обратите также внимание на то, что стандарт С++ тщательно формулируется, чтобы не говорить о том, могут ли такие инициализации быть до ввода main()
- это, вероятно, несущественно, но есть, по крайней мере, несколько способов, в которых можно было бы сказать разница.
Другие программы
POSIX еще меньше говорит о других видах программ, чем о программах на С++, за исключением сценариев оболочки. Конечно, сценарии оболочки вообще не имеют main()
вообще, и у них нет прямого доступа к библиотеке C, для которой явно fork()
.
Ответ 3
Вы можете использовать fork с момента полной загрузки и инициализации libc.
Простая тестовая программа может показать, что это верно:
#include <stdio.h>
void before(void) __attribute__ (( constructor ));
void after(void) __attribute__ (( destructor ));
int main(void)
{
puts("main");
return 0;
}
void before(void)
{
puts("before");
}
void after(void)
{
puts("after");
}
Вывод:
$ LD_DEBUG=files ./a.out
26032:
26032: file=libc.so.6 [0]; needed by ./a.out [0]
26032: file=libc.so.6 [0]; generating link map
26032: dynamic: 0x00007f58c7703ba0 base: 0x00007f58c7341000 size: 0x00000000003c8a00
26032: entry: 0x00007f58c7361950 phdr: 0x00007f58c7341040 phnum: 10
26032:
26032:
26032: calling init: /lib/x86_64-linux-gnu/libc.so.6
26032:
26032:
26032: initialize program: ./a.out
26032:
before
26032:
26032: transferring control: ./a.out
26032:
main
26032:
26032: calling fini: ./a.out [0]
26032:
after
Загружена библиотека, выполнена инициализация, поэтому она должна быть безопасной для использования fork с функцией тегов с конструктором.