2008年12月5日 星期五

詳解ttysnoops

前言:
ttysnoops是一個監視文字console的一個小工具,如果在embedded system開發環境,通常是使用com port或是使用telnet ssh之類的方法去做溝通。但是如果你的機器並不在你身邊,你卻想要知道你寫的程式過得怎樣,一個人在遠方是否有什麼異狀,想要知道它輸出的訊息?
這時該怎麼辦? 這時就會需要用到ttysnoops了。

原理:
ttysnoops 需要在執行login之前先被執行。ttysnoops執行時,如同ssh一樣,會先開一對/dev/ptm、/dev/pts/x。
然後會用execv來執行login,並且使用dup2來轉移login的stdio到/dev/pts/x上面,如此一來ttysnoops就可以利用對應的/dev/ptm來做存取。

解析source code:
ttysnoops會先開啟一個/dev/ptm,kernel會自動生出一個/dev/pts/0出來,find_ptyxx中,ttyfd可能是/dev/pts/0,dup2將ttyfd複製給stdio。 如此一來,這個行程(ttysnoops的子行程)的所作所為就會反映到/dev/pts/0,而不會在stdio上,又/dev/pts/0對映到/dev/ptm,因此ttysnoop可以讀寫/dev/ptm來達成與(ttysnoops的子行程)溝通。所以ttysnoops稍後會有一個處裡,也就是查看ptyfd(/dev/ptm)若有資料,會寫到ttysnoops的stdio,來讓使用者以為一切都很正常。
因此稍後執行login以後,它所顯示的東西會寫到/dev/pts/0上面,而不會顯示在stdio上,又因為父行程(ttysnoops)繼續執行去監視ptyfd(/dev/ptm),就會感覺是直接跟login直接溝通,但其實資料流已經透過ttysnoops攔截下來了。如果有一個client連進來後,ttysnoops又會fork出一個子行程,然後它會開啟一個/var/spool/ttysnoops/0這個named socket,然後再一次使用dup2將stdio導向到這個socket,如此一來,login的所作所為就有兩個行程會知道了,ttysnoopys以及連進來監視的client。
使用情境:
1. 當執行login以後,login會輸出login:的字樣,提示輸入帳號
2. 此時login只會寫到ptyfd上面,因此ttysnoop會將這個字串讀出並寫入自己的stdout
3. 這時候本機上就顯示login:了
4. 如果本機上打字進去,會由ttysnoop先收到,收到以後就寫給ptyfd,然後login就會去做後續工作....
5. 這時,有client登入了,登入以後,如果ttysnoops從ptyfd讀出東西,就會輸出給他自己的stdout,當然就也會輸出給authfd
6. 若是client打字進來,authfd收到以後,因為他對應到ttysnoops的stdio,所以ttysnoops也會從他的stdin收到字串,收到以後就會使用write寫給pthfd
下載連結:

2008年8月31日 星期日

做案子真的需要UML

今天買了一本書叫做OCUP UML初級認證攻略,作者是邱郁惠,她寫了不少關於系統設計的書。


這一本我索性的買了下來,因為這本書給了一個目標就是考取UML的初級認證,終於有一個學習UML的目標了。如果沒有一個認證,在公司裡面真的很難有人會相信你、認同你使用UML來描述系統。我是認為UML絕對是非常直得學習的語言,因為一張圖可代表千言萬語,也非常有助於愛開會的台灣公司,有一個可以開會討論的工具。不要每次開會都是天馬行空,開完後沒有任何結果與紀錄。

開發嵌入式系統更是需要這類的工具,因為這種專案不是只有跟某一種領域的人交談,而是跟軟體、硬體、業務、PM、工廠等等...各種不同專業不同個性的人合作。

2008年8月23日 星期六

handle class in C language

在C++中有一種模組設計的技巧叫做handle class,其宗旨就是要讓封裝的特性更強烈。只提供一個handle來控制這個物件,其他所有資料均不開放。而在C語言裡面,要怎麼弄出一個handle clasee呢?我在此提供我的方法:

1. 首先我的習慣是一個.c檔配一個.h檔,而這一組就是相當於一個class,相信很多人也都這樣做。
2. 所有的Globol variable與private function都使用static宣告,讓其他.c無法使用,也避免掉重複宣告的困擾。
3. 在.h檔裡面增加define如下

