1.剖析Linux内核源码解读之《实现fork研究(一)》
2.cloneåforkè°ç¨çåºå«åèç³»
3.Github上Fork开源代码,源码本地二次开发,源码保持源码同步
4.ForkjoinPool -1
5.linux0.11源码分析-fork进程
剖析Linux内核源码解读之《实现fork研究(一)》
Linux内核源码解析:深入探讨fork函数的源码实现机制(一)
首先,我们关注的源码焦点是fork函数,它是源码Linux系统创建新进程的核心手段。本文将深入剖析从用户空间应用程序调用glibc库,源码个人展示源码直至内核层面的源码具体过程。这里假设硬件平台为ARM,源码使用Linux内核3..3和glibc库2.版本。源码这些版本的源码库和内核代码可以从ftp.gnu.org获取。
在glibc层面,源码针对不同CPU架构,源码牛年茅台溯源码进入内核的源码步骤有所不同。当glibc准备调用kernel时,源码它会将参数放入寄存器,源码通过软中断(SWI) 0x0指令进入保护模式,最终转至系统调用表。在arm平台上,系统调用表的结构如下:
系统调用表中的CALL(sys_clone)宏被展开后,会将sys_clone函数的地址放入pc寄存器,这个函数实际由SYSCALL_DEFINEx定义。在do_fork函数中,关键步骤包括了对父进程和子进程的6哥源码商城跟踪,以及对子进程进行初始化,包括内存分配和vfork处理等。
总的来说,调用流程是这样的:应用程序通过软中断触发内核处理,通过系统调用表选择并执行sys_clone,然后调用do_fork函数进行具体的进程创建操作。do_fork后续会涉及到copy_process函数,这个函数是理解fork核心逻辑的重要入口,包含了丰富的内核知识。在后续的内容中,我将深入剖析copy_process函数的鸭产品溯源码工作原理。
cloneåforkè°ç¨çåºå«åèç³»
å¨Linuxä¸ä¸»è¦æä¾äºforkãvforkãcloneä¸ä¸ªè¿ç¨å建æ¹æ³ã
é®é¢
å¨linuxæºç ä¸è¿ä¸ä¸ªè°ç¨çæ§è¡è¿ç¨æ¯æ§è¡fork(),vfork(),clone()æ¶ï¼éè¿ä¸ä¸ªç³»ç»è°ç¨è¡¨æ å°å°sys_fork(),sys_vfork(),sys_clone(),åå¨è¿ä¸ä¸ªå½æ°ä¸å»è°ç¨do_fork()å»åå ·ä½çå建è¿ç¨å·¥ä½ã
fork
forkå建ä¸ä¸ªè¿ç¨æ¶ï¼åè¿ç¨åªæ¯å®å ¨å¤å¶ç¶è¿ç¨çèµæºï¼å¤å¶åºæ¥çåè¿ç¨æèªå·±çtask_structç»æåpid,ä½å´å¤å¶ç¶è¿ç¨å ¶å®ææçèµæºãä¾å¦ï¼è¦æ¯ç¶è¿ç¨æå¼äºäºä¸ªæ件ï¼é£ä¹åè¿ç¨ä¹æäºä¸ªæå¼çæ件ï¼èä¸è¿äºæ件çå½å读åæéä¹åå¨ç¸åçå°æ¹ãæ以ï¼è¿ä¸æ¥æåçæ¯å¤å¶ãè¿æ ·å¾å°çåè¿ç¨ç¬ç«äºç¶è¿ç¨ï¼ å ·æè¯å¥½ç并åæ§ï¼ä½æ¯äºè ä¹é´çé讯éè¦éè¿ä¸é¨çé讯æºå¶ï¼å¦ï¼pipeï¼å ±äº«å åçæºå¶ï¼ å¦å¤éè¿forkå建åè¿ç¨ï¼éè¦å°ä¸é¢æè¿°çæ¯ç§èµæºé½å¤å¶ä¸ä¸ªå¯æ¬ãè¿æ ·çæ¥ï¼forkæ¯ä¸ä¸ªå¼éåå大çç³»ç»è°ç¨ï¼è¿äºå¼é并ä¸æ¯ææçæ åµä¸é½æ¯å¿ é¡»çï¼æ¯å¦æè¿ç¨forkåºä¸ä¸ªåè¿ç¨åï¼å ¶åè¿ç¨ä» ä» æ¯ä¸ºäºè°ç¨execæ§è¡å¦ä¸ä¸ªå¯æ§è¡æ件ï¼é£ä¹å¨forkè¿ç¨ä¸å¯¹äºèå空é´çå¤å¶å°æ¯ä¸ä¸ªå¤ä½çè¿ç¨ãä½ç±äºç°å¨Linuxä¸æ¯éåäºcopy-on-write(COWåæ¶å¤å¶)ææ¯ï¼ä¸ºäºéä½å¼éï¼forkæå并ä¸ä¼çç产ç两个ä¸åçæ·è´ï¼å 为å¨é£ä¸ªæ¶åï¼å¤§éçæ°æ®å ¶å®å®å ¨æ¯ä¸æ ·çãåæ¶å¤å¶æ¯å¨æ¨è¿çæ£çæ°æ®æ·è´ãè¥åæ¥ç¡®å®åçäºåå ¥ï¼é£æå³çparentåchildçæ°æ®ä¸ä¸è´äºï¼äºæ¯äº§çå¤å¶å¨ä½ï¼æ¯ä¸ªè¿ç¨æ¿å°å±äºèªå·±çé£ä¸ä»½ï¼è¿æ ·å°±å¯ä»¥éä½ç³»ç»è°ç¨çå¼éãæ以æäºåæ¶å¤å¶åå¢ï¼vforkå ¶å®ç°æä¹å°±ä¸å¤§äºã
fork()è°ç¨æ§è¡ä¸æ¬¡è¿å两个å¼ï¼å¯¹äºç¶è¿ç¨ï¼forkå½æ°è¿ååç¨åºçè¿ç¨å·ï¼è对äºåç¨åºï¼forkå½æ°åè¿åé¶ï¼è¿å°±æ¯ä¸ä¸ªå½æ°è¿å两次çæ¬è´¨ã
å¨forkä¹åï¼åè¿ç¨åç¶è¿ç¨é½ä¼ç»§ç»æ§è¡forkè°ç¨ä¹åçæ令ãåè¿ç¨æ¯ç¶è¿ç¨çå¯æ¬ãå®å°è·å¾ç¶è¿ç¨çæ°æ®ç©ºé´ï¼å åæ çå¯æ¬ï¼è¿äºé½æ¯å¯æ¬ï¼ç¶åè¿ç¨å¹¶ä¸å ±äº«è¿é¨åçå åãä¹å°±æ¯è¯´ï¼åè¿ç¨å¯¹ç¶è¿ç¨ä¸çåååéè¿è¡ä¿®æ¹å¹¶ä¸ä¼å½±åå ¶å¨ç¶è¿ç¨ä¸çå¼ãä½æ¯ç¶åè¿ç¨åå ±äº«ä¸äºä¸è¥¿ï¼ç®å说æ¥å°±æ¯ç¨åºçæ£æ段ãæ£æ段åæ¾çç±cpuæ§è¡çæºå¨æ令ï¼é常æ¯read-onlyçã
vfork
vforkç³»ç»è°ç¨ä¸åäºforkï¼ç¨vforkå建çåè¿ç¨ä¸ç¶è¿ç¨å ±äº«å°å空é´ï¼ä¹å°±æ¯è¯´åè¿ç¨å®å ¨è¿è¡å¨ç¶è¿ç¨çå°å空é´ä¸ï¼å¦æè¿æ¶åè¿ç¨ä¿®æ¹äºæ个åéï¼è¿å°å½±åå°ç¶è¿ç¨ã
å æ¤ï¼ä¸é¢çä¾åå¦ææ¹ç¨vfork()çè¯ï¼é£ä¹ä¸¤æ¬¡æå°a,bçå¼æ¯ç¸åçï¼æå¨å°åä¹æ¯ç¸åçã
ä½æ¤å¤æä¸ç¹è¦æ³¨æçæ¯ç¨vfork()å建çåè¿ç¨å¿ é¡»æ¾ç¤ºè°ç¨exit()æ¥ç»æï¼å¦ååè¿ç¨å°ä¸è½ç»æï¼èfork()åä¸åå¨è¿ä¸ªæ åµã
Vforkä¹æ¯å¨ç¶è¿ç¨ä¸è¿ååè¿ç¨çè¿ç¨å·ï¼å¨åè¿ç¨ä¸è¿å0ã
ç¨ vforkå建åè¿ç¨åï¼ç¶è¿ç¨ä¼è¢«é»å¡ç´å°åè¿ç¨è°ç¨exec(execï¼å°ä¸ä¸ªæ°çå¯æ§è¡æä»¶è½½å ¥å°å°å空é´å¹¶æ§è¡ä¹ã)æexitãvforkç好å¤æ¯å¨åè¿ç¨è¢«å建åå¾å¾ä» ä» æ¯ä¸ºäºè°ç¨execæ§è¡å¦ä¸ä¸ªç¨åºï¼å 为å®å°±ä¸ä¼å¯¹ç¶è¿ç¨çå°å空é´æä»»ä½å¼ç¨ï¼æ以对å°å空é´çå¤å¶æ¯å¤ä½ç ï¼å æ¤éè¿vforkå ±äº«å åå¯ä»¥åå°ä¸å¿ è¦çå¼éã
clone
ç³»ç»è°ç¨fork()åvfork()æ¯æ åæ°çï¼èclone()å带æåæ°ãfork()æ¯å ¨é¨å¤å¶ï¼vfork()æ¯å ±äº«å åï¼èclone()æ¯åå¯ä»¥å°ç¶è¿ç¨èµæºæéæ©å°å¤å¶ç»åè¿ç¨ï¼è没æå¤å¶çæ°æ®ç»æåéè¿æéçå¤å¶è®©åè¿ç¨å ±äº«ï¼å ·ä½è¦å¤å¶åªäºèµæºç»åè¿ç¨ï¼ç±åæ°å表ä¸çclone_flagsæ¥å³å®ãå¦å¤ï¼clone()è¿åçæ¯åè¿ç¨çpidã
Github上Fork开源代码,本地二次开发,保持源码同步
在Github上,获取并利用开源代码进行本地二次开发是一项常见操作。首先,你需要通过Fork功能复制一个大佬的开源代码仓库,这就像克隆一个项目,让你可以在不影响原始项目的情况下进行试验或贡献代码。要实现这一点,只需简单地执行两个步骤:
1. Fork仓库:复制链接后,使用git clone命令,编程猫作业源码将仓库克隆到本地,例如:`git clone /YOUR-USERNAME/origin-repo.git`
2. 同步本地副本:为保持与原始仓库同步,你需要配置git。通常,这涉及设置upstream指向主仓库,然后使用git pull从upstream获取更新。如果你想将这些更改推送到你的Fork仓库,还需要执行一次`git push`操作。
通过这些步骤,你就可以在本地对Fork的源代码进行修改,并确保与原始代码库保持同步。这是开源社区中协作开发的基础实践,帮助开发者们扩展和改进现有的开源项目。
ForkjoinPool -1
ForkJoinæ¯ç¨äºå¹¶è¡æ§è¡ä»»å¡çæ¡æ¶ï¼ æ¯ä¸ä¸ªæ大任å¡åå²æè¥å¹²ä¸ªå°ä»»å¡ï¼æç»æ±æ»æ¯ä¸ªå°ä»»å¡ç»æåå¾å°å¤§ä»»å¡ç»æçæ¡æ¶ãForkå°±æ¯æä¸ä¸ªå¤§ä»»å¡åå为è¥å¹²åä»»å¡å¹¶è¡çæ§è¡ï¼Joinå°±æ¯å并è¿äºåä»»å¡çæ§è¡ç»æï¼æåå¾å°è¿ä¸ªå¤§ä»»å¡çç»æãä¸é¢æ¯ä¸ä¸ªæ¯ä¸ä¸ªç®åçJoin/Fork计ç®è¿ç¨ï¼å°1âæ°åç¸å
é常è¿æ ·ä¸ªæ¨¡åï¼ä½ 们ä¼æ³å°ä»ä¹ï¼
Release Framework ï¼ å¸¸è§çå¤ç模åæ¯ä»ä¹ï¼ task pool - worker poolç模åã ä½æ¯Forkjoinpool éåäºå®å ¨ä¸åç模åã
ForkJoinPoolä¸ç§ExecutorServiceçå®ç°ï¼è¿è¡ForkJoinTaskä»»å¡ãForkJoinPoolåºå«äºå ¶å®ExecutorServiceï¼ä¸»è¦æ¯å 为å®éç¨äºä¸ç§å·¥ä½çªå(work-stealing)çæºå¶ãææ被ForkJoinPool管çç线ç¨å°è¯çªåæ交å°æ± åéçä»»å¡æ¥æ§è¡ï¼æ§è¡ä¸åå¯äº§çåä»»å¡æ交å°æ± åä¸ã
ForkJoinPoolç»´æ¤äºä¸ä¸ªWorkQueueçæ°ç»(æ°ç»é¿åº¦æ¯2çæ´æ°æ¬¡æ¹ï¼èªå¨å¢é¿)ãæ¯ä¸ªworkQueueé½æä»»å¡éå(ForkJoinTaskçæ°ç»)ï¼å¹¶ä¸ç¨baseãtopæåä»»å¡éåéå°¾åé头ãwork-stealingæºå¶å°±æ¯å·¥ä½çº¿ç¨æ¨ä¸ªæ«æä»»å¡éåï¼å¦æéåä¸ä¸ºç©ºååéå°¾çä»»å¡å¹¶æ§è¡ã示æå¾å¦ä¸
æµç¨å¾ï¼
poolå±æ§
workQueuesæ¯poolçå±æ§ï¼å®æ¯WorkQueueç±»åçæ°ç»ãexternalPushåexternalSubmitæå建çworkQueue没æowner(å³ä¸æ¯worker)ï¼ä¸ä¼è¢«æ¾å°workQueuesçå¶æ°ä½ç½®ï¼ècreateWorkerå建çworkQueueï¼å³workerï¼æownerï¼ä¸ä¼è¢«æ¾å°workQueuesçå¥æ°ä½ç½®ã
WorkQueueçå 个éè¦æååé说æå¦ä¸ï¼
è¿æ¯WorkQueueçconfigï¼é«ä½è·poolçconfigå¼ä¿æä¸è´ï¼èä½ä½åæ¯workQueueå¨workQueuesæ°ç»çä½ç½®ã
ä»workQueueså±æ§çä»ç»ä¸ï¼æ们ç¥éï¼ä¸æ¯ææworkQueueé½æworkerï¼æ²¡æworkerçworkQueueç§°ä¸ºå ¬å ±éåï¼shared queueï¼ï¼configç第ä½å°±æ¯ç¨æ¥å¤ææ¯å¦æ¯å ¬å ±éåçãå¨externalSubmitå建工ä½éåæ¶ï¼æï¼
q.config = k | SHARED_QUEUE;
å ¶ä¸qæ¯æ°å建çworkQueueï¼kå°±æ¯qå¨workQueuesæ°ç»ä¸çä½ç½®ï¼SHARED_QUEUE=1<<ï¼æ³¨æè¿éconfig没æä¿çmodeçä¿¡æ¯ã
èå¨registerWorkerä¸ï¼åæ¯è¿æ ·ç»workQueueçconfigèµå¼çï¼
w.config = i | mode;
wæ¯æ°å建çworkQueueï¼iæ¯å ¶å¨workQueuesæ°ç»ä¸çä½ç½®ï¼æ²¡æ设置SHARED_QUEUEæ è®°ä½
scanStateæ¯workQueueçå±æ§ï¼æ¯intç±»åçãscanStateçä½ä½å¯ä»¥ç¨æ¥å®ä½å½åworkerå¤äºworkQueuesæ°ç»çåªä¸ªä½ç½®ãæ¯ä¸ªworkerå¨è¢«å建æ¶ä¼å¨å ¶æé å½æ°ä¸è°ç¨poolçregisterWorkerï¼èregisterWorkerä¼ç»scanStateèµä¸ä¸ªåå§å¼ï¼è¿ä¸ªå¼æ¯å¥æ°ï¼å 为workeræ¯ç±createWorkerå建ï¼å¹¶ä¼è¢«æ¾å°WorkQueuesçå¥æ°ä½ç½®ï¼ècreateWorkerå建workeræ¶ä¼è°ç¨registerWorkerã
ç®è¨ä¹ï¼workerçscanStateåå§å¼æ¯å¥æ°ï¼éworkerçscanstateåå§å¼=INACTIVE=1<<ï¼å°äº0ï¼éworkerçworkQueueå¨externalSubmitä¸å建ï¼ã
å½æ¯æ¬¡è°ç¨signalWorkï¼ætryReleaseï¼å¤éworkeræ¶ï¼workerçé«ä½å°±ä¼å 1
å¦å¤ï¼scanState<0表示workeræªæ¿æ´»ï¼å½workerè°ç¨runtaskæ§è¡ä»»å¡æ¶ï¼scanStateä¼è¢«ç½®ä¸ºå¶æ°ï¼å³è®¾ç½®scanStateçæå³è¾¹ä¸ä½ä¸º0ã
workerä¼ç æ¶ï¼æ¯è¿æ ·åå¨ç
workerçå¤é类似è¿æ ·ï¼
å¨workerä¼ç ç4è¡ä¼ªç ä¸ï¼è®©ctlçä½ä½çå¼å为worker.scanStateï¼è¿æ ·ä¸æ¬¡å°±å¯ä»¥éè¿scanStateå¤é该workerãå¤é该workeræ¶ï¼æ该workerçpreStack设置为ctlä½ä½çå¼ï¼è¿æ ·ä¸ä¸æ¬¡å¤éçworkerå°±æ¯scanStateçäºè¯¥preStackçworkerã
è¿ééè¿preStackä¿åä¸ä¸ä¸ªworkerï¼è¿ä¸ªworkeræ¯å½åworkeræ´æ©å°å¨çå¾ ï¼æ以形æä¸ä¸ªåè¿å åºçæ ã
runStateæ¯intç±»åçå¼ï¼æ§å¶æ´ä¸ªpoolçè¿è¡ç¶æåçå½å¨æï¼æä¸é¢å 个å¼ï¼å¯ä»¥å¥½å 个å¼åæ¶åå¨ï¼ï¼
å¦ærunStateå¼ä¸º0ï¼è¡¨ç¤ºpoolå°æªåå§åã
RSLOCK表示éå®poolï¼å½æ·»å workeråpoolç»æ¢æ¶ï¼å°±è¦ä½¿ç¨RSLOCKéå®æ´ä¸ªpoolãå¦æç±äºrunState被éå®ï¼å¯¼è´å ¶ä»æä½çå¾ runState解éï¼é常ç¨waitè¿è¡çå¾ ï¼ï¼å½runState设置äºRSIGNALï¼è¡¨ç¤ºrunState解éï¼å¹¶éç¥ï¼notifyAllï¼çå¾ çæä½ã
å©ä¸4个å¼é½è·runStateçå½å¨ææå ³ï¼é½å¯ä»¥é¡¾åæä¹ï¼
å½éè¦åæ¢æ¶ï¼è®¾ç½®runStateçSTOPå¼ï¼è¡¨ç¤ºåå¤å ³éï¼è¿æ ·å ¶ä»æä½çå°è¿ä¸ªæ è®°ä½ï¼å°±ä¸ä¼ç»§ç»æä½ï¼æ¯å¦tryAddWorkerçå°STOPå°±ä¸ä¼åå建workerï¼
ètryTerminate对è¿äºçå½å¨æç¶æçå¤çåæ¯è¿æ ·çï¼
å½åtopåbaseçåå§å¼ä¸º INITIAL_QUEUE_CAPACITY >>>1= (1 << )>>>1 = /2ãç¶åpushä¸ä¸ªtaskä¹åï¼top+=1ï¼ä¹å°±æ¯è¯´ï¼top对åºçä½ç½®æ¯æ²¡ætaskçï¼æè¿pushè¿æ¥çtaskå¨top-1çä½ç½®ãèbaseçä½ç½®åè½å¯¹åºå°taskï¼base对åºæå æ¾è¿éåçtaskï¼top-1对åºæåæ¾è¿éåçtaskã
qlockå¼å«ä¹ï¼1: locked, < 0: terminate; else 0
å³å½qlockå¼ä½0æ¶ï¼å¯ä»¥æ£å¸¸æä½ï¼å¼=1æ¶ï¼è¡¨ç¤ºéå®
int SQMASK=0xeï¼åä»»ä½æ´æ°è·SQMASKä½ä¸åï¼å¾å°çæ°å°±æ¯å¶æ°ã
è¯æï¼
注æè¿éå为äºè¿å¶æ¯ ï¼å°¤å ¶æ³¨ææå³è¾¹ç¬¬ä¸ä½æ¯0ï¼ä»»ä½æ°è·æå³è¾¹ç¬¬ä¸ä½æ¯0çæ°ä½ä¸åï¼å¾å°çæ°å°±æ¯å¶æ°ï¼å 为ä½ä¸ä¹åï¼ç¬¬ä¸ä½å°±æ¯0ï¼æ¯å¦s=A&SQMASKï¼Aå¯ä»¥æ¯ä»»ææ´æ°ï¼ç¶åæsæäºè¿å¶è¿è¡å¤é¡¹å¼å±å¼ï¼åæs=2 n1+2 n2 â¦â¦+2^nnï¼è¿énâ¥1ï¼æ以så¯ä»¥è¢«2æ´é¤ï¼å³sæ¯å¶æ°ã
æ以ä¸ä¸ªæ°æ¯å¥æ°è¿æ¯å¶æ°ï¼çå ¶æå³è¾¹ç¬¬ä¸ä½å³å¯ã
æ们ç¥éworkQueueæexternalPushå建çåcreateWorkerå建çworkerï¼ä¸¤ç§æ¹å¼å建çworkQueueï¼å ¶æ¾ç½®å°workQueuesçä½ç½®æ¯ä¸åçï¼åè æ¾å°workQueueçå¶æ°ä½ç½®ï¼èåè åæ¾å°å¥æ°ä½ç½®ãä¸åworkQueueæ¾å°èªå·±å¨workQueuesçä½ç½®çç®æ³æç¹ä¸åã
ä¸é¢çä¸ä¸forkjoinæ¡æ¶è·åworkQueuesä¸çå¶æ°ä½ç½®çworkQueueçç®æ³ï¼
è¿æ ·å°±è½è·åworkQueuesçå¶æ°ä½ç½®çworkQueueãmä¿è¯m & r & SQMASKè¿æ´ä¸ªè¿ç®ç»æä¸ä¼è¶ åºworkQueuesçä¸æ ï¼SQMASKä¿è¯åå°çæ¯å¶æ°ä½ç½®çworkQueueãè¿éæä¸ä¸ªæ趣çç°è±¡ï¼å设0å°workQueues.length-1ä¹é´æn个å¶æ°ï¼m & r & SQMASKæ¯æ¬¡é½è½åå°å ¶ä¸ä¸ä¸ªå¶æ°ï¼èä¸è¿ç»n次åå°çå¶æ°ä¸ä¼åºç°éå¤å¼ï¼æ£åæ§é常好ãèä¸æ¯å¾ªç¯çï¼å³1å°n次ån个ä¸åå¶æ°ï¼n+1å°2nä¹æ¯ån次ä¸åå¶æ°ï¼æ¤æ¶n个å¶æ°æ¯ä¸ªé½è¢«éæ°åä¸æ¬¡ãä¸é¢åæä¸rå¼æä»ä¹ç§å¯ï¼ä¸ºä½è½ä¿è¯è¿æ ·çæ£åæ§
ThreadLocalRandomå æä¸å¸¸éPROBE_INCREMENT = 0x9eb9ï¼ä»¥åä¸ä¸ªéæçprobeGenerator =new AtomicInteger() ï¼ç¶åæ¯ä¸ªçº¿ç¨çprobe= probeGenerator.addAndGet(PROBE_INCREMENT)æ以第ä¸ä¸ªçº¿ç¨çprobeå¼æ¯0x9eb9ï¼ç¬¬äºä¸ªçº¿ç¨çå¼å°±æ¯0x9eb9+0x9eb9ï¼ç¬¬ä¸ä¸ªçº¿ç¨çå¼å°±æ¯0x9eb9+0x9eb9+0x9eb9以æ¤ç±»æ¨ï¼æ´ä¸ªå¼æ¯çº¿æ§çï¼å¯ä»¥ç¨y=kx表示ï¼å ¶ä¸k=0x9eb9ï¼x表示第å 个线ç¨ãè¿æ ·æ¯ä¸ªçº¿ç¨çprobeå¯ä»¥ä¿è¯ä¸ä¸æ ·ï¼èä¸å ·æå¾å¥½ç离æ£æ§ã
å®é ä¸ï¼å¯ä»¥ä¸ç¨0x9eb9è¿ä¸ªå¼ï¼ç¨ä»»æä¸ä¸ªå¥æ°é½æ¯å¯ä»¥çï¼æ¯å¦1ãå¦æç¨1çè¯ï¼probe+=1ï¼è¿æ ·æ¯ä¸ªçº¿ç¨çprobeå°±é½æ¯ä¸åçï¼èä¸å ·æå¾å¥½ç离æ£æ§ãä¹å°±æ¯è¯´ï¼å设æéå¶æ¡ä»¶probe<nï¼è¶ è¿nå产ç溢åºãåprobeèªå n次åæä¼å¼å§åºç°éå¤å¼ï¼n次åprobeæ¯æ¬¡èªå çå¼é½ä¸åãå®é ä¸ç¨ä»»æä¸ä¸ªå¥æ°ï¼é½å¯ä»¥ä¿è¯probeèªå n次åæä¼å¼å§åºç°éå¤å¼ï¼æå ´è¶£å¯çæ¬ææåéå½é¨åãç±äºå¥æ°ç离æ£æ§ï¼æ以åªè¦çº¿ç¨æ°å°äºmæè SQMASK两è ä¸çæå°å¼ï¼åæ¯ä¸ªçº¿ç¨é½è½å¯ä¸å°å æ®ä¸ä¸ªwsä¸çä¸ä¸ªä½ç½®
å½ä¸ä¸ªæä½æ¯å¨éForkjoinThreadç线ç¨ä¸è¿è¡çï¼å称该æä½ä¸ºå¤é¨æä½ãæ¯å¦æ们åé¢æ§è¡pool.invokeï¼invokeå åæ§è¡externalPushãç±äºinvokeæ¯å¨éForkjoinThread线ç¨ä¸è¿è¡çï¼è¿éæ¯å¨main线ç¨ä¸è¿è¡ï¼ï¼æ以æ¯ä¸ä¸ªå¤é¨æä½ï¼è°ç¨çæ¯externalPushãä¹åtaskçæ§è¡æ¯éè¿ForkJoinThreadæ¥æ§è¡çï¼æ以taskä¸çforkå°±æ¯å é¨æä½ï¼è°ç¨çæ¯pushï¼æä»»å¡æ交å°å·¥ä½éåãå ¶å®forkçå®ç°æ¯ç±»ä¼¼ä¸é¢è¿æ ·çï¼
å³forkä¼æ ¹æ®æ§è¡èªèº«ç线ç¨æ¯å¦æ¯ForkJoinThreadçå®ä¾æ¥å¤ææ¯å¤äºå¤é¨è¿æ¯å é¨ãé£ä¸ºä½è¦åºåå å¤é¨ï¼
ä»»ä½çº¿ç¨é½å¯ä»¥ä½¿ç¨ForkJoinæ¡æ¶ï¼ä½æ¯å¯¹äºéForkJoinThreadç线ç¨ï¼å®å°åºæ¯ææ ·çï¼ForkJoinæ æ³æ§å¶ï¼ä¹æ æ³å¯¹å ¶ä¼åãå æ¤åºååºå å¤é¨ï¼è¿æ ·æ¹ä¾¿ForkJoinæ¡æ¶å¯¹ä»»å¡çæ§è¡è¿è¡æ§å¶åä¼å
forkJoinPool.invoke(task)æ¯æä»»å¡æ¾å ¥å·¥ä½éåï¼å¹¶çå¾ ä»»å¡æ§è¡ãæºç å¦ä¸
è¿éexternalPushè´è´£ä»»å¡æ交ï¼externalPushæºç å¦ä¸ï¼
linux0.源码分析-fork进程
在操作系统中,Linux0.源码中的fork函数执行流程分为启动和系统调用两个阶段。启动阶段首先在init/main.c中执行init用于启动shell,让用户执行命令。
在include/unistd.h中定义了宏,表示将__NR_fork的值复制给eax寄存器,并将_res与eax绑定。使用int 0x中断后,系统调用函数system_call被调用,从sys_call_table中找到对应的函数执行。fork函数执行时,操作系统会在内核栈里保存相关寄存器,准备中断返回。
接着,操作系统通过int调用system_call,在kernel/system_call.s中执行call _sys_call_table(,%eax,4)指令。内核栈中,因为是段内跳转,所以cs不需要入栈。ip指向call指令的下一句代码。执行call指令进入系统调用表。
在includ/linux/sys.h中,系统调用表是一个数组,根据eax即系统函数编号找到对应的函数执行。对于fork,__NR_fork值2被放入eax寄存器,%eax * 4找到sys_fork。执行sys_fork后,调用find_empty_process函数找到可用的进程号,并放入eax寄存器返回。
接着,系统调用执行copy_process函数建立新进程结构体并复制数据。新进程的ip出栈,执行完copy_process后,系统调用返回,内核栈状态改变。此阶段最后通过iret指令弹出寄存器,恢复中断前状态。
总结,fork函数通过复制当前进程结构体、处理信号并初始化新进程,实现父进程与子进程的创建与共享。子进程返回值为0,父进程返回新子进程的pid。通过fork函数的执行,操作系统能够高效地创建进程,实现多任务处理。