fork()
a vfork()
wrappery v glibc jsou implementovány pomocí clone()
systémové volání. Pro lepší pochopení vztahu mezi fork()
a clone()
, musíme zvážit vztah mezi procesy a vlákny v Linuxu.
Tradičně fork()
by duplikovaly všechny prostředky vlastněné nadřazeným procesem a přiřadily kopii podřízenému procesu. Tento přístup vyžaduje značnou režii, která by mohla být k ničemu, pokud dítě okamžitě zavolá exec()
. V Linuxu fork()
využívá copy-on-write stránky, abyste zdrželi nebo se úplně vyhnuli kopírování dat, která lze sdílet mezi nadřazeným a podřízeným procesem. Jedná se tedy o jedinou režii, která vzniká během normálního fork()
je kopírování rodičovských tabulek stránek a přiřazení jedinečné struktury deskriptoru procesu, task_struct
, pro dítě.
Linux má také výjimečný přístup k vláknům. V Linuxu jsou vlákna pouze obyčejné procesy, které náhodou sdílejí některé zdroje s jinými procesy. Jedná se o radikálně odlišný přístup k vláknům ve srovnání s jinými operačními systémy, jako jsou Windows nebo Solaris, kde procesy a vlákna představují zcela odlišné druhy bestií. V Linuxu má každé vlákno obyčejných task_struct
svůj vlastní, který je náhodou nastaven tak, že sdílí určité zdroje, jako je adresní prostor, s nadřazeným procesem.
flags
parametru clone()
systémové volání obsahuje sadu příznaků, které indikují, které zdroje, pokud nějaké, by měly sdílet nadřazený a podřízený proces. Procesy a vlákna jsou vytvářeny pomocí clone()
, jediným rozdílem je sada příznaků, která je předána clone()
.
Normální fork()
lze implementovat jako:
clone(SIGCHLD, 0);
Tím se vytvoří úloha, která nesdílí žádné zdroje se svým rodičem a je nastavena na odesílání SIGCHLD
signál ukončení rodičovi, když opustí.
Naproti tomu úloha, která sdílí adresní prostor, prostředky souborového systému, deskriptory souborů a obslužné rutiny signálů s nadřazeným prvkem, jinými slovy vlákno , lze vytvořit pomocí:
clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);
vfork()
je zase implementován prostřednictvím samostatného CLONE_VFORK
příznak, který způsobí, že nadřazený proces uspí, dokud jej podřízený proces neprobudí signálem. Podřízený prvek bude jediným vláknem provádění v nadřazeném jmenném prostoru, dokud nezavolá exec()
nebo výstupy. Dítěti není dovoleno zapisovat do paměti. Odpovídající clone()
volání může být následující:
clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)
Implementace sys_clone()
je specifická pro architekturu, ale většina práce se odehrává v do_fork()
definováno v kernel/fork.c
. Tato funkce volá statické clone_process()
, který vytvoří nový proces jako kopii rodiče, ale ještě ho nespustí. clone_process()
zkopíruje registry, přiřadí PID nové úloze a buď duplikuje nebo sdílí příslušné části procesního prostředí, jak je specifikováno klonem flags
. Když clone_process()
vrátí, do_clone()
probudí nově vytvořený proces a naplánuje jeho spuštění.
Komponenta zodpovědná za překlad funkcí systémových volání userland do systémových volání jádra pod Linuxem je knihovna libc. V GLibC to knihovna NPTL přesměruje na clone(2)
systémové volání.