Monday, November 14, 2011

What is different between fork() & vfork()?

Ref:  http://csie-tw.blogspot.com/2009/04/vforkuclinux.html

節錄自:大黑狗 之 嵌入式系統專案實務 與 產業觀察

  fork()和vfork()這兩個系統功能都可以複製出和呼叫者﹙parent﹚完全相同processchild﹚,但呼叫vfork()後的parent process會被暫停,直到被複製出來的child process執行exec()exit();而呼叫fork()後的parent process會和新產生的child process平行(concurrent﹚執行。
  接下來我們必須約略解釋一下fork()Linux中的實現方式,旨在讓讀者知道為什麼這個系統功能沒法直接移植到沒有MMUCPU上;首先我們必須先介紹一下”copy-on-write”這個觀念:
    一個程式在執行時會佔據記憶體空間,粗略可分為程式段、資料段、堆疊段與常數段,其中程式段與堆疊段是唯讀的,資料段與堆疊段的內容則有可能在執行時期被改變。Linux中,當某個process呼叫fork()產生child process時,系統只會為新的process配置堆疊段,其他的記憶體區段都是共用的;實際上在child process呼叫exec()去執行另一個程式前,諸如程式段以及常數段這些內容不可以被改變的記憶體區段始終可以共用。可是資料段就不能一直共用,如果parentchild process同時去操作某個變數勢必會引起混亂。
    Child processfork出來後馬上呼叫exec()去執行其他程式是最常用的流程,以此說來,雖然每個process都必須有獨立的資料段,但馬上為child process配置資料段是很不經濟的,因為在大部分的狀況下child process並不會去對資料段作寫入的動作,在執行exec()後,之前的資料段就沒用了。
為了解決這個問題,Linux(fork)採用”copy-on-write”的技術,在child process尚未對資料段作寫入的動作之前,parentchild process共用資料段;當child process對資料段記憶體作出寫入的要求時,系統會配置一塊實體記憶體﹙一個page﹚給child process,並將原本資料段中被要求寫入之page的內容複製到這塊新的page;接著系統會更改child process的page table,使要被寫入資料的虛擬位址可以對應到上述新配置的實體記憶體位址。
此時child processparent process的資料段大部分都還是功用的,不同的地方只是這次要被寫入的page;這種演算法的好處很多,在最節省記憶體的前提下使得parentchild process不致互相影響。要達到這種效果,CPU沒有支援MMU是做不到的,所以uClinux無法直接支援fork()這個系統功能。
uClinux無法作到安全的資料段分享機制,產生child process後複製整塊資料段也顯得有點笨拙,於是只好讓parent process停止執行,直到child process結束執行或有了自己的資料段之後才能恢復執行,前者表示child process出現例外或呼叫了_exit(),而後者則表示child process呼叫了exec()去執行其他的程式。這樣妥協出來的功能,就是原本Linux中的vfork()系統呼叫。
如果讀者對copy-on-write的原理不清楚也沒關係,讀者在使用uClinux時只需知道一般Linux在實現fork()這個系統功能時必須用到MMU的機制,而uClinux執行在沒有MMUCPU之上,所以fork()無法直接移植到uClinux上;uClinux提供vfork()以達到多工的效果。
必須注意的是,使用vfork()產生的child process很可能會破壞parent process原本的資料段,所以程式設計師在uClinux上使用vfork()時必須格外小心;而且沒有fork()系統功能的事實使得許多原本運行在Linux上的應用程式無法完全不經修改救執行於uClinux之上。
我的心得:在早期的fork會複製整個parent的address space,造成時間的浪費,使用vfork則不會複製parent的address space。近來的fork則使用copy-on-write的技術,但是這卻需要MMU的幫忙,才能將child process的page table修改成正確的physcial address,而在嵌入式系統上,uClinux並不支援MMU,所以只能使用vfork。


Read more: http://csie-tw.blogspot.com/2009/04/vforkuclinux.html#ixzz1djWY034l

Tuesday, November 8, 2011

Port Forwarding,Port Triggering及UPnP/NAT-PMP


Tomato Port Forwarding / Port Triggering 設定

簡單介紹有關頻寬分享器常會有的功能:Port Forwarding,Port Triggering及UPnP/NAT-PMP


當頻寬分享器安裝好後,通常會有一個功能,叫Port Forwarding,但是手冊上不一定會說明怎麼使用,比如ASUS RT-N10 / RT-N16二本手冊,我根本沒看到在哪設定? 以下介紹在Tomato Firmware上有的Port Forwarding功能:

  • Port Forwarding
  • Port Triggering
  • UPnP/NAT-PMP

Port Forwarding
這是最早出現的轉Port方式,比如如果你的PC,IP為192.168.0.1,在這台機器上有一個應用程式開啟了1234這個埠(Port),負責接收網際網路的需求,但是由於頻寬分享器本身的防火牆功能,並不允許外面的連線連到192.168.0.1:1234這個端點,故需要設定Port Forwarding,告訴頻寬分享器,如果收到要到Port 1234的要求,就轉到192.168.0.1的Port 1234。Port Forwarding最不方便的是,要設定內部轉到哪台IP,不能動態設定。典型用Port Forwarding的例子是:架在內部的Web Server,要能讓外部可以連接時,都會用Port Forwarding。



 

 Port Triggering
Port Triggering和Port Forward很類似,差別在於不用指定IP Address,試想想如果PC端是用DHCP,那麼指定IP的話,不是很麻煩? Port Triggering可說是Port Forwarding的進化版,只要指示Router,收到外部對哪個Port要求Request時,送到內部哪個Port即可。但是它應該也無法同時處理二台PC上同一個Port的要求,我沒有實驗過是不是真的不行。





 UPnP / NAT-PMP

UPnP是為了解決上面二種麻煩的設定而產生的,在有支援UPnP的軟硬體下,通常不用做任何設定,程式就可以直接設作業系統及軟體設備溝通,並建立連結。
NAT-PMP (NAT Port Mapping Protocol)是架構在UPnP下的更進階的協定,要用這功能,UPnP一定要打開,NAT-PMP神奇的地方是,它可以直接和Router溝通,可以把它想成自動在Router上設Port Forwarding,主要是由Apple提出,應用方面也以Apple的設備為主,但是不少軟體也有支援(比如BitComet)。

在Tomato Firmware上設定Port Forwarding、Port Triggering和UPnP


下圖表示如何在Tomato Firmware上設定Port Forwarding:


 範例--設定Port Forwarding:下面的例子為指定192.168.0.1:12185 TCP Port和192.168.0.1:9663 UDP 二個Port Forwarding,請注意畫面上的設定是沒打開(On)的,另外,設好後,右下角有個Save的按鈕,要按了以後才生效。




範例--設定Port Trigger:下面的例子為指定12185 TCP Port,9663 UDP Port,7263 TCP三個Port Triggering,這種設定方式是不用指定IP的,請注意畫面上的設定是沒打開(On)的,另外,設好後,右下角有個Save的按鈕,要按了以後才生效。


 


範例--設定UPnP/NAT-PMP:這個設定沒什麼好設的,只要確定有開啟就好,要用NAT-PMP的話,要先開UPnP,反正二個都打開就行,畫面上會顯示目前運作中的UPnP


 

理論上設有UPnP後,PC端應該就可以自動設定了,可是有時卻發現還是無效,原因可能是:
  • 你用Windows XP:UPnP需要手動開啟,請自行Google,Windows 7內定UPnP是開的
  • 軟體本身支援UPnP,但是Router卻沒開對應的Port:這可以手動設定


如何手動設定Router的UPnP對應 

以Bitcomet和eMule來說,二者都支援UPnP,但是打開UPnP後,BotComet可以連出去,但是eMule卻出現Low ID,在用Tomato前,用RT-10還出現二個程式即使是Port Triggering設好了,都不能動的狀況,應該可以想成這二支程式在當時,只設定好作業系統的UPnP映射?

手動設定Router的Port Mapping
以Windows 7為例,其中一個設定方式如下:




  • 打開網路和共用中心,點開下圖中的網路圖示:

 
網路結構下,應該會看到分享器(UPnP Router):




  • 按右鍵,選內容後,按下設定:


上面列出已經設定好的Mapping,其中BitComet二個是程式自己設的,eMule是我設的:


 

    為何eMule在它的程式中設定用UPnP後,還是出現Low ID? 因為它不支援NAT-PMP,無法主動設定Router上的Mapping,而BitComet有支援NAT-PMP,它會告訴Router相關的設定,這就是為何同樣支援UPnP,但是eMule設了卻沒用的原因。
     
  • 如果要新增的話,按下新增按鈕即可:





eMule和Port Forwarding / Port Triggering / UPnP
eMule雖然有UPnP的設定,可惜的是並不能正常運作,就連Port Triggering都有非常不穩定,所以最安全的方法,還是用最古老的Port Forwarding吧!