Quando si chiama vfork()
, viene creato un nuovo processo e quel nuovo processo prende in prestito l'immagine del processo del processo padre, ad eccezione dello stack. Al processo figlio viene assegnata una nuova stella dello stack, tuttavia ciò non consente return
dalla funzione che ha chiamato vfork()
.
Mentre il bambino è in esecuzione, il processo padre viene bloccato, poiché il bambino ha preso in prestito lo spazio degli indirizzi del padre.
Indipendentemente da ciò che fai, tutto ciò che accede allo stack modifica solo lo stack privato del bambino. Se tuttavia si modificano i dati globali, questo modifica i dati comuni e quindi influisce anche sul genitore.
Le cose che modificano i dati globali sono ad esempio:
chiamando malloc () o free ()
usando stdio
modifica delle impostazioni del segnale
modifica delle variabili che non sono locali alla funzione che ha chiamato vfork()
.
...
Una volta chiamato _exit()
(importante, non chiamare mai exit()
), il figlio termina e il controllo viene restituito al genitore.
Se chiamate una funzione dalla exec*()
famiglia, viene creato un nuovo spazio indirizzo con un nuovo codice programma, nuovi dati e una parte dello stack dal genitore (vedi sotto). Una volta che questo è pronto, il bambino non prende più in prestito lo spazio degli indirizzi dal bambino, ma utilizza un proprio spazio degli indirizzi.
Il controllo viene restituito al genitore, poiché lo spazio degli indirizzi non è più utilizzato da un altro processo.
Importante: su Linux non esiste vfork()
un'implementazione reale . Linux implementa piuttosto in vfork()
base al fork()
concetto Copy on Write introdotto da SunOS-4.0 nel 1988. Per far credere agli utenti che usano vfork()
, Linux imposta semplicemente i dati condivisi e sospende il genitore mentre il bambino non ha chiamato _exit()
o una delle exec*()
funzioni.
Linux quindi non beneficia del fatto che un vero vfork()
non ha bisogno di impostare una descrizione dello spazio degli indirizzi per il figlio nel kernel. Ciò si traduce in un vfork()
che non è più veloce di fork()
. Sui sistemi che implementano un reale vfork()
, è in genere 3 volte più veloce di fork()
e influisce sulle prestazioni delle shell che usano vfork()
- ksh93
, il recente Bourne Shell
e csh
.
Il motivo per cui non dovresti mai chiamare exit()
dal vfork()
figlio ed è che exit()
scarica lo stdio nel caso in cui ci siano dati non scaricati dal momento prima di chiamare vfork()
. Ciò potrebbe causare strani risultati.
A proposito: posix_spawn()
è implementato sopra vfork()
, quindi vfork()
non verrà rimosso dal sistema operativo. È stato menzionato che Linux non usa vfork()
per posix_spawn()
.
Per lo stack, c'è poca documentazione, ecco cosa dice la pagina man di Solaris:
The vfork() and vforkx() functions can normally be used the
same way as fork() and forkx(), respectively. The calling
procedure, however, should not return while running in the
child's context, since the eventual return from vfork() or
vforkx() in the parent would be to a stack frame that no
longer exists.
Quindi l'implementazione può fare qualunque cosa gli piaccia. L'implementazione di Solaris utilizza la memoria condivisa per il frame dello stack della funzione che chiama vfork()
. Nessuna implementazione garantisce l'accesso alle parti più vecchie dello stack dal genitore.