1. 程式人生 > 實用技巧 >NodeJS_0003:nodejs 設定允許跨域請求

NodeJS_0003:nodejs 設定允許跨域請求

要求:

請您根據本課程所學內容總結梳理出一個精簡的Linux系統概念模型,最大程度統攝整頓本課程及相關的知識資訊,模型應該是邏輯上可以運轉的、自洽的,並舉例某一兩個具體例子(比如讀寫檔案、分配記憶體、使用I/O驅動某個硬體等)納入模型中驗證模型。

談談您對課程的心得體會,改進建議等。

根據課程順序,把學習內容主要分為以下幾個大塊:

一. 系統呼叫和堆疊框架

· 為了遮蔽硬體操作的細節,增強系統的安全性,增強使用者程式的可移植性,Linux操縱系統劃分了使用者態和核心態,對應的記憶體空間被劃分成使用者空間和核心空間。核心態的許可權高於使用者態,即核心態下,cs:ip可以指向任意位置,而使用者態下,cs:ip的活動範圍只能是自己的空間。為了使使用者呼叫作業系統底層服務,如中斷,時鐘,異常等,需要採取一種機制,就是系統呼叫。

從軟體的角度看,通過int 0x80指令或者syscall指令可以觸發系統呼叫。首先,當linux進入核心態時,先儲存此時的上下文環境,如果是硬體中斷觸發的系統呼叫,儲存的是中斷上下文,如果是使用者程式觸發的系統呼叫,儲存使用者程序上下文。所謂的上下文是核心儲存的,用於系統呼叫返回的引數資訊然後,通過系統呼叫號,找到對應的系統呼叫處理函式的首地址,建立函式堆疊,修改cs:ip的值並執行處理函式。處理函式執行完畢後,根據儲存的上下文資訊恢復現場返回使用者態。

· 堆疊是C語言程式執行時必須的一個記錄呼叫路徑和引數的空間, 在這個堆疊上儲存了函式呼叫框架, 傳遞的引數, 儲存的返回地址, 函式內部 的區域性變數等等引數。一個函式呼叫動作是通過call

指令來完成的。

一個完成的函式呼叫過程大致可以用下圖表示:即call target,進入target,退出target。

二. 程序管理

概念:程序是Linux進行資源分配和排程的基本單位,程序也被看做是程式的一次執行過程,當持久化在磁碟上的二進位制程式碼被載入記憶體時,Linux作業系統為其分配了使用者棧和核心棧,同時使用task_struct這種資料結構對程序進行描述,task_struct是Linux作業系統感知程序存在的資料結構,具體描述了程序號,程序狀態,程序的排程策略和排程資訊,程序開啟檔案表,程序連結串列,父子程序的關係等資訊。Linux根據這個資料結構找到程序對應的使用者棧和核心棧,並根據cs,ip,ss,sp,ebp等暫存器資訊,執行這個程序。

狀態切換

上下文切換:期間涉及到prev程序上下文的儲存,以及next程序上下文的載入,如圖所示:

具體的還牽扯到了程序的核心態和使用者態堆疊。

程序排程:有了程序的概念,Linux就可以執行磁碟中持久化的二進位制程式碼了。為了提高cpu利用率,提高計算機的併發性,引入了程序的排程這個概念,這相當於Linux虛擬化了多個“平行空間”,每個程序都有自己獨立的使用者棧和核心棧,Linux核心根據排程策略,在一定的時機對程序進行排程。

程序排程時機包括:時間片用完,中斷返回,程序狀態發生變化,系統呼叫返回等。

至於排程策略,Linux系統採用優先順序排程的策略,又分成實時程序和非實時程序,實時程序指需要及時處理的程序,優先順序範圍是0~99100~139是非實程序的優先順序範圍。實時程序的優先順序高於非實時程序。同一優先順序對列按FIFO或者RR(時間片輪轉)進行排程。

三. 中斷

中斷最初⽤於避免CPU輪詢I/O裝置,就緒狀態發⽣時讓I/O裝置主動通過中斷訊號通知CPU,大大提⾼了CPU在輸⼊輸出上的⼯作效率,這就是硬體中斷(外部中斷)。後來隨著中斷適⽤範圍擴⼤,比如解決機器運⾏過程出現的異常情況以及系統調⽤的實現等,這就產⽣了軟體中斷(內部中斷),也稱為異常,軟體中斷⼜分為故障(fault)和陷阱(trap)。