////////////////////test.h/////////////////////////
#ifdef TEST_C

struct{

int a;
int b;
int c;

}test

#else

void test_hanle;

#endif


extern void test_init( struct test *test_handle);

/////////////////////////////////////////////////////

如此一來只要在test.c裡面宣告#define TEST_C就可以讓tset.c只看到他自己的成員們,但是別的.c檔想要來#include "test.h"的時候,就只能看到test這個模組釋放出來的函式,以及一個handle---void test_hanlde,那所有的function都可以設計成必須要傳入test_handle 才能使用這個模組。

如果test.c裡面有修改到什麼實作細節,也不會影響到include "test.h"的上層程式。因為其他的.c檔,只會參考到test.h裡面的void teset_handle而已。所以編譯的時候,只會編到test.c為止。

2008年5月27日 星期二

Father process is killed by a signal after calling system()

大家都知道system()是在程式裡面執行shell命令的函式,它裡面會使用fork去創造一個shell行程,並且用shell行程去執行shell命令。但是man裡面並沒有提到他會發出一個signal 17,有些版本的Linux系統收到此signal後,會執行Term的動作,此網頁有詳細介紹:http://linux.about.com/od/commands/l/blcmdl7_signal.htm

為了避免system()會因為它裡面所開的子行程要結束,而送出signal 17,必須要在安裝一個signal的時候所使用的sigaction函式,加上SA_NOCLDSTOP的flag。才不會讓父行程收到signal 17,這樣才不會無緣無故的呼叫system後父行程因為system()而死掉。

這邊提醒一下,不是只有這個signal要擷取。而是所有的signal都需要擷取下來,然後做妥善的處理。

2008年5月10日 星期六

呼叫pthread_cancel發生segmentation fault

可能是因為pthread_cancel裡面是使用動態記憶體配置,如果拿同一個pthread_t傳入pthread_cancel兩次,那麼第二次呼叫的時候就會收到SIGSEGV信號。這個問題通常是沒做好資源保護,而造成的race condition。

這個pthread_cancel一呼叫後,預設動作並不會馬上就把該thread給停掉,而是在某些system call裡面來做停止的動作,因此這些system call也就是所謂的cancel point。所以使用這個function時候需要非常非常的小心,因此我的建議是在你的一生中,都不要用這個function....。或許太嚴重了,不過真的要非常小心才是。因為還有非常多方法可以避免掉呼叫這個function,來結束一個thread

所以一個thread,最好幫他設計一個Finite State Machine(FSM),藉由狀態的控制,來改變thread的行為。因為FSM的設計可以讓你限定這個Thread的狀態,狀態的切換之間可準確的控制資源的配置與釋放。如果使用一般無組織的flag來決定thread的運作,那這些flag的所有組合,你都要去測試一變,才能知道有無問題。

2008年4月21日 星期一

Linux的Messge queue簡介

Message queue應該是蠻常用的一種IPC,主要的特點是它能夠暫存不同型態的message,並且每一種型態都以Queue的存取方式來操作。比起share memory;Message Queue更能夠處理非同步的訊息。如果使用share memory的話,將會帶來非常多的同步問題,因為share memory只是一塊記憶體,沒有彈性去處理更多的資訊。而Message Queue卻可以讓訊息好好的排隊等著被處理來達成Producer & Consumer的處理模型 。

在Linux上面,可以用ipcs的shell指令來觀察目前所有的IPC資源使用情況:
#ipcs -s
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status

------ Semaphore Arrays --------
key semid owner perms nsems

------ Message Queues --------
key msqid owner perms used-bytes messages
0x000004d2 42631168 root 666 8 1
0x0000270f 42663937 root 666 2080 4
0x0000270e 42401794 root 666 0 0

一些使用法在Google上都可以找到,下面列出一些使用Message queue的重點:

1. 在Message Queue使用上來說,主要是靠一個號碼去跟Kernel要一個新的Message Queue。如果其他的行程也都用這個號碼開啟Message Queue的話,那每個行程都可以看到這個MessageQueue裡的東西。但是Message Queue可以存放著不同的型態的Message,因此各行程可以某個特定的形態去取得特定的Message。所以可以架構成多對多的通訊方式。

