<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          第37回 | shell 程序跑起來(lái)了

          共 4019字,需瀏覽 9分鐘

           ·

          2022-05-22 19:08

          新讀者看這里,老讀者直接跳過(guò)。


          本系列會(huì)以一個(gè)讀小說(shuō)的心態(tài),從開(kāi)機(jī)啟動(dòng)后的代碼執(zhí)行順序,帶著大家閱讀和賞析 Linux 0.11 全部核心代碼,了解操作系統(tǒng)的技術(shù)細(xì)節(jié)和設(shè)計(jì)思想。


          本系列的 GitHub 地址如下,希望給個(gè) star 以示鼓勵(lì)(文末閱讀原文可直接跳轉(zhuǎn),也可以將下面的鏈接復(fù)制到瀏覽器里打開(kāi))

          https://github.com/sunym1993/flash-linux0.11-talk


          本回的內(nèi)容屬于第四部分。



          你會(huì)跟著我一起,看著一個(gè)操作系統(tǒng)從啥都沒(méi)有開(kāi)始,一步一步最終實(shí)現(xiàn)它復(fù)雜又精巧的設(shè)計(jì),讀完這個(gè)系列后希望你能發(fā)出感嘆,原來(lái)操作系統(tǒng)源碼就是這破玩意。


          以下是已發(fā)布文章的列表,詳細(xì)了解本系列可以先從開(kāi)篇詞看起。


          開(kāi)篇詞


          第一部分 進(jìn)入內(nèi)核前的苦力活


          第1回 | 最開(kāi)始的兩行代碼

          第2回 | 自己給自己挪個(gè)地兒

          第3回 | 做好最最基礎(chǔ)的準(zhǔn)備工作

          第4回 | 把自己在硬盤(pán)里的其他部分也放到內(nèi)存來(lái)

          第5回 | 進(jìn)入保護(hù)模式前的最后一次折騰內(nèi)存

          第6回 | 先解決段寄存器的歷史包袱問(wèn)題

          第7回 | 六行代碼就進(jìn)入了保護(hù)模式

          第8回 | 煩死了又要重新設(shè)置一遍 idt 和 gdt

          第9回 | Intel 內(nèi)存管理兩板斧:分段與分頁(yè)

          第10回 | 進(jìn)入 main 函數(shù)前的最后一躍!

          第一部分總結(jié)與回顧


          第二部分 大戰(zhàn)前期的初始化工作


          第11回 | 整個(gè)操作系統(tǒng)就 20 幾行代碼

          第12回 | 管理內(nèi)存前先劃分出三個(gè)邊界值

          第13回 | 主內(nèi)存初始化 mem_init

          第14回 | 中斷初始化 trap_init

          第15回 | 塊設(shè)備請(qǐng)求項(xiàng)初始化 blk_dev_init

          第16回 | 控制臺(tái)初始化 tty_init

          第17回 | 時(shí)間初始化 time_init

          第18回 | 進(jìn)程調(diào)度初始化 sched_init

          第19回 | 緩沖區(qū)初始化 buffer_init

          第20回 | 硬盤(pán)初始化 hd_init

          第二部分總結(jié)與回顧


          第三部分:一個(gè)新進(jìn)程的誕生


          第21回 | 新進(jìn)程誕生全局概述

          第22回 | 從內(nèi)核態(tài)切換到用戶態(tài)

          第23回 | 如果讓你來(lái)設(shè)計(jì)進(jìn)程調(diào)度

          第24回 | 從一次定時(shí)器滴答來(lái)看進(jìn)程調(diào)度

          25回 | 通過(guò) fork 看一次系統(tǒng)調(diào)用

          第26回 | fork 中進(jìn)程基本信息的復(fù)制

          第27回 | 透過(guò) fork 來(lái)看進(jìn)程的內(nèi)存規(guī)劃

          第三部分總結(jié)與回顧


          第28回 | 番外篇 - 我居然會(huì)認(rèn)為權(quán)威書(shū)籍寫(xiě)錯(cuò)了...

          第29回 | 番外篇 - 讓我們一起來(lái)寫(xiě)本書(shū)?

          第30回 | 番外篇 - 寫(xiě)時(shí)復(fù)制就這么幾行代碼


          第四部分:shell 程序的到來(lái)

          第31回 | 拿到硬盤(pán)信息
          第32回 | 加載根文件系統(tǒng)
          第33回 | 打開(kāi)終端設(shè)備文件
          第34回 | 進(jìn)程2的創(chuàng)建
          第35回 | execve 加載并執(zhí)行 shell 程序
          第36回 | 缺頁(yè)中斷
          第37回 | shell 程序跑起來(lái)了(本文)



          ------- 正文開(kāi)始?-------




          書(shū)接上回,上回書(shū)咱們說(shuō)到,Linux 通過(guò)缺頁(yè)中斷處理過(guò)程,將 /bin/sh 的代碼從硬盤(pán)加載到了內(nèi)存,此時(shí)便可以正式執(zhí)行 shell 程序了。

          ?

          這個(gè) shell 程序,也就是 Linux 0.11 中要執(zhí)行的這個(gè) /bin/sh 程序,它的源碼并沒(méi)有體現(xiàn)在 Linux 0.11 源碼中。

          ?

          也可以說(shuō),不論這個(gè) /bin/sh 是個(gè)啥文件,哪怕只是個(gè) hello world 程序,Linux 0.11 的啟動(dòng)過(guò)程中也會(huì)傻傻地去執(zhí)行它。

          ?

          但同時(shí),shell 又是一個(gè)我們?cè)偈煜げ贿^(guò)的東西了。

          ?

          在我的騰訊云服務(wù)器上(用 Termius 連接),它是這個(gè)樣子的。

          ?

          ?

          在我的 Ubuntu 16.04 虛擬機(jī)上,它是這個(gè)樣子的。

          ?

          ?

          在我的 mac 電腦上,它是這個(gè)樣子的。

          ?

          ?

          沒(méi)錯(cuò),它就是我們通常說(shuō)的那個(gè)命令行黑窗口。

          ?

          當(dāng)然 shell 只是一個(gè)標(biāo)準(zhǔn),具體的實(shí)現(xiàn)可以有很多,比如在我的 Ubuntu 16.04 上,具體的 shell 實(shí)現(xiàn)是 bash。

          flash:~$?echo?$SHELL
          /bin/bash

          而在我的 mac 上,具體的實(shí)現(xiàn)是 zsh。

          ~?echo?$SHELL
          /bin/zsh

          當(dāng)然,默認(rèn)的 shell 實(shí)現(xiàn)也可以手動(dòng)進(jìn)行設(shè)置并更改。

          ?

          還有個(gè)有意思的事,shell 前面的提示符,是否可以修改呢?

          ?

          我的騰訊云服務(wù)器上,提示符是

          [root@VM-24-11-centos?~]#

          我的 Ubuntu 虛擬機(jī)上,提示符是

          flash:~$

          我的 mac 電腦上更簡(jiǎn)單,提示符是

          ~

          我現(xiàn)在覺(jué)得我那個(gè)騰訊云服務(wù)器上的提示符太長(zhǎng)了怎么辦?我們先查看一個(gè)變量 PS1 的值

          [root@VM-24-11-centos?~]#?echo?$PS1
          [\u@\h?\W]\$

          然后,我們直接把這個(gè)值給改了。

          [root@VM-24-11-centos?~]#?echo?$PS1
          [\u@\h?\W]\$
          [root@VM-24-11-centos?~]#?PS1=[呵呵呵]
          [呵呵呵]

          可以看到神奇的事情發(fā)生了,前面的提示符變成了我們自己定義的樣子。

          ?

          其實(shí)我就想說(shuō),shell 程序也僅僅是個(gè)程序而已,它的輸出,它的輸入,它的執(zhí)行邏輯,是完全可以通過(guò)閱讀程序源碼來(lái)知道的,和一個(gè)普通的程序并沒(méi)有任何區(qū)別。

          ?

          好了,接下來(lái)我們就閱讀一下 shell 程序的源碼,只需要找到它的一個(gè)具體實(shí)現(xiàn)即可。但是 bash,zsh 等實(shí)現(xiàn)都過(guò)于復(fù)雜,很多東西對(duì)于我們學(xué)習(xí)完全沒(méi)必要。

          ?

          所以這里我通過(guò)一個(gè)非常非常精簡(jiǎn)的 shell 實(shí)現(xiàn),即 xv6 里的 shell 實(shí)現(xiàn)為例,來(lái)進(jìn)行講解。

          ?

          xv6 是一個(gè)非常非常經(jīng)典且簡(jiǎn)單的操作系統(tǒng),是由麻省理工學(xué)院為操作系統(tǒng)工程的課程開(kāi)發(fā)的一個(gè)教學(xué)目的的操作系統(tǒng),所以非常適合操作系統(tǒng)的學(xué)習(xí)。

          ?

          ?

          而在它的源代碼中,又恰好實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的 shell 程序,所以閱讀它的代碼,對(duì)我們這個(gè)系列課程來(lái)說(shuō),簡(jiǎn)直再合適不過(guò)了。

          ?

          ?

          看到?jīng)],甚至在這么一個(gè)小小的截圖里,已經(jīng)可以完整展示 sh.c 里全部的 main 方法代碼了。

          ?

          但我仍然十分貪婪,即便是這么短的代碼,我也幫你把一些多余的校驗(yàn)邏輯去掉,再去掉關(guān)于 cd 命令的特殊處理分支,來(lái)一個(gè)最干凈的版本。

          //?xv6-public?sh.c
          int?main(void)?{
          ????static?char?buf[100];
          ????//?讀取命令
          ????while(getcmd(buf,?sizeof(buf))?>=?0){
          ????????//?創(chuàng)建新進(jìn)程
          ????????if(fork()?==?0)
          ????????????//?執(zhí)行命令
          ????????????runcmd(parsecmd(buf));
          ????????//?等待進(jìn)程退出
          ????????wait();
          ????}
          }

          看,shell 程序變得異常簡(jiǎn)單了!

          ?

          總得來(lái)說(shuō),shell 程序就是個(gè)死循環(huán),它永遠(yuǎn)不會(huì)自己退出,除非我們手動(dòng)終止了這個(gè) shell 進(jìn)程。

          ?

          在死循環(huán)里面,shell 就是不斷讀?。?strong>getcmd)我們用戶輸入的命令,創(chuàng)建一個(gè)新的進(jìn)程(fork),在新進(jìn)程里執(zhí)行(runcmd)剛剛讀取到的命令,最后等待(wait)進(jìn)程退出,再次進(jìn)入讀取下一條命令的循環(huán)中。

          ?

          由此你是不是也感受到了 xv6 源碼的簡(jiǎn)單之美,真的是見(jiàn)名知意,當(dāng)你跟我走完這個(gè) Linux 0.11 之旅后,再去閱讀 xv6 的源碼你會(huì)覺(jué)得非常舒服,因?yàn)?Linux 0.11 很多地方都用了非常騷的編碼技巧,使得理解起來(lái)很困難,誰(shuí)讓 Linus 這么特立獨(dú)行呢。

          ?

          我們之前說(shuō)過(guò) shell 就是不斷 fork + execve 完成執(zhí)行一個(gè)新程序的功能的,那 execve 在哪呢?

          ?

          那我們就要看執(zhí)行命令的 runcmd 代碼了。

          void?runcmd(struct?cmd?*cmd)?{
          ????...
          ????struct?execcmd?ecmd?=?(struct?execcmd*)cmd;
          ????...
          ????exec(ecmd->argv[0],?ecmd->argv);
          ????...
          }

          這里我又省略了很多代碼,比如遇到管道命令 PIPE,遇到命令集合 LIST 時(shí)的處理邏輯,我們僅僅看單純執(zhí)行一條命令的邏輯。

          ?

          可以看到,就是簡(jiǎn)簡(jiǎn)單單調(diào)用了個(gè) exec 函數(shù),這個(gè) exec 是 xv6 代碼里的名字,在 Linux 0.11 里就是我們?cè)?第35回 | execve 加載并執(zhí)行 shell 程序 里講的 execve 函數(shù)。

          ?

          shell 執(zhí)行一個(gè)我們所指定的程序,就和我們?cè)?Linux 0.11 里通過(guò) fork + execve 函數(shù)執(zhí)行了 /bin/sh 程序是一個(gè)道理。

          ?

          你看,fork 和 execve 函數(shù)你一旦懂了,shell 程序的原理你就直接秒懂了。而 fork 和 execve 函數(shù)的原理,其實(shí)如果你非常熟練地掌握中斷、虛擬內(nèi)存、文件系統(tǒng)、進(jìn)程調(diào)度等更為底層的基礎(chǔ)知識(shí),其實(shí)也不難理解。

          ?

          所以,根基真的很重要,本回已經(jīng)到操作系統(tǒng)啟動(dòng)流程的最后一哆嗦了,如果你現(xiàn)在感覺(jué)十分混亂,最好的辦法就是,不斷去啃之前那些你認(rèn)為"無(wú)聊的"、"沒(méi)用的"章節(jié)。

          ?

          好了,今天的 shell 就到這里了,畢竟我們是講 Linux 0.11 核心流程的系列,不必過(guò)多深入 shell 這個(gè)應(yīng)用程序。

          ?

          接下來(lái)有個(gè)問(wèn)題,shell 程序執(zhí)行了,操作系統(tǒng)就結(jié)束了么?

          ?

          欲知后事如何,且聽(tīng)下回分解。




          ------- 關(guān)于本系列?-------




          本系列的開(kāi)篇詞看這,開(kāi)篇詞


          本系列的番外故事看這,讓我們一起來(lái)寫(xiě)本書(shū)?也可以直接無(wú)腦加入星球,共同參與這場(chǎng)旅行。



          最后,本系列完全免費(fèi),希望大家能多多傳播給同樣喜歡的人,同時(shí)給我的 GitHub 項(xiàng)目點(diǎn)個(gè) star,就在閱讀原文處,這些就足夠讓我堅(jiān)持寫(xiě)下去了!我們下回見(jiàn)。

          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产欧美黄色一级二级三级 | 色婷婷亚洲精品天天 | 亚洲淫淫网 | 色吊丝最新永久网址大全 | 黄片在线免费观看免播放器 |