2011年3月28日 星期一

simple & clean daemon code

This blog is original from here: [ uCdot ]

Here the little trick is :
Use option '-D' as a 'differentiate mark' of daemon process
from the parent process. 
  
The second time it self exec(), means the daemon process
starting with -D option, which make it goes to the 'else' block :

It's a Clean and Simple example!
#

2011年3月12日 星期六

uClinux 新手筆記

如果想要知道一些概念,這篇是很好的總整理:
[ uClinux for Linux Programmers ]

大致上的摘要是這樣:
  uClinux 給沒有 MMU 的 CPU 使用,因此不支援原來
  Linux 的 Virtual Memory (VM) 環境。

  沒有 VM,process 不能於 run time 時期增加 process
  address space,所以 brk/sbrk() 無法被實做,
  也不能用 tmpfs,因為它依賴於 VM 的支援。

  沒有 VM,每一支 uClinux app 都要在 run time 時由系統來作 relocation。
  而且是 sequential && contiguous. 的排在 file system 內,一次就得載入
  整個程式 於連續的 physical memory 上,所以只能用 romfs。

  傳統的 power of 2 memory allocation 機制在這裡會造成許多浪費
 (例如要 33k 會給 64k),所以可選其他的 memory allocation 機制
  ,例如 page_alloc2 或 kmalloc2。
  page_alloc2 以 4k 為單位分配 (例如要 33k 會給 36k)
  kmalloc2 以 8k 為判斷,大於 8k 的需求從 free memory 的底部拿,
  小於 8k 的從 free memory 的起始處拿。這樣的好處是減少由
  短暫而多次的 allocation --- 如網路程式的 buffer --- 引起的碎片問題。

  沒有 VM,對應用程式來說,就沒有 dynamic stack 可用,一旦程式超出
  stack 範圍,會引發不可預期的結果。程式要自己知道需要多大的 stack,
  在 compile time 就必須決定好。
  heap 也不能使用 VM 機制,所以 uClinux 使用了 kernel free memory
  當作一個大的 system memory pool.
 
  對於應用程式與程序來說,uClinux 沒有提供 fork();只提供替代的 vfork(),
  有別於 fork(),使用 vfork() 會使得 parent process suspend 直到
  child process  結束 或 執行 exec() 為止

  fork() 發生後,parent & child process 有各自的資源 (address space 與 stack),
  parent & child process 沒有任何共用的東西。
  反觀 vfork() ,它會使得 child process 與 parent process 共用 stack。
  因此 vfork() 後,parent process suspend 了,若此時 child process 從現在的
  stack frame 返回上層,則會影響到 parent  process stack ---
  應用程式必須自行注意,確保不會發生這種情形!(心得:難怪
  網路上有人建議 busybox API 加上 fork_and_exit())!
  另外,child process 也必須使用 _exit() 而不能用 exit() ,
  原因也是因為 stack 共用。

  沒有 VM,uClinux 的程式只能使用 flat executable format (bFLT),
  這有兩種型態:
  一、code text & data 都是 relocatable
  二、Compile 出 PIC 碼 (Position Independent Code)
         只有部份 data 需要 relocation 即可。
  其中第二項衍生出 XIP (eXecute In Place) ,就是程式可以直接在 ROM
  上面執行的方式,因為 ROM 是 read only,可以被多個 instance share 使用。

  因為 romfs 上面的程式是 contiguously 排放的,這使得 romfs 是唯一可支援
  XIP 的 file system。
  從這裡可推出這樣的關係:做出 XIP 系統 需要 compiler 支援 PIC 碼。目前
  只有 m68k & ARM 有這樣的 gcc compiler.

  編出 bFLT 的程式,其實就是先編出 ELF 格式,再由 linker 轉換。只要
  compile 選項使用 -Wl,-elf2flt 即可作到。另外例如 -Wl,-elf2flt=s16384 這樣
  可以指定 stack 為 16k,toolchain default stack is 4k。(心得:有時
  default 是不夠的)

  再來談到 shared library,僅僅想用gcc -shared 選項,無法幫你在 bFLT
  格式中製作  shared library。(心得:下面有 Analog Device 網站上
  的好文詳細描述如何製作 shared library for uClinux)
  這裡只提一個重要概念,shared  library 必須是 XIP ,否則在每個
  uClinux application 都會產生一份 copy --- 這種情形比 static linking
  還要糟糕!

  結論:伴隨著 NOMMU,uClinux 衍生出這些 與 Linux 的不同處
             uClinux 應用程式開發者,需要自行注意。