2. 如果任一行程將這個號碼的Message Queue做移除的動作,那正在操作Message Queue的行程都會讓msgrecv return -1。此時需要再去做message開啟的動作。

3. 如果msgrecv的返回值為-1而且errno=EINTR,這並不是因為message queue出錯,而是在等待message queue的同時,發生了signal中斷,因此kernel就會讓msgrecv返回-1,並且設定errno=EINTR。所以一定要去判斷errno,到底是為什麼傳回了-1。

2008年3月15日 星期六


今天到天瓏晃晃,想找看看有沒有新的書可以讓我充實一下。無意間看到這一本書就拿起來翻一翻,隨便一翻都會看到在職場上會碰到的問題,然後我就索性在天瓏給他買下來了。就如同書裡說的一樣,這本書已經是很多文章與經驗的菁華,也有非常多的引用,並不是唬爛的。它點出了一個軟體系統在實際寫程式前,需要做的功課有多重要。

蓋房子之所以能這麼快、這麼精準的在蓋完後就可以賣,全拜建築業早已有許多的流程與制度來輔佐設計師、工程師與工人。但軟體有沒有一些流程呢?可能有,但採用的公司非常的少。因為很多公司會認為軟體工程是不必要的,但奇怪的是這些公司在徵人的時候卻要找軟體工程師而不是程式設計師。這本書不是在講軟體工程的理論,而是告訴你如何做工程,才能以最短時間生出一個成功的軟體。

2008年3月5日 星期三

自己做的轉速表



這個轉速表是大學的時候做的。因為koso的轉速表要1000多,對學生來說真是一筆龐大的負擔。說難,程式其實也不是說很難寫。說簡單,要把這些電路手工塞到一個霧燈裡面是也不簡單了....尤其還要自己設計與裁剪電路板。我想只有對改車有一股熱誠才會做下去吧~~。如果也有車友想自己做,做個朋友,我可以指導你喔~~。
最近看到大千有出一個機車上的字幕機,感覺真的超炫的,不過居然要價3000上下。雖然是可以買來就直接裝上去,方便又很酷,但是在相關產業工作的人來說,這簡直是利潤蠻高的產品(但量很少)。所以我還蠻想要自己做一套的~~如果有車友有意思要開發可以跟我討論討論。

2008年3月1日 星期六

介紹Time-Triggered Cooperative Scheduler的書


前幾篇我分享的東西就是這一本書的內容。它是講Time-Triggered Cooperative Scheduler如何使用在8051上面來達到各種好處,我在這本書上面獲益良多。我認為大學內的8051課程要用這本當教科書才對,不然大多數的人都會認為寫8051就只是一些IO控制而已。
當然不只有單晶片能夠使用它,之前的分享文章也有提到在有OS的系統上面使用它會有什麼好處,那就請大家細細品嚐這本書囉~~~希望有機會能夠跟大家一起討論喔~~

2008年2月20日 星期三

Cooperative Schedular在有OS的嵌入式系統

如果你的系統是有OS的,Cooperative Schedular又能帶來什麼好處呢?

有許多人會覺得有OS的時候,就可以利用OS的各種API來達成延遲、計時的動作。因為我的工作環境是使用Linux,因此也能夠使用thread來做平行處理。但是有時候我只需要一個簡單的計時功能,計時到了就改變一個變數的值而已,這時也要用thread嗎?或許有人會說用OS提供的timer就可以了阿~~但是OS提供的Timer裡面大多都會用到system call來完成timer的工作,更有OS是新開一個thread來做timer的工作。這些有用到system call的API,最好不要太頻繁的使用,每呼叫一次都要做一次排程,每做一次排程就要context switch等一系列的動作。

但如果是使用Cooperative Schedular來做簡單的計時工作,就可以很快速的在user space來做計時的工作。而且因為每個Task都是在同一個thread上的,所以Task之間共用到的資源不需要再考慮到惱人的同步問題。如果大大小小的東西都用Thread來執行,只要是globol的變數都要去注意它是否有被其他thread所使用,否則就會有race condition的情形。而且Task間沒有資源同步問題,也相當於節省了記憶體的開銷(所有Task可以輪流使用同一塊記憶體)。

