èããŠïŒ
çµå±ã®ãšãããæãç¹ç¯ããŠããå Žåã誰ãããããå¿
èŠãšããŸããïŒ
V.V.ãã€ã³ãã¹ããŒã1914

ç§ã¯çµã¿èŸŒã¿ã·ã¹ãã ã®ããã°ã©ãã³ã°ã«æºãã£ãŠããã
forkïŒïŒããã³
vforkïŒïŒã·ã¹ãã ã³ãŒã«ã䜿çšããåé¡ãããããçè§£ããããã«ããã®èšäºãæžãããšã«ããŸããã ãããã®2çªç®ã¯ãã°ãã°äœ¿çšããªãããã«å§ããããŸããã圌ãçç±ã§çŸããããšã¯æããã§ãã
ç¹å®ã®åŒã³åºãã䜿çšããæ¹ãè¯ãçç±ãšçç±ãèŠãŠã¿ãŸãããã
ããŸããšããŠã
ãããžã§ã¯ãã§ã®
vforkïŒïŒ /
forkïŒïŒå®è£
ã®èª¬æãæäŸãã
ãŸã ã ãŸããç§ã®èå³ã¯çµã¿èŸŒã¿ã·ã¹ãã ã§ã®ãããã®åŒã³åºãã®äœ¿çšã«é¢é£ããŠããããããã®å®è£
ã®äž»ãªæ©èœã¯ä»®æ³ã¡ã¢ãªã®äžè¶³ã§ãã ãããããã·ã¹ãã ããã°ã©ãã³ã°ãšçµã¿èŸŒã¿ã·ã¹ãã ã«ç²ŸéããŠããããããã¹ã¯ã®äœæ°ãã¢ããã€ã¹ãæäŸããçµéšãå
±æããã§ãããã
ç«ã®äžã§èª°ãæ°ã«ããŠãã ããã
å®çŸ©ãã€ãŸãããããã®é¢æ°ãå®çŸ©ãããŠããPOSIXæšæºããå§ããŸãã
forkïŒïŒã¯ãããã€ãã®å€æ°ãé€ããããã»ã¹ã®æ£ç¢ºãªã³ããŒãäœæããŸãã æ£åžžã«å®è¡ããããšã颿°ã¯ãŒãã®å€ãåããã»ã¹ã«è¿ããåããã»ã¹ã®æ°ã芪ã«è¿ããŸãïŒãã®åŸãããã»ã¹ã¯ãèªåã®ç掻ããå§ããŸãïŒã
vforkïŒïŒã¯ forkïŒïŒãšããŠå®çŸ©ãããŸãããæ¬¡ã®å¶éããããŸãããã«ãã§äœæãããããã»ã¹ã次ã®ã¢ã¯ã·ã§ã³ã®å°ãªããšã1ã€ãå®è¡ããå Žåã颿°ã®åäœã¯å®çŸ©ãããŸããã
- vforkïŒïŒãåŒã³åºããã颿°ããæ»ããŸãã
- _exitïŒïŒãŸãã¯exec *ïŒïŒä»¥å€ã®é¢æ°ãåŒã³åºããŸãã
- vforkïŒïŒé¢æ°ã«ãã£ãŠè¿ãããå€ãä¿åãããŠãã倿°ä»¥å€ã®ããŒã¿ã倿ŽããŸãã
ãã®ãããªåŒ·ãå¶éãæã€ã·ã¹ãã ã³ãŒã«ãããçç±ãçè§£ããã«ã¯ãããã»ã¹ã®æ£ç¢ºãªã³ããŒãäœã§ããããçè§£ããå¿
èŠããããŸãã
ãã·ã¢èªã®ãã®ãããã¯ã«é¢ããæ€çŽ¢ãšã³ãžã³ã®
æåã®ãªã³ã¯ã®1ã€ã¯ã Linuxã®ããã»ã¹ã¯ããŒã³ãªãã·ã§ã³ã®èª¬æã§ãã äžéšã®ãã©ã¡ãŒã¿ãŒã¯ã芪ããã»ã¹ãšåããã»ã¹ã«å
±éã«ããããšãã§ããŸãã
- ã¢ãã¬ã¹ç©ºéïŒCLONE_VMïŒ;
- ãã¡ã€ã«ã·ã¹ãã æ
å ±ïŒCLONE_FSïŒ;
- éããŠãããã¡ã€ã«ã®ããŒãã«ïŒCLONE_FILESïŒ;
- ã·ã°ãã«ãã³ãã©ãŒããŒãã«ïŒCLONE_SIGHANDïŒ;
- 芪ããã»ã¹ïŒCLONE_PARENTïŒã
POSIXã§ã¯ã
vforkïŒïŒã®å€æ°ã倿Žã§ããŸãããããã¯ãã¯ããŒãã³ã°ãã¢ãã¬ã¹ç©ºéã§ããããšã瀺åããŠããŸãã
ãã®ãªã³ã¯ã¯ä»®å®ã確èªããŸãïŒ
forkïŒïŒãšã¯ç°ãªãã vforkïŒïŒã¯èŠªããã»ã¹ã®ã³ããŒãäœæããŸãããã _exit颿°ãŸãã¯exec颿°ã®ãããããåŒã³åºããããŸã§ã芪ããã»ã¹ãšå
±æãããã¢ãã¬ã¹ç©ºéãäœæããŸãã
芪ããã»ã¹ã¯ãã®æç¹ã§å®è¡ã忢ããŸãã ããããã䜿çšã«é¢ãããã¹ãŠã®å¶éãç¶ããŸã-åããã»ã¹ã¯ã芪ããã»ã¹ãšå
±æãããã°ããŒãã«å€æ°ãäžè¬å€æ°ããã倿Žã§ããŸããã
ã€ãŸãããã®ã¹ããŒãã¡ã³ããtrueã®å Žåã
vforkïŒïŒãåŒã³åºããåŸ
ãäž¡æ¹ã®ããã»ã¹ã§åãããŒã¿ã衚瀺ãããŸãã
å®éšããŠã¿ãŸãããã ãããåœãŠã¯ãŸãå Žåãçæãããããã»ã¹ã®ããŒã¿ã«å ãããã倿Žã¯ã芪ããã»ã¹ã«è¡šç€ºããããã®éãåæ§ã§ãã
ä»®å®ããã§ãã¯ããã³ãŒããstatic int create_process(void) { pid_t pid; int status; int common_variable; common_variable = 0; pid = fork(); if (-1 == pid) { return errno; } if (pid == 0) { common_variable = 1; exit(EXIT_SUCCESS); } waitpid(pid, &status, 0); if (common_variable) { puts("vfork(): common variable has been changed."); } else { puts("fork(): common variable hasn't been changed."); } return EXIT_SUCCESS; } int main(void) { return create_process(); }
ãã®ããã°ã©ã ããã«ãããŠå®è¡ãããšãçµè«ãåŸãããŸãã
forkïŒïŒïŒå
±é倿°ã¯å€æŽãããŠããŸãããforkïŒïŒã
vforkïŒïŒã«çœ®ãæãããšãåºåãå€ãããŸãïŒ
vforkïŒïŒïŒå
±é倿°ã倿ŽãããŸãããå€ãã®äººã¯ãã®ããããã£ã䜿çšããŠããã»ã¹éã§ããŒã¿ã転éããŸããããã®ãããªããã°ã©ã ã®åäœã¯POSIXã«ãã£ãŠå®çŸ©ãããŠããŸããã ããã«ããã
vforkïŒïŒã䜿çšããªãããšããå§ãããŸãã
å®éãéçºè
ãæèçã«å€æ°ã®å€ã倿Žããããšãšãåããã»ã¹ã
vforkïŒïŒãåŒã³åºããã颿°ããæ»ãããšãã§ããªãããšãå¿ãããšãããã¯å¥ã®ããšã§ãïŒããã¯èŠªããã»ã¹ã®ã¹ã¿ãã¯æ§é ãç Žå£ããããã§ã
ïŒ ïŒïŒã ãããŠããã€ãã®ããã«æ
æã«è¡åããããšãããããªãèªèº«ã®å±éºãšãªã¹ã¯ã§ææžåãããŠããªãæ©äŒã䜿çšããŸãã
次ã«ãããã»ã©æçœã§ãªãåé¡ãããã€ã瀺ããŸãã
- ãSecure Programming for Linux and Unix HOWTOã ãšããæ¬ã¯ ãããšãåããã»ã¹ãé«ã¬ãã«èšèªã³ãŒãã®ããŒã¿ã倿ŽããªããŠãããã·ã³ã³ãŒãã®å Žåã¯ããã§ã¯ãªããããããªããšè¿°ã¹ãŠããŸãïŒããšãã°ãé ãããäžæå€æ°ã®åºçŸã®ããïŒã
- ãã®ããã°ã§ã¯ã次ã®è³ªåãåæããŸããvforkïŒïŒããã«ãã¹ã¬ããã¢ããªã±ãŒã·ã§ã³ã§åŒã³åºãããå Žåã¯ã©ããªããŸããïŒ Linuxã§ã®vforkïŒïŒã®å®è£
ãæ€èšããŠãã ãããããã¥ã¢ã«ã§ã¯ã芪ããã»ã¹ã¯åŒã³åºããããšãã«åæ¢ãããšè¿°ã¹ãŠããŸãããå®éã«ã¯çŸåšã®ã¹ã¬ããã§ã®ã¿çºçããŸãïŒãã¡ããå®è£
ã¯ç°¡åã§ãïŒã ããã¯ãåããã»ã¹ãä»ã®ã¹ã¬ãããšäžŠè¡ããŠå®è¡ãç¶ããããšãæå³ããäŸãã°ã芪ããã»ã¹ã®æš©éã倿Žã§ããŸãã ãããŠãããã§ã¯ãã¹ãŠãéåžžã«æªããªããŸããåãã¢ãã¬ã¹ç©ºéã§ç°ãªãæš©éãæã€2ã€ã®ããã»ã¹ãååŸããã»ãã¥ãªãã£ããŒã«ãéããŸãã
ããã§
ã exec *ãã¡ããªãŒã®æ©èœãæ€èšããŸãã
vforkïŒïŒã䜿çšããŠååŸããããã»ã¹ã§åŒã³åºãããšãã§ããã®ã¯ããããïŒ
_exitïŒïŒãã«ãŠã³ãããªãïŒã®ã¿ã§ãã æ°ããã¢ãã¬ã¹ç©ºéãäœæããæå®ããããã¡ã€ã«ããã³ãŒããšããŒã¿ãããŒãããŸãã åæã«ãå€ãã¢ãã¬ã¹ç©ºéã¯æ¬è³ªçã«ç Žå£ãããŸãã
ãã®ããã
forkïŒïŒã䜿çšããŠããã»ã¹ãäœæããŠãã
exec *ïŒïŒãåŒã³åºãã
forkïŒïŒãåŒã³åºããšãã«ã¢ãã¬ã¹ç©ºéãäœæïŒã³ããŒïŒããããšã¯åé·ã§ãããããã¯ããªãæéã®ãããæäœã§ããã
forkãåŒã³åºãã®ã«æéããããå ŽåããããŸã
ïŒïŒ ã ããšãã°ããŠã£ãããã£ã¢ã§ã¯ããã®ç¬éãæã泚ç®ãããŠãããæšæºãšã¯ç°ãªããæ¬¡ã®
ããã«æç€ºãããŠããŸãïŒ
forkïŒïŒæäœã¯ãåçšã«åå¥ã®ã¢ãã¬ã¹ã¹ããŒã¹ãäœæããŸãã åããã»ã¹ã«ã¯ã芪ããã»ã¹ã®ãã¹ãŠã®ã¡ã¢ãªã»ã°ã¡ã³ãã®æ£ç¢ºãªã³ããŒããããŸãã
ãã¡ãããä»®æ³ã¡ã¢ãªãåããã»ãšãã©ã®ææ°ã·ã¹ãã ã§ã¯ãã³ããŒã¯è¡ãããŸãã;芪ããã»ã¹ã®ã¡ã¢ãªã®ãã¹ãŠã®ããŒãžã¯ã
ã³ããŒãªã³ã©ã€ããã©ã°ã§ããŒã¯ãããŠã
ãŸã ã ãã ããããŒãã«ã®éå±€å
šäœã調ã¹ãå¿
èŠããããããã«ã¯æéãããããŸãã
vforkïŒïŒåŒã³åºãã¯
forkïŒïŒãããé«éã§ããããšã倿ããŠã
ãŸã ãããã¯
LinuxManããŒãžã«ãèšèŒãããŠ
ããŸã ã
å¥ã®å®éšãè¡ãããããå®éã«ããã§ããããšã確èªããŸãã åã®äŸãå°ã倿ŽããŸãããµã€ã¯ã«ã远å ããŠ1000åã®ããã»ã¹ãäœæããå
±é倿°ãåé€ããŠç»é¢ã«è¡šç€ºããŸãã
åä¿¡ããã³ãŒãã #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <sys/wait.h> static int create_process(void) { pid_t pid; int status; pid = vfork(); if (-1 == pid) { return errno; } if (pid == 0) { /* child */ exit(EXIT_SUCCESS); } waitpid(pid, &status, 0); return EXIT_SUCCESS; } int main(void) { int i; for (i = 0; i < 1000; i ++) { create_process(); } return EXIT_SUCCESS; }
timeã³ãã³ããå®è¡ããŸãã
forkïŒïŒäœ¿çšæã®åºå | vforkïŒïŒäœ¿çšæã®åºå |
real 0m0.135s user 0m0.000s sys 0m0.052s | real 0m0.028s user 0m0.000s sys 0m0.016s |
æ§ããã«èšã£ãŠããçµæã¯å°è±¡çã§ãã éå§ããéå§ãŸã§ãããŒã¿ã¯ãããã«ç°ãªããŸããã
vforkïŒïŒã¯4ã5åéããªããŸãã
çµè«ã¯æ¬¡ã®ãšããã§ãã
forkïŒïŒã¯ããéãåŒã³åºãã§ããã
vforkïŒïŒãåŒã³åºãããšãã§ããå Žåã¯ã䜿çšããããšããå§ãããŸãã
vforkïŒïŒã¯å®å
šæ§ã®äœãåŒã³åºãã§ãããèªåã§è¶³ãæã¡ãããã®ã§ãããã«å¿ããŠææçŸ©ã«äœ¿çšããå¿
èŠããããŸãã
forkïŒïŒ /
vforkïŒïŒã¯ãããã»ã¹çšã«åå¥ã®ãªãœãŒã¹ïŒinodeããŠãŒã¶ãŒãäœæ¥ãã©ã«ããŒïŒãäœæããå¿
èŠãããå Žåã«äœ¿çšããå¿
èŠããããŸãã
forkïŒïŒã¯ ãå¥ã®ã¢ãã¬ã¹ã¹ããŒã¹ãäœæããå¿
èŠãããå Žåã«æé©ã§ãã ãã ããä»®æ³ã¡ã¢ãªã®ããŒããŠã§ã¢ãµããŒããªãã§å°èŠæš¡ãªããã»ããµãã©ãããã©ãŒã ã«å®è£
ããããšã¯éåžžã«å°é£ã§ãã
èšäºã®2çªç®ã®éšåã«
é²ãåã« ãPOSIXã«ã¯
posix_spawnïŒïŒé¢æ°ãããããšã«æ³šæããŠãã ããã å®éããã®é¢æ°ã«ã¯
vforkïŒïŒãš
execïŒïŒãå«ãŸããŠããããã
forkïŒïŒã®ããã«ã¢ãã¬ã¹ç©ºéãåäœæããªããŠãã
vforkïŒïŒã«é¢é£ããåé¡ãåé¿ã§ããŸãã
次ã«ãMMUããµããŒãããªã
forkïŒïŒ /
vforkïŒïŒã®å®è£
ã«
é²ã¿ãŸãããã
Vforkã®å®è£
ã·ã¹ãã ã«
vforkïŒïŒãå®è£
ãããšãã
vforkïŒïŒã®åŒã³åºãã¯æ¬¡ã®ããã«ãã¹ãã§ãããšæ³å®ããŸããïŒèŠªã¯ã¹ã¿ã³ãã€ã¢ãŒãã«ãªããåããã»ã¹ã¯æåã«
vforkïŒïŒããè¿ããã
_exitïŒïŒãŸãã¯
exec *ïŒïŒé¢æ°ãåŒã³åºããããšãã«èŠªã
åŒã³èµ·ãããŸã ã€ãŸããåå«ã¯èŠªã¹ã¿ãã¯ã§å®è¡ã§ããŸãããä»ã®ã¿ã€ãã®ç¬èªã®ãªãœãŒã¹ïŒiããŒããã·ã°ãã«ã®ããŒãã«ãªã©ïŒã䜿çšã§ããŸãã
ãããžã§ã¯ãå
ã®ããŸããŸãªã¿ã€ãã®ãªãœãŒã¹ã®ã¹ãã¬ãŒãžã¯ã¿ã¹ã¯ïŒ
struct task ïŒã§ãã 䜿çšå¯èœãªã¡ã¢ãªãiããŒãããã®ããã»ã¹ã«å±ããã¹ã¬ããã®ãªã¹ããªã©ãããã»ã¹ã®ãã¹ãŠã®ãªãœãŒã¹ãèšè¿°ããã®ã¯ãã®æ§é ã§ãã ã¿ã¹ã¯ã«ã¯åžžã«ã¡ã€ã³ã¹ã¬ããããããŸã-åæåããããšäœæãããŸãã ç§ãã¡ã®ã·ã¹ãã ã®ã¹ããªãŒã ã¯ãèšç»ã®ãªããžã§ã¯ããšåŒã°ããŸãããã
ã«ã€ããŠã¯ãç§ã®ååã®èšäºã§èª¬æããŠããŸãã ãããŒã¯ã¿ã¹ã¯ã§ã¯ãªãã¹ã¿ãã¯ãå¶åŸ¡ããããã2ã€ã®å®è£
ãªãã·ã§ã³ãæäŸã§ããŸãã
- æ°ããäœæãããã¹ã¬ããã®ã¹ã¿ãã¯ã芪ã¹ã¿ãã¯ã«å€æŽããŸãã
- åãå®è¡ã¹ã¬ããã®ã¿ã¹ã¯ãæ°ããã¿ã¹ã¯ã«ã眮ãæãããŸãã
äœããã®æ¹æ³ã§ãã¿ã¹ã¯ãäœæãããã芪ããç¶æ¿ããå¿
èŠããããŸããä¿¡å·ã®ããŒãã«ãç°å¢å€æ°ãªã©ãè€è£œãããŸãã ãã ããã¢ãã¬ã¹ç©ºéã¯ç¶æ¿ãããŸããã
vforkïŒïŒããã®æ»ãã¯ã芪ããã»ã¹ãšåããã»ã¹ã«å¯ŸããŠ2åè¡ãããŸãã ãã®ãããã©ããã§ã
vforkïŒïŒãåŒã³åºãããã¹ã¿ãã¯ãã¬ãŒã ã®ã¬ãžã¹ã¿ãä¿åããå¿
èŠããããŸãã åããã»ã¹ãå®è¡æã«ãããã®å€ãäžæžãããå¯èœæ§ããããããããã¯ã¹ã¿ãã¯äžã§å®è¡ã§ããŸããã ãã ãã
vforkïŒïŒã·ã°ããã£ã¯ãããã¡ã®ååšãæç€ºããŠããªããããæåã«ã¬ãžã¹ã¿ãã¹ã¿ãã¯ã«ä¿åããããããã芪ã¿ã¹ã¯ã®ã©ããã«ä¿åãããŸãã ã¹ã¿ãã¯ãžã®ã¬ãžã¹ã¿ã®ä¿åã¯ã·ã¹ãã ã³ãŒã«ã䜿çšããŠå®è¡ã§ããŸãããããã䜿çšããã«ç¬èªã«å®è¡ããããšã«ããŸããã åœç¶ã
vforkïŒïŒé¢æ°ã¯ã¢ã»ã³ãã©ãŒã§èšè¿°ãããŠããŸãã
i386ã¢ãŒããã¯ãã£çšã®ã³ãŒãã vfork: subl $28, %esp; pushl %ds; pushl %es; pushl %fs; pushl %gs; pushl %eax; pushl %ebp; pushl %edi; pushl %esi; pushl %edx; pushl %ecx; pushl %ebx; movl PT_END(%esp), %ecx; movl %ecx, PT_EIP(%esp); pushf; popl PT_EFLAGS(%esp); movl %esp, %eax; addl $PT_END+4, %eax; movl %eax, PT_ESP(%esp); push %esp; call vfork_body
ãããã£ãŠãæåã«ã¬ãžã¹ã¿ãã¹ã¿ãã¯ã«ä¿åãããæ¬¡ã«C
çªç®ã®é¢æ°
vfork_bodyïŒïŒãåŒã³åºãããŸãã åŒæ°ãšããŠãã¬ãžã¹ã¿ã®ã»ãããæã€æ§é äœãžã®ãã€ã³ã¿ãæž¡ãããŸãã
i386ã®æ§é ã«èšåããŸããã typedef struct pt_regs { uint32_t ebx; uint32_t ecx; uint32_t edx; uint32_t esi; uint32_t edi; uint32_t ebp; uint32_t eax; uint32_t gs; uint32_t fs; uint32_t es; uint32_t ds; uint32_t trapno; uint32_t err; uint32_t eip; uint32_t cs; uint32_t eflags; uint32_t esp; uint32_t ss; } pt_regs_t;
vfork_bodyïŒïŒã³ãŒãã¯ãã¢ãŒããã¯ãã£çã«ç¬ç«ããŠããŸãã 圌ã¯ã¿ã¹ã¯ãäœæããçµäºã«å¿
èŠãªã¬ãžã¹ã¿ãç¶æãã責任ããããŸãã
颿°ã³ãŒãã¯vfork_bodyïŒïŒã§ãã void __attribute__((noreturn)) vfork_body(struct pt_regs *ptregs) { struct task *child; pid_t child_pid; struct task_vfork *task_vfork; int res; assert(thread_self() == task_self()->tsk_main); child_pid = task_prepare(""); if (0 > child_pid) { ptregs_retcode_err_jmp(ptregs, -1, child_pid); panic("vfork_body returning"); } child = task_table_get(child_pid); task_vfork = task_resource_vfork(child->parent); memcpy(&task_vfork->ptregs, ptregs, sizeof(task_vfork->ptregs)); res = vfork_child_start(child); if (res < 0) { vfork_child_done(child, vfork_body_exit_stub, &res); ptregs_retcode_err_jmp(&task_vfork->ptregs, -1, -res); } panic("vfork_body returning"); }
ã³ãŒãã®ç°¡åãªèª¬æã
æåã«ããã«ãã¹ã¬ããããã§ãã¯ãããŸãïŒ
vforkïŒïŒã䜿çšããå Žåã®ãã«ãã¹ã¬ããã«é¢é£ããåé¡ã¯äžèšã§èª¬æããŸããïŒã 次ã«ãæ°ããã¿ã¹ã¯ãäœæãããæåãããšã
vforkïŒïŒããæ»ãããã®ã¬ãžã¹ã¿ããã®ã¿ã¹ã¯ã«æ ŒçŽãããŸãã
ãã®åŸã
vfork_child_startïŒïŒé¢æ°ã
åŒã³åºãããŸã ãããã¯ãååã瀺ãããã«ãåããã»ã¹ããéå§ãããŸãã ããã§ã®åŒçšã¯å¶ç¶ã§ã¯ãããŸãããå®éãã¿ã¹ã¯ã¯åŸã§èµ·åã§ããããããããžã§ã¯ãã«2ã€ããç¹å®ã®å®è£
ã«ãã¹ãŠäŸåããŸãã 説æã«é²ãåã«ã颿°
_exitïŒïŒããã³
exec *ïŒïŒãæ€èšããŠãã ããã
åŒã³åºããããšã芪ã¹ã¬ããã¯ããã¯è§£é€ãããªããã°ãªããŸããã ãã®æç¹ã§ãåããã»ã¹ãã·ã¹ãã å
ã®å¥ã®ãšã³ãã£ãã£ãšããŠéå§ãããŸãã
execvæ©èœã³ãŒã int execv(const char *path, char *const argv[]) { struct task *task; task = task_self(); task_resource_exec(task, path, argv); vfork_child_done(task, task_exec_callback, NULL); return 0; }
exec *ãã¡ããªãŒã®ä»ã®æ©èœã¯ã
execvïŒïŒã®åŒã³åºããéããŠè¡šçŸãããŸãã
æ©èœã³ãŒã_exitïŒïŒ void _exit(int status) { struct task *task; task = task_self(); vfork_child_done(task, task_exit_callback, (void *)status); task_start_exit(); { task_do_exit(task, TASKST_EXITED_MASK | (status & TASKST_EXITST_MASK)); kill(task_get_id(task_get_parent(task)), SIGCHLD); } task_finish_exit(); panic("Returning from _exit"); }
ããããäžèšã®ã³ãŒããããããããã«ã芪ããã»ã¹ã®ããã¯ãè§£é€ããããã«
vfork_child_doneïŒïŒé¢æ°ã䜿çšããããã©ã¡ãŒã¿ãŒã®1ã€ãšããŠãã³ãã©ãŒã瀺ãããŸãã ç¹å®ã®äœæ¥ã¢ã«ãŽãªãºã ãå®è£
ããã«ã¯ã以äžãå®è£
ããå¿
èŠããããŸãã
- vfork_child_startïŒïŒ -ã¯ããŒã³äœæããã»ã¹ã®éå§æã«åŒã³åºããã颿°ã¯ã芪ããã»ã¹ããããã¯ããå¿
èŠããããŸãã
- vfork_child_doneïŒïŒ -åããã»ã¹ã®æçµèµ·åæã«åŒã³åºããã颿°ã芪ããã»ã¹ã¯ããã¯è§£é€ãããŠããŸãã
- task_exit_callbackïŒïŒ -åããã»ã¹ãå®äºãããã³ãã©ã
- task_exec_callbackïŒïŒ -åããã»ã¹ãå®å
šã«èµ·åãããã³ãã©ãŒã
æåã®å®è£
æåã®å®è£
ã®èãæ¹ã¯ãåãã¹ã¿ãã¯ã«å ããŠåãå¶åŸ¡ãããŒã䜿çšããããšã§ãã å®éããã®å Žåã
vfork_child_doneïŒïŒãåŒã³åºããããšãã«åã¿ã¹ã¯ãå®å
šã«éå§ããããŸã§ãçŸåšã®ã¹ã¬ããã®ã¿ã¹ã¯ãåãšã眮æãããã ãã§ãã
Vfork_child_startïŒïŒé¢æ°ã³ãŒã int vfork_child_start(struct task *child) { thread_set_task(thread_self(), child); task_vfork_start(child); ptregs_retcode_jmp(&task_resource_vfork(child->parent)->ptregs, 0); panic("vfork_child_start returning"); return -1; }
次ã®ããšãèµ·ãããŸãïŒå®è¡ã®çŸåšã®ã¹ã¬ããïŒã€ãŸãã芪ïŒã¯
thread_set_taskïŒïŒé¢æ°ã«ãã£ãŠçæãããããã»ã¹ã«
ã¢ã¿ãããããŸã-çŸåšã®ã¹ã¬ããã®æ§é å
ã®å¯Ÿå¿ãããã€ã³ã¿ãŒã倿Žããã ãã§ãã ããã¯ãã¿ã¹ã¯ã«é¢é£ä»ãããããªãœãŒã¹ã«ã¢ã¯ã»ã¹ãããšãã«ãã¹ã¬ãããã¿ã¹ã¯ã以åã®ããã«èŠªã§ã¯ãªãåãšããŠåç
§ããããšãæå³ããŸãã ããšãã°ãã¹ã¬ãããã©ã®ã¿ã¹ã¯ã«å±ããŠãããã確èªããããšãããšïŒ
task_selfïŒïŒé¢æ°ïŒãåã¿ã¹ã¯ãåãåããŸãã
ãã®åŸãåã¿ã¹ã¯ã¯
vforkã®çµæãšããŠäœææžã¿ãšããŠããŒã¯ãããŸã
ãvfork_child_doneïŒïŒé¢æ°ãå¿
èŠã«å¿ããŠå®è¡ãããããã«ããã®ãã©ã°ãå¿
èŠã«ãªããŸãïŒããã«ã€ããŠã¯åŸã§èª¬æããŸãïŒã
次ã«ã
vforkïŒïŒãåŒã³åºããããšãã«ä¿åãããã¬ãžã¹ã¿ãä¿å
ãããŸãã POSIXã«ãããšã
vforkïŒïŒåŒã³åºãã¯åããã»ã¹ã«ãŒãã®å€ãè¿ãå¿
èŠãããããšãæãåºããŠãã ãããããã¯
ptregs_retcode_jmpïŒptregsã0ïŒåŒã³åºãã§èµ·ããããšã§ãã
æ¢ã«è¿°ã¹ãããã«ãåããã»ã¹
ã _exitïŒïŒãŸãã¯
execvïŒïŒé¢æ°ãåŒã³åºããšãã
vfork_chlid_doneïŒïŒé¢æ°ã¯èŠªã¹ã¬ãããããã¯è§£é€ããå¿
èŠããããŸãã ããã«ãç®çã®ãã³ãã©ãŒãå®è¡ããããã®åã¿ã¹ã¯ãæºåããå¿
èŠããããŸãã
Vfork_child_doneïŒïŒé¢æ°ã³ãŒã void vfork_child_done(struct task *child, void * (*run)(void *), void *arg) { struct task_vfork *vfork_data; if (!task_is_vforking(child)) { return; } task_vfork_end(child); task_start(child, run, NULL); thread_set_task(thread_self(), child->parent); vfork_data = task_resource_vfork(child->parent); ptregs_retcode_jmp(&vfork_data->ptregs, child->tsk_id); }
ãã³ãã©ãŒã³ãŒãtask_exit_callbackïŒïŒ void *task_exit_callback(void *arg) { _exit((int)arg); return arg; }
ãã³ãã©ãŒã³ãŒãtask_exec_callbackïŒïŒ void *task_exec_callback(void *arg) { int res; res = exec_call(); return (void*)res; }
vfork_child_doneïŒïŒãåŒã³åºããšãã¯
ã vfork ïŒïŒãªãã§
execïŒïŒ /
_exitïŒïŒã䜿çšããå Žåãèæ
®ããå¿
èŠããããŸãã芪ã®ããã¯ãè§£é€ããå¿
èŠããªããããçŸåšã®é¢æ°ãçµäºããã ãã§ãããã«åãèµ·åã§ããŸãã ããã»ã¹ã
vforkïŒïŒã䜿çšããŠäœæãããå Žåãæ¬¡ã®ããšãçºçããŸããæåã«ã
task_vfork_endïŒïŒã䜿çšããŠ
is_vforkingãã©ã°ãåã¿ã¹ã¯ãã
åé€ãããæåŸã«åã¿ã¹ã¯ã®ã¡ã€ã³ã¹ã¬ãããéå§ããŸãã
run颿°ã¯ãšã³ããªãã€ã³ããšããŠæå®ãããŸããããã¯ãåè¿°ã®ãã³ãã©ãŒïŒ
task_exec_callback ã
task_exit_callback ïŒã®ããããã§ããå¿
èŠããããŸã
ãvfork ïŒïŒãå®è£
ããå Žåã«å¿
èŠã§ãã ãã®åŸãã¹ã¬ããã¯ã¿ã¹ã¯ã«å±ããŸããåã§ã¯ãªãã芪ãåã³ç€ºãããŸãã æåŸã«ãåããã»ã¹IDãæ»ãå€ãšããŠ
vforkïŒïŒåŒã³åºããã芪ã¿ã¹ã¯ã«æ»ããŸãã ããã¯ã
ptregs_retcode_jmpïŒïŒãåŒã³åºãããšã§è¡ããããšæ¢ã«èšãããŠããŸãã
2çªç®ã®vforkå®è£
2çªç®ã®å®è£
ã®ã¢ã€ãã¢ã¯ãæ°ããã¿ã¹ã¯ãšãšãã«äœæãããæ°ããã¹ã¬ããã§èŠªã¹ã¿ãã¯ã䜿çšããããšã§ãã ããã¯ã芪ã¹ããªãŒã ã«ä»¥åã«ä¿åãããã¬ãžã¹ã¿ãåã¹ããªãŒã ã«åŸ©å
ãããšèªåçã«çºçããŸãã ãã®å Žåã
åè¿°ã®èšäºã§èª¬æãããŠ
ããããã«ãã¹ã¬ããéã§å®éã®åæã䜿çšã§ããŸãã ãã¡ãããããã¯ããçŸããã§ããããœãªã¥ãŒã·ã§ã³ãå®è£
ããããšãå°é£ã§ããããã¯ã芪ã¹ã¬ãããåŸ
æ©ããŠãããšãã«ããã®åå«ãåãã¹ã¿ãã¯ã§å®è¡ãããããã§ãã ãã®ãããåŸ
æ©äžã«äžéã¹ã¿ãã¯ã«åãæ¿ããå¿
èŠããããŸããäžéã¹ã¿ãã¯ã§ã¯ã
_exitïŒïŒãŸãã¯
exec *ïŒïŒã®åå«ã«ããåŒã³åºããå®å
šã«åŸ
æ©ã§ããŸãã
2çªç®ã®å®è£
ã®Vfork_child_start颿°ã³ãŒã int vfork_child_start(struct task *child) { struct task_vfork *task_vfork; task_vfork = task_resource_vfork(task_self()); task_vfork->stack = sysmalloc(sizeof(task_vfork->stack)); if (!task_vfork->stack) { return -EAGAIN; } task_vfork->child_pid = child->tsk_id; if (!setjmp(task_vfork->env)) { CONTEXT_JMP_NEW_STACK(vfork_waiting, task_vfork->stack + sizeof(task_vfork->stack)); } task_vfork = task_resource_vfork(task_self()); sysfree(task_vfork->stack); ptregs_retcode_jmp(&task_vfork->ptregs, task_vfork->child_pid); panic("vfork_child_start returning"); return -1; }
ã³ãŒãã®èª¬æïŒ
æåã«ãã¹ã¿ãã¯ã«ã¹ããŒã¹ãå²ãåœãŠããããã®åŸã芪ã¯
vforkïŒïŒããæ»ãããã«ãããå¿
èŠãšãããããåã®
pid ïŒããã»ã¹IDïŒãä¿åãããŸãã
setjmpïŒïŒãåŒã³åºããšã
vforkïŒïŒãåŒã³åºãããã¹ã¿ãã¯äžã®å Žæã«æ»ãããšãã§ããŸãã æ¢ã«è¿°ã¹ãããã«ãåŸ
æ©ã¯äžéã¹ã¿ãã¯ã§å®è¡ããå¿
èŠããããåãæ¿ãã¯
CONTEXT_JMP_NEW_STACKïŒïŒãã¯ãã䜿çšããŠå®è¡ãããŸãããã®ãã¯ãã¯çŸåšã®ã¹ã¿ãã¯ã倿Žããå¶åŸ¡ã
vfork_waitingïŒïŒé¢æ°ã«
æž¡ããŸãã ãã®äžã§ã
vfork_child_doneïŒïŒãåŒã³åºããããŸã§ãåå«ãã¢ã¯ãã£ãåãããç¥å
ããããã¯ãããŸãã
Vfork_waitingã³ãŒã static void vfork_waiting(void) { struct sigaction ochildsa; struct task *child; struct task *parent; struct task_vfork *task_vfork; parent = task_self(); task_vfork = task_resource_vfork(parent); child = task_table_get(task_vfork->child_pid); vfork_wait_signal_store(&ochildsa); { task_vfork_start(parent); task_start(child, vfork_child_task, &task_vfork->ptregs); while (SCHED_WAIT(!task_is_vforking(parent))); } vfork_wait_signal_restore(&ochildsa); longjmp(task_vfork->env, 1); panic("vfork_waiting returning"); }
ã³ãŒããããããããã«ããŸããåããã»ã¹ã®ã·ã°ãã«ããŒãã«ãä¿åãããŸãã å®éã
SIGCHLDã·ã°ãã«ã¯ãªãŒããŒã©ã€ããããŸããããã¯ãåããã»ã¹ã®ã¹ããŒã¿ã¹ã倿Žããããšãã«éä¿¡ãããŸãã ãã®å Žåã芪ã®ããã¯ãè§£é€ããããã«äœ¿çšãããŸãã
æ°ããSIGCHLDãã³ãã©ãŒ static void vfork_parent_signal_handler(int sig, siginfo_t *siginfo, void *context) { task_vfork_end(task_self()); }
ã·ã°ãã«ããŒãã«ã®ä¿åãšåŸ©å
ã¯ãPOSIX call
sigactionïŒïŒã䜿çšããŠè¡ãããŸãã
ãã³ãã©ãŒã®ä¿å static void vfork_wait_signal_store(struct sigaction *ochildsa) { struct sigaction sa; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = vfork_parent_signal_handler; sigemptyset(&sa.sa_mask); sigaction(SIGCHLD, &sa, ochildsa); }
ãã³ãã©ãŒã®å埩 static void vfork_wait_signal_restore(const struct sigaction *ochildsa) { sigaction(SIGCHLD, ochildsa, NULL); }
ã·ã°ãã«ãã³ãã©ã眮ãæããåŸãã¿ã¹ã¯ã¯ã¹ã¿ã³ãã€ã¢ãŒããšããŠããŒã¯ãããŸãããã®ã¢ãŒãã§ã¯ã
_exitïŒïŒ /
exec *ïŒïŒãåŒã³åºããããšãã«ãåã¿ã¹ã¯ã®çŸåšã®èµ·åãŸã§ä¿æãããŸãã 颿°
vfork_child_taskïŒïŒã¯ ãã¿ã¹ã¯ãžã®ãšã³ããªãã€ã³ããšããŠäœ¿çšããã以åã«ä¿åãããã¬ãžã¹ã¿ã埩å
ãã
vforkïŒïŒããæ»ããŸãã
Vfork_child_taskïŒïŒé¢æ°ã³ãŒã static void *vfork_child_task(void *arg) { struct pt_regs *ptregs = arg; ptregs_retcode_jmp(ptregs, 0); panic("vfork_child_task returning"); }
_exitïŒïŒããã³
exec *ïŒïŒãåŒã³åºããããšã
SIGCHLDãéä¿¡ãããã·ã°ãã«ãã³ãã©ãŒã¯ãåãéå§ããã®ãåŸ
ã£ãŠãããšããããŒã¯ãåé€ããŸãã ãã®åŸãå€ã
SIGCHLDã·ã°ãã«ãã³ãã©ã埩å
ãããå¶åŸ¡ã
longjmpïŒïŒã䜿çšããŠ
vfork_child_startïŒïŒé¢æ°ã«æ»ããŸãã ãã®é¢æ°ã®ã¹ã¿ãã¯ãã¬ãŒã ã¯ãåããã»ã¹ã®å®è¡åŸã«ç ŽæãããããããŒã«ã«å€æ°ã«ã¯å¿
èŠãªãã®ãå«ãŸããªãããšã«æ³šæããŠãã ããã 以åã«éžæããã¹ã¿ãã¯ãè§£æŸããåŸãåã¿ã¹ã¯çªå·ã
vforkïŒïŒé¢æ°ããè¿ãããŸãã
vforkã®ããã©ãŒãã³ã¹ã確èªãã
vforkïŒïŒã®æ£ããåäœããã¹ãããããã«
ãããã€ãã®ç¶æ³ãã«ããŒããäžé£ã®ãã¹ããäœæããŸããã
ãã®ãã¡ã®2ã€ã¯ã
_exitïŒïŒããã³
execvïŒïŒãåããã»ã¹
ã«ãã£ãŠåŒã³åºããããšãã«
vforkïŒïŒããã®æ£ããæ»ãããã§ãã¯ããŸãã
æåã®ãã¹ã TEST_CASE("after called vfork() child call exit()") { pid_t pid; pid_t parent_pid; int res; parent_pid = getpid(); pid = vfork(); test_assert(pid != -1); if (pid == 0) { _exit(0); } wait(&res); test_assert_not_equal(pid, parent_pid); test_assert_equal(getpid(), parent_pid); }
äºæ¬¡è©Šéš TEST_CASE("after called vfork() child call execv()") { pid_t pid; pid_t parent_pid; int res; parent_pid = getpid(); pid = vfork(); test_assert(pid != -1); if (pid == 0) { close(0); close(1); close(2); if (execv("help", NULL) == -1) { test_assert(0); } } wait(&res); test_assert_not_equal(pid, parent_pid); test_assert_equal(getpid(), parent_pid); }
å¥ã®ãã¹ãã§ã¯ã芪ããã»ã¹ãšåããã»ã¹ã«ããåãã¹ã¿ãã¯ã®äœ¿çšã確èªããŸãã
第äžãã¹ã TEST_CASE("parent should see stack modifications made from child") { pid_t pid; int res; int data; data = 1; pid = vfork(); test_assert(pid != -1); if (pid == 0) { data = 2; _exit(0); } wait(&res); test_assert_equal(data, 2); }
ããããç§ã¯ããã€ãã®å®éã®ããããŠãµãŒãããŒãã£ã®ããã°ã©ã ã§ã®äœæ¥ã®æ£ç¢ºæ§ããã§ãã¯ããããš
æããŸãããããŠãã®ããã«ãæåãª
dropbearããã±ãŒãžã
éžã°ããŸãã ã èšå®ããããšã
forkïŒïŒããã§ãã¯ããèŠã€ãããªãå Žåã¯
vforkïŒïŒã䜿çšã§ããŸãã ããã¯ãããã©ãŒãã³ã¹ãæ¹åããããã§ã¯ãªãã
ucLinuxããµããŒãããããã«è¡ãã
ããšããã«èšããªããã°ãªããŸãã ã
OSã¯ããã«å¿ããŠèšå®ããïŒdropbearãvforkïŒïŒã䜿çšããããã«ïŒãsshã䜿çšããŠäž¡æ¹ã®å®è£
ãšã®æ¥ç¶ãæ£åžžã«ç¢ºç«ãããŸãããã¹ã¯ãªãŒã³ã·ã§ãã PSãŸãããã®ãããžã§ã¯ãã§ã¯ãMMUã䜿çšããã«forkïŒïŒèªäœãå®è£
ããããšãã§ããŸãããçŸæç¹ã§ã¯ãããã«ã€ããŠã®èšäºãå·çãããŠããŸãã