簡而言之,在沒有中斷機制之前,計算機只能⼀個程式⼀個程式地執⾏,也就是批處理,而無法多個程式併發⼯作。有了中斷機制,CPU幫我們做了⼀件事情,就是當⼀箇中斷訊號發⽣時,CPU把當前正在執⾏的程序X的CS:RIP暫存器和RSP暫存器等都壓棧到了⼀個叫核心堆疊的地⽅,然後把CS:RIP指向⼀箇中斷處理程式的入口,做儲存現場的⼯作,然後去執⾏其他程序⽐如Y,等重新回來時再恢復現場,即恢復CS:RIP暫存器和RSP暫存器等到CPU上繼續執⾏原程序X。顯然中斷機制在計算機系統中發揮著關鍵作⽤。

經過上述的硬體級處理過後, 核心態的堆疊會發生變化, 但是由使用者態進入中斷和由核心態進入中斷又不太一樣,由上圖的特權級是否變化即可看出,具體在堆疊中則有以下區別:

可以看到核心態進入中斷,需要額外儲存使用者態的上下文資訊,以便從核心態變成使用者態時繼續執行。

四. 檔案管理

Linux支援多種檔案系統,包括ext2、ext3、vfat等等。

Linux採用虛擬檔案系統VFS來達到支援多種檔案系統格式的目標。VFS為各類檔案系統提供一個統一的操作介面和程式設計介面。向上提供統一的程式設計介面,向下對各種檔案系統進行相容。

檔案系統的結構包括在磁碟上的結構和在記憶體中的結構。磁碟上包括引導控制塊、盤控制塊、目錄結構、FCB。在記憶體中包括:

  • 系統開啟檔案表:包含每個已開啟檔案的FCB的副本,以及其他資訊。
  • 程序開啟檔案表:包含一個指向系統開啟檔案表相應項的指標,以及其他資訊。

file結構一方面可從f_dentry連結到目錄項模組以及inode模組,獲取所有和檔案相關的資訊,另一方面連結file_operations子模組,其中包含所有可以使用的系統呼叫函式,從而最終完成對檔案的操作。

五. 具體例子

以使用者讀一個檔案為例,

當用戶點選開啟檔案時,會呼叫庫函式中的read()函式,而在這個函式中會觸發軟中斷指令,CPU陷入到核心態,程序堆疊也會切換到相應的核心態堆疊。

接著,進入異常處理的硬體級流程,在這個過程中,CPU在棧中儲存eflags、cs、和eip的內容,隨後進入異常處理的軟體級流程,在這個過程中, CPU會進一步儲存上下文.。

與這個過程相對應的是:CPU讀取idtr暫存器指向的IDT表中的第128項,此時可以得到0x80中斷門,通過這個中斷門CPU可以得到中斷處理例程。

接著, 中斷處理例程會到系統呼叫表中找到read()函式相對應的VFS虛擬檔案系統中的系統呼叫sys_read()。

到達VFS層次後,sys_read()會根據fd在程序開啟檔案表中找到相應的系統開啟檔案表(File資料結構),然後執行系統開啟檔案表中的file operations中具體的操作。

檔案開啟之後,將pt_regs資料結構中描述的暫存器以及cs:eip暫存器恢復, 此時程序又重新恢復到了使用者態, 並沿著read()函式的下一條語句繼續執行。

六. 總結與建議

總的來說,這門課真的是乾貨滿滿,兩位老師深入核心程式碼的耐心講解,在現在的大環境下真的很難得,也確實讓我學到了不少東西,真正瞭解到了Linux底層的一些執行流程與原理,

相較於平時自己的摸索,這種課程真的給我帶來了很大的幫助。

建議的話,一些核心程式碼部分的講解,邏輯的梳理,只是聽老師用嘴說,可能不是很容易理解,如果能有形象的展示,也許會更助於理解。

最後,希望這門課可以一直繼續開下去,幫助更多學弟學妹們。

謝謝二位老師的辛苦付出,祝老師們身體健康!