依據我的經驗來使用Cooperative Schedular的話,我會在一個Task裡面的動作不會block的情況下全部加入Cooperative Schedular裡面。所謂會block的API大約有:recv()、fread()、read()、usleep()、sleep()、sigsuspend()。

有這麼多利,當然也有弊啦~~jitter是Coooperative Schedular最麻煩的情況了。當某個Task花的CPU時間特別久,那就會導致其他的Task也都在等它做完。不過我是認為這種情況是可避免的,程式是自己寫的,一定會知道它停在哪邊。但如果有一種情況,那就是CPU的loading太高了,高到jitter情況發生。那其實也沒辦法,因為CPU loading太高的話,就算是開thread一樣會lag。

2008年2月19日 星期二

Cooperative Schedular在無OS的嵌入式系統

Cooperative Schedular能夠在小型嵌入式系統提供什麼樣的好處呢? 就拿一般的8051的範例來說,很多的範例所做的延遲功能(Delay),或許是用在LED需要的閃爍延遲、或許是IC的spec所需要的延遲,絕大多數都是使用loop來做:
void delay_10ms( int delay)
{
while( delay ) delay--;
}
然後去微調delay的數量來達到需要的delay時間。如果是只要延遲幾個clock還可以,但是如果是要延遲更長的時間,使用這種方式無疑是讓你的機器做白工。因為在loop的時候,你的CPU是100%的時間都在做一件事情,那就是一直在執行while這個動作。為什麼不想個辦法讓這個工作正在延遲狀態的時候,讓CPU去做別的事情,或是CPU沒事做的話就進入省電模式。等到延遲時間到了以後,CPU才再繼續動作。

但是如果使用Time-Triggered Cooperative Schedular來做這件事情將會非常的有效率,可以讓CPU在有工作的時候去動作。可以很容易的控制每個工作的延遲時間與執行週期,以至於可以在延遲期間或是沒有工作需要執行的時候進入省電模式,降低溫度與耗電。

另外,要怎麼去設計程式,才可以讓一個Task不需要busy loop就可以利用Cooperative Schedular達成延遲的效果呢?過幾天我拿鍵盤掃描的例子來跟大家分享。

我的嵌入式系統觀念

自從計算機的發明到現在個人電腦的普及,電腦帶動了整個世界的進步,我們利用電腦來操作繁雜的動作或是運算複雜的演算法,當電腦中的處理器越快,就能夠更快的得到我們要的結果,因此在過去的處理器著重的是速度。但現在對於電腦產品的需求已不再是速度,而是多樣化。在個人電腦普及的時代,有許多的工作都能夠在同一台電腦上完成,若是需要特別的功能,只要硬體資源足夠,都能夠利用撰寫軟體來達成該功能,因此個人電腦是一台通用的電腦。但現在有很多的應用是不需要像個人電腦這樣運算功能強大的硬體,像是在PC上可以播放mp3,但有更大的市場需要mp3能夠隨身攜帶,因此設計一個特殊的硬體以及軟體,讓mp3能夠在省電、體積小、價格便宜的市場需求下實現出來。因此mp3播放器可稱為嵌入式系統。而嵌入式系統是在最近幾年才有的概念嗎?那可不,在10多年以前,日本知名公司出產的電視遊樂器,想要玩何種遊戲就插什麼卡,在主機以及卡帶上都有可程式化的處理器,所以早在十多年前日本人就已經大量的利用嵌入式系統了。如果一台PC拿來作為監視系統的平台,算不算是嵌入式系統?我相信許多人的答案是肯定的,因為這個時候PC上的軟體只針對監視系統的各種需求來設計,並不會拿來作為其他用途,因此可稱為嵌入式系統。

嵌入式系統在現在的生活中早已與我們密不可分了,像是手機、汽車的行車電腦、熱水器、瓦斯爐等等,都是嵌入式系統的一環,隨著處理器的進步,嵌入式系統只會越來越多,並且一步步地提供我們更好的生活。