摘要(完)

[ 認識 bFLT ],當然增加概念,但是對於開發程式,沒有直接幫助。

另外,下面這幾篇好文,並沒有排在 google 的前面,但是對於在 uClinux
下開發程式, 極有幫助,特此紀錄之。
1.  Executable file formats
2.  elf2flt 的說明
3.  用 flthdr (flat header)工具來看 bFLT 檔案
4.  Creating Libries

一些 uClinux mailing list 的摘要:
[ Problems building for uClinux ]: Jamie Lokier 有教讀者一些 narrow down problem 的方法,很實用!
還有遇到 error: no memory region specified for loadable section `.plt` 的現象,是因為 linker 遇到 .plt .got ,使其無法 link 成 BFLT program--- 這個 error 在 porting  program for uClinux 時很常遇到.

1. BFLT program 的製作 ,其實就是 compile 出 elf 後,再用 elf2flt  轉換成 BFLT format program,一般都用 CFLAGS += -elf2flt 告訴 compiler 在 link time 時幫我們轉換。

2. 若您的程式有自己的 lib ,而且是 static link 的方式,則 lib 先只是作成 elf ,然後 archive 起來 ,用 ranlib 做出 library index (方便 linking ,可有可無),等到和 program linking 時才使用 elf2flt  轉換成 BFLT.

#



2011年3月11日 星期五

linux serial port programming : CLOCAL 的設定

先來看 Carrier Detect (CD) signal line 的意義。
節錄自 "Serial Communication / Mark Nelson" 一書 :
"Unfortunatly, before the era of intelligent modems, some terminals
or other DTE equipment were designed to treat a modem as unusable
without CD. Devices such as these would not send or receive
characters to a modem that had CD low. Because of these anachronisms,
most modems built today can keep CD high at all times, whether or not
a carrier has been established.

Because these feature is sometimes the default mode of operation,
using CD for accurate detection of carrier presence is somewhat risky.
However, most users should be able to configure their modems so as to
disable this troublesome behavior
."

中文口白一下:以前時代,CD 是 modem (DCE 端) 用來告訴 終端機 (DTE 端) 說:
我有連到對方喔!但是後續的 modem (DCE) 有的已經不照這種約定了---
不管有沒有跟遠端連線,一律拉 CD 起來。
所以 DTE 根據 CD 判斷 DCE 有無與對方連線的方式,已經不可靠了。
所以現在 DTE 必須可以 configure設定,不要再看這個不可靠的 CD signal.

怎樣 configure ? Linux serial driver 提供這樣的 flag --- termios 屬性若有設定
CLOCAL ,在 2.6.28 generic_serial.c ::
uart_change_speed():
{    ...
    if (termios->c_cflag & CLOCAL)
        state->info->flags &= ~UIF_CHECK_CD;
    ...
}

那 UIF_CHECK_CD 有何作用呢?

uart_handle_dcd_change(struct uart_port *port, unsigned int status)
{  ...
    if (info->flags & UIF_CHECK_CD) {
        if (status)
            wake_up_interruptible(&info->port.open_wait);
        else if (info->port.tty)
            tty_hangup(info->port.tty);
    }
    ...
}

也就是說,有 UIF_CHECK_CD 時,就 wake up 正在等待 open 的 process,
或是 hangup tty,這些都是在 CD signal change 時本來預定的動作。
 
所以在這裡,設定 CLOCAL 可以 "遮蔽" 對於 CD 訊號的判斷。
若您的應用程式 open serial port 時,忘記設定 CLOCAL,
就會照者書上所說的操作定義 --- 因為 DTE 發現 DCE 的 CD 不見了,
就 hang up tty 了。
#