嵌入式系統是根據不同的需求,來設計不同的硬體以及軟體,以達到成本、利益與需求的平衡。所以相對於個人電腦,嵌入式系統是一個依據特殊需求所設計的一個系統,在設計階段不僅包含了微電腦軟硬體緊密的設計,也要考量到不同領域的合作。像是美國太空總署所開發的火星探測車至少就包含了控制、太空科學、通訊等許多專業領域的結合,並且利用微電腦來將各領域所製造的模組整合起來,使其穩定的工作。因此開發一個嵌入式系統需要與各種領域的開發人員互相合作,並且以軟硬體緊密的結合達到系統功能完全的符合規格,所以嵌入式系統不是只有一個人就能完成的系統,而是要與各個不同領域的工程師互相合作。

有很多人初學嵌入式系統都有一個疑問:一個過去稱為微處理機系統或是微電腦系統的裝置,為何現在有另一個名稱叫做嵌入式系統?嵌入式系統的原文是Embedded system,Embedded是一個形容詞,意思是「被放入的」,而Embedded system照字面上的翻譯是一個「被放入的系統」,聽起來感覺是一個未完成的字彙,到底一個系統會被放入什麼東西呢?那就是—微電腦,一個可程式化的微電腦被放入到一個系統中就可稱為嵌入式系統。而嵌入式系統可大約分為下列幾種:

1. 小型嵌入式系統(通常無OS、至少一個人可完成軟硬體設計,如:來電顯示器)
2. 中型嵌入式系統(有OS、一個研發團隊可完成,如:Wii、電腦字典、手機)
3. 大型嵌入式系統(有OS、跨研發團隊、跨公司,如:飛行模擬系統)

Cooperative Schedular(協同排程)介紹

這文章跟大家分享的是協同工作,比較算是討論嵌入式系統的軟體設計部份。這種性質的工作在一個嵌入式系統內是非常必要的一種機制。 如果你想要減少你系統中開thread的數量、如果你想要在8051中妥善的使用CPU資源,那你絕對需要知道如何設計Cooperative Task。
嵌入式系統是一個使用微電腦的軟硬體緊密結合以及其他領域共同開發的系統,而這個系統是用來滿足某一個功能。由於中大型的嵌入式系統所使用的硬體效能足以加入作業系統,讓不同領域的工程師得以自由的撰寫程式,而不必處理太低階的軟硬體資源分配,因為作業系統都有很好的機制來管理這些資源。

過去開發小型嵌入式系統的時候,也許是因為處理器的效能以及記憶體的容量過小,通常是由一個人使用組合語言完成,雖然使用組合語言能夠發揮處理器的最高效能,但可讀性非常的差,導致系統無法由另一個人維護。相當於開發完以後,這個機器就是一個能力很強的深宮怨婦。而現在的微控制器不論速度以及容量都提升不少,但價格卻是越來越便宜。當嵌入式系統的市場需求越來高,很難再由一個人來完成整個系統的時候,就算是小型的嵌入式系統,也需要一個有架構的設計,讓開發團隊參與並且互相合作。在小型嵌入式系統中,通常使用微控制器來開發,若是在上面跑正規的作業系統,將會變成一個龐大的負擔。但是又要讓各個開發人員共同使用有限的資源。這時就非常需要有一個Schedular來管理很多的Cooperative Task。

Cooperative Schedular在一個系統中,就像是一個德國的高速公路,每一台車都要以最快的速度通過高速公路。如果只有單線道,而且有任何一台車停下來,將會導致塞車。如果塞車的時間並沒有嚴重到任何一台車到達目的的時間,那就沒問題。如果太嚴重,則會發生一種叫做jitter的現象。而jitter也就是Cooperative Schedular最需要改善、探討的議題。但在一般的情況下可以將軟即時的Task放在Cooperative Schedular裡面,而需要即時的工作則是利用thread(有OS)或是ISR(無OS)裡面來執行。所以如果把高速公路比喻成Cooperative Schedular來使用CPU,則可以看成:
一般的單晶片就是單線道,如果是在有支援平行處理的OS上,一個Cooperative Schedular跑的thread就是一條線道。而沒有跑Cooperative Schedular的thread可以看作是交流道外的道路。這個比喻各位看倌有feel了嗎?