Monday, February 23, 2009

Stack Backtracing Inside Your Program

If you usually work with non-trivial C sources, you may have wondered which execution path (that is, which sequence of function calls) brought you to a certain point in your program. Also, it would be even more useful if you could have that piece of information whenever your beautiful, bug-free program suddenly crashes, and you have no debugger at hand. What is needed is a stack backtrace and, thanks to a little known feature of the GNU C library, obtaining it is a fairly easy task.

Stack Frames and Backtraces

Before diving into the article, let's briefly go over how function calls and parameters pass work in C. In order to prepare for the function call, parameters are pushed on the stack in reverse order. Afterwards, the caller's return address also is pushed on the stack and the function is called. Finally, the called function's entry code creates some more space on the stack for storage of automatic variables. This layout commonly is called a stack frame for that particular instance of the function call. When more function calls are nested, the whole procedure is repeated, causing the stack to keep growing downwards and building a chain of stack frames (see Figure 1). Thus, at any given point in a program it theoretically is possible to backtrace the sequence of stack frames to the originating calling point, up to the main() function (to be exact, up to the libc function, which calls main() when the process starts up).

Figure 1. Nested Function Calls

Stack Backtracing from within GDB

Getting the stack backtrace with GDB (or an equivalent graphical front end) for a program that crashed while running is straightforward: you simply issue the bt command, which returns the list of functions called up to the point of the crash. As this is a standard practice, we do not provide any more details here; have a look at the GDB info page if you need specifics (info gdb stack gets you there).

Stack Backtracing Using libc

If for some reason you're not running inside a debugger, two options are available for tracing what the program is doing. The first method is to disseminate it with print and log messages in order to pinpoint the execution path. In a complex program, this option can become cumbersome and tedious even if, with the help of some GCC-specific macros, it can be simplified a bit. Consider, for example, a debug macro such as

#define TRACE_MSG fprintf(stderr, __FUNCTION__     \
"() [%s:%d] here I am\n", \
__FILE__, __LINE__)

You can propagate this macro quickly throughout your program by cutting and pasting it. When you do not need it anymore, switch it off simply by defining it to no-op.

A nicer way to get a stack backtrace, however, is to use some of the specific support functions provided by glibc. The key one is backtrace(), which navigates the stack frames from the calling point to the beginning of the program and provides an array of return addresses. You then can map each address to the body of a particular function in your code by having a look at the object file with the nm command. Or, you can do it a simpler way--use backtrace_symbols(). This function transforms a list of return addresses, as returned by backtrace(), into a list of strings, each containing the function name offset within the function and the return address. The list of strings is allocated from your heap space (as if you called malloc()), so you should free() it as soon as you are done with it.

If you prefer to avoid dynamic memory allocation during the backtrace--reasonable, as the backtrace is likely to happen under faulty conditions--you can resort to backtrace_symbols_fd(). This prints the strings directly to the given file descriptor and does not allocate new memory for strings storage. It is a safer choice in those cases where memory heap potentially is corrupted.

In order to convert an address to a function name, the last two functions rely on symbol information to be available inside the program itself. To enable this feature, compile your program with the -rdynamic option (see man dlopen for more details).

Listing 1. How to Use the Backtrace Functions

Listing 1 demonstrates how to use these functions. The test() function calls either func_low() or func_high(), both of which call show_stackframe() to print out the execution path. The program is compiled with

gcc -rdynamic listing1.c -o listing1

The output should look something like:

Execution path:
./listing1(show_stackframe+0x2e) [0x80486de]
./listing1(func_high+0x11) [0x8048799]
./listing1(test+0x43) [0x80487eb]
./listing1(main+0x13) [0x8048817]
/lib/libc.so.6(__libc_start_main+0xbd) [0x4003e17d]
./listing1(backtrace_symbols+0x31) [0x80485f1]
First call: 167
Execution path:
./listing1(show_stackframe+0x2e) [0x80486de]
./listing1(func_low+0x11) [0x8048779]
./listing1(test+0x21) [0x80487c9]
./listing1(main+0x33) [0x8048837]
/lib/libc.so.6(__libc_start_main+0xbd) [0x4003e17d]
./listing1(backtrace_symbols+0x31) [0x80485f1]
Second call: -3

By the way, function prototypes for the backtrace functions reside in the header file execinfo.h.

One Step Farther

At this point, we have in hand a tool that is able to print the list of function calls up to the current execution point. This can be a useful tool in many different contexts. Think of having a complex program and needing to know who's calling a given function with the wrong parameters. With a simple check and a call to our show_stackframe() function, the faulty caller can be spotted easily.

An even more useful application for this technique is putting a stack backtrace inside a signal handler and having the latter catch all the "bad" signals your program can receive (SIGSEGV, SIGBUS, SIGILL, SIGFPE and the like). This way, if your program unfortunately crashes and you were not running it with a debugger, you can get a stack trace and know where the fault happened. This technique also can be used to understand where your program is looping in case it stops responding. All you need to do is set up a SIGUSR1/2 handler and send such a signal when needed. Before presenting an example, we need to open a parenthesis on signal handling.

Signal Handling and Stack Frames

Backtracing from within a signal handler requires some interesting intricacies that take us on a little detour through signal delivery to processes. Going into deep detail on this matter is outside the scope of this article, but we briefly can summarize it this way:

  • When the kernel needs to notify a signal of a given process, it prepares some data structures attached to the process' task struct and sets a signal-pending bit.

  • Later on, when the signalee process is scheduled for execution, its stack frame is altered by the kernel in order to have EIP point to the process' signal handler. This way, when the process runs it behaves as if it had called its own signal handler by itself before being suspended.

  • The initial steps of user space signal management are taken care of inside libc, which eventually calls the real process' signal handling routines which, in turn, execute our stack backtrace function.

As a consequence of this mechanism, the first two entries in the stack frame chain when you get into the signal handler contain, respectively, a return address inside your signal handler and one inside sigaction() in libc. The stack frame of the last function called before the signal (which, in case of fault signals, also is the one that supposedly caused the problem) is lost. Thus, if function B called function A, which in turn caused a SIGSEGV, a plain backtrace would list these entry points:

your_sig_handler()
sigaction() in libc.so
func_B()
main()

and no trace of the call to function A would be found. For more details, have a look at the manuals for signal() and sigaction().

Back to Backtrace

In order to get a meaningful backtrace, we need a workaround. Luckily, when you have the sources of both the kernel and libc, you can find a workaround for nearly anything. In Listing 2 we exploit an undocumented parameter of type sigcontext that is passed to the signal handler (see the UNDOCUMENTED section in man sigaction) and contains, among other things, the value of EIP when the signal was raised. After the call to backtrace(), we use this value to overwrite the useless entry corresponding to the sigaction() return address in the trace array. When we later call backtrace_symbols(), the address we inserted is resolved the same as any other entry in the array. Finally, when we print the backtrace, we start from the second entry (i=1 in the loop), because the first one always would be inside our signal handler.

Listing 2. Using sigcontext

Since kernel version 2.2 the undocumented parameter to the signal handler has been declared obsolete in adherence with POSIX.1b. A more correct way to retrieve additional information is to use the SA_SIGINFO option when setting the handler, as shown in Listing 3 and documented in the man page. Unfortunately, the siginfo_t structure provided to the handler does not contain the EIP value we need, so we are forced to resort again to an undocumented feature: the third parameter to the signal handler. No man page is going to tell you that such a parameter points to an ucontext_t structure that contains the values of the CPU registers when the signal was raised. From this structure, we are able to extract the value of EIP and proceed as in the previous case.

Listing 3. Using the SA_SIGINFO Option

Hazards and Limitations

A couple of points are important to keep in mind when you use the backtrace functions. First, backtrace_symbols() internally calls malloc() and, thus, can fail if the memory heap is corrupted--which might be the case if you are dealing with a fault signal handler. If you need to resolve the return addresses in such a situation, calling backtrace_symbols_fd() is safer, because it directly writes to the given file descriptor without allocating memory. The same reasoning implies that it is safer to use either static or automatic (non dynamic) storage space for the array passed to backtrace().

Also, there are some limitations to the ability of automatically tracing back the execution of a program. The most relevant are some compiler optimizations that, in one way or another, alter the contents of the stack frame or even prevent a function from having one (think of function inlining). Obviously, the stack frame does not even exist for macros, which are not function calls at all. Finally, a stack backtrace is impossible to perform if the stack itself has been corrupted by a memory trash.

Regarding symbol resolution, the current glibc (version 2.3.1 at the time of this writing) allows users to obtain the function name and offset only on systems based on the ELF binary format. Furthermore, static symbols' names cannot be resolved internally, because they cannot be accessed by the dynamic linking facilities. In this case, the external command addr2line can be used instead.

Inner Workings

In case you wonder how would you access stack information in a C program, the answer is simple: you can't. Stack handling, in fact, depends heavily on the platform your program runs on, and the C language does not provide any means to do it in a standard way. The implementation of backtrace() in the glibc library contains platform-specific code for each platform, which is based either on GCC internal variables (__builtin_frame_address and __builtin_return_address) or on assembly code.

In the case of the i386 platform (in glibc-x.x.x/sysdeps/i386/backtrace.c), a couple of lines of assembly code are used to access the contents of the ebp and esp CPU registers, which hold the address of the current stack frame and of the stack pointer for any given function:

register void *ebp __asm__ ("ebp");
register void *esp __asm__ ("esp");

Starting from the value of ebp, it is easy to follow the chain of pointers and move up to the initial stack frame. In this way you gather the sequence of return addresses and build the backtrace.

At this point, you still have to resolve the return addresses into function names, an operation dependent on the binary format you are using. In the case of ELF, it is performed by using a dynamic linker internal function (_dl_addr(), see glibc-x.x.x/sysdeps/generic/elf/backtracesyms.c).

Conclusion

Are you working on a complex program that contains a lot of different execution paths that make you cluelessly wander through hundreds of functions, desperately trying to understand which one called which other function? Wander no more and print a backtrace. It's free, fast and easy. While you are at it, do yourself a favour and also use that function inside a fault signal handler--it's guaranteed to help you with those nasty bugs that appear once in a thousand runs.

Gianluca Insolvibile has been a Linux enthusiast since kernel 0.99pl4. He currently deals with networking and digital video research and development.

Interactive Linux Kernel map
















Java script 版

Resources for Tracing Linux

Unix下工具
grep: “grep [option] …pattern… [file] ”
ex : grep –ri return rtlcore.c
無敵的指令,雖然可能找很久
ctags: “find -name ‘*.[ch]’ | xargs ctags”
這樣檔案tags裡就有各種關鍵字的索引了
cflow: “cflow –r fun_name *.c”
產生call graph
c2html: “c2html <> file.html”

結構圖繪制工具
Jude
http://objectclub.esm.co.jp/Jude/

Sunday, February 22, 2009

耶和華所賜的福使人富足,並不加上憂愁。

耶和華所賜的福使人富足,並不加上憂愁。(箴言10:22)

The blessing of the LORD brings wealth,
and he adds no trouble to it. (Proverbs 10:22)

Saturday, February 07, 2009

x86 32bit call backtrace

需include

driver可以用dump_stack() 這個func來back trace
不過還沒有試過,能不能work還未知

底下是x86 32bit的實作
http://lxr.linux.no/linux+v2.6.27.2/arch/x86/kernel/traps_32.c#L288
288void dump_stack(void)
289{
290 unsigned long bp = 0;
291 unsigned long stack;
292
293#ifdef CONFIG_FRAME_POINTER
294 if (!bp)
295 asm("movl %%ebp, %0" : "=r" (bp):);
296#endif
297
298 printk("Pid: %d, comm: %.20s %s %s %.*s\n",
299 current->pid, current->comm, print_tainted(),
300 init_utsname()->release,
301 (int)strcspn(init_utsname()->version, " "),
302 init_utsname()->version);
303
304 show_trace(current, NULL, &stack, bp);
305}
306
307EXPORT_SYMBOL(dump_stack);

Thursday, February 05, 2009

Wednesday, February 04, 2009

用Open Source工具開發軟體: 新軟體開發關念

http://www.freebsd.org.hk/html/cyril/x1249.html

http://lxr.linux.no/linux+v2.6.27.2/arch/x86/kernel/traps_32.c#L453

Enable Backtrace

Enable Backtrace

April 18th, 2007 · 3 Comments

最近 Linux kernel 2.4 的 Backtrace 不見了, 這樣實在非常不好 Debug,
查了一下才發現, 少加了一些 Flags.

原來會顯示(部份)

Process swapper (pid: 1, stack limit = 0xc030a368)
Stack: (0xc030bfc0 to 0xc030c000)
bfc0: c0042410 c00424a8 c030a000 c020f558 c0011118 c030a000 c020f558 c0200d10
bfe0: 000191cc c00430d8 c00430a4 c01fe000 c0237948 c0046974 c4a57686 1b469a8c
Backtrace: no frame pointer
Code: c0237ba0 e92d40f0 e3a04000 e1a05004 (e5854000)
Kernel panic: Attempted to kill init!

這時是沒有 frame pointer , 這時在 compile 時加上參數 -fomit-frame-pointer
就可以了. 以 Linux 2.4 ARM Platform 為例, 請在 arch/arm/Makefile 的 cflags 加上
這個參數
加了以後, 程式有問題就會顯示

Process swapper (pid: 1, stack limit = 0xc0efa368)
Stack: (0xc0efbf9c to 0xc0efc000)
bf80: c0042a70
bfa0: c0042b08 c0efa000 c0217558 c0efbfd8 c0efbfbc c00114cc c0011820 c0efa000
bfc0: c0217558 c0208d10 00019834 c0efbff4 c0efbfdc c00430e0 c00114c8 c00430a4
bfe0: c0206000 c023f948 00000000 c0efbff8 c0046a54 c00430b4 00000000 00000000
Backtrace:
Function entered at [] from []
r7 = C0217558 r6 = C0EFA000 r5 = C0042B08 r4 = C0042A70
Function entered at [] from []
Function entered at [] from []
r6 = C023F948 r5 = C0206000 r4 = C00430A4
Code: e92dd8f0 e24cb004 e3a04000 e1a05004 (e5854000)
Kernel panic: Attempted to kill init!

但是這一堆 Code, 實在是看不懂, 那要怎麼辦呢? 還好 Linux kernel 2.4 有提供一個
Tool: ksymoops 可以用.
執行指令
ksymoops -m System.map

將 Backtrace 那一段貼上去

Backtrace:
Function entered at [] from []
r7 = C0217558 r6 = C0EFA000 r5 = C0042B08 r4 = C0042A70
Function entered at [] from []
Function entered at [] from []
r6 = C023F948 r5 = C0206000 r4 = C00430A4
Code: e92dd8f0 e24cb004 e3a04000 e1a05004 (e5854000)
Kernel panic: Attempted to kill init!
Backtrace:
Function entered at [] from []
r7 = C0217558 r6 = C0EFA000 r5 = C0042B08 r4 = C0042A70
Function entered at [] from []
Function entered at [] from []
r6 = C023F948 r5 = C0206000 r4 = C00430A4
Code: e92dd8f0 e24cb004 e3a04000 e1a05004 (e5854000)


就會得到結果

Trace; c0011810 <$a+0/0>
Trace; c00114cc

>>r7; c0217558 <__machine_arch_type+0/4>
>>r5; c0042b08 <__initcall_end+0/4f8>
>>r4; c0042a70 <$d+0/0>

Trace; c00114b8 <$a+0/0>
Trace; c00430e0
Trace; c00430a4
Trace; c0046a54

>>r6; c023f948
>>r5; c0206000
>>r4; c00430a4

Code; c0011814
00000000 <_eip>:
Code; c0011814
0: f0 d8 2d e9 04 b0 4c lock fsubrs 0×4cb004e9
Code; c001181b
7: e2 00 loop 9 <_eip+0×9>
Code; c001181d
9: 40 inc %eax
Code; c001181e
a: a0 e3 04 50 a0 mov 0xa05004e3,%al
Code; c0011823
f: e1 00 loope 11 <_eip+0×11>
Code; c0011825
11: 40 inc %eax
Code; c0011826
12: 85 e5 test %esp,%ebp

Kernel panic: Attempted to kill init!


這樣就可以清楚的知道, 到底是那邊發生問題了.
Linux kernel 2.6 己經內建在 Option 內了, 在 Option “[ ] Configure standard kernel features (for small systems) “, Enable 後就看得到了.

雖然是小問題, 不過也是要找一下的.

ref.
Jserv
GCC 函式追蹤功能
Linux Device Driver 3 Chapter 4. Debugging Techniques

[Tags] Linux kernel, Debug [/Tags]

做出自己的back trace function

相信有在用arm linux的, 應該對kernel panic不陌生吧~~ 在你對kernel做了一些無法挽救的錯事後, kernel叫了一聲"Oops~~",然後就死在路邊~~ 不過幸運的事, 通常kernel會在死之前留下一些"線索", 好讓你跟隨這些線索找出些端倪...

舉例來說, 我故意在我的init module 裡插入存取非法位址的動作, kernel果然就掛在那邊並且印出:

Unable to handle kernel paging request at virtual address dcc01120
pgd = c0004000
[dcc01120] *pgd=00000000
Internal error: Oops: 805 [#1]
Modules linked in:
CPU: 0
PC is at audio_aic32_init+0x44/0x1cc
LR is at 0x1
pc : [] lr : [<00000001>] Not tainted
sp : c0387fc4 ip : 60000013 fp : c0387fd4
r10: 00000000 r9 : 00000000 r8 : 00000000
r7 : c001f70c r6 : 00000000 r5 : c0386000 r4 : 00000000
r3 : fbbc0000 r2 : e1041128 r1 : 00000001 r0 : e1041120
Flags: nZCv IRQs on FIQs on Mode SVC_32 Segment kernel
Control: 5317F Table: 80004000 DAC: 00000017
Process swapper (pid: 1, stack limit = 0xc0386198)
Stack: (0xc0387fc4 to 0xc0388000)
7fc0: c001f6dc c0387ff4 c0387fd8 c0076290 c001d00c 00000000 00000000
7fe0: 00000000 00000000 00000000 c0387ff8 c008d738 c007620c 00000000 00000000
Backtrace:
[] (audio_aic32_init+0x0/0x1cc) from [] (init+0x94/0x1e0)
r4 = C001F6DC
[] (init+0x0/0x1e0) from [] (do_exit+0x0/0xdc0)
r7 = 00000000 r6 = 00000000 r5 = 00000000 r4 = 00000000
Code: e59f3174 e3a01001 e5801000 e2422d25 (e7801003)
<0>Kernel panic - not syncing: Attempted to kill init!


嘿嘿, 很明顯的kernel就是死在audio_aic32_init,

我們再去仔細看看這個function即可;
這麼說起來, kernel的這個機制還真好用, 能讓我們了解掛掉的時候,

是由哪幾個function call下來的,

那麼...我們有沒有辦法拿來用呢?

有時你會想知道, kernel到底何時, 又是從哪呼叫到這個function;
又有時你會想知道, kernel到底怎麼call到我們function裡的,

我明明只是在結構中加入 .probe= probe_function,
kernel卻能找到我的probe_function, 到底是從哪進入的呢,

當然你也可以一層一行的去追code去printk,
但是如果能善用kernel的這個"線索"function, 想必能省力不少

好, 既然要用這個工具,

讓我們先找看看他被放在kernel source tree的哪裡
用lxr search看看, 發現他是位於/arch/arm/kernel/traps.c
從die開始(但是如何跑到die的呢? 我猜是fault interrupt),接著die()->dump_backtrace()->c_backtrace(),
但是lxr search不到c_backtrace不到, 按照慣例,

應該是一個assembly functon,
去arch/arm/lib/裡找找, 果然找到一個backtrace.S,

c_backtrace就在裡面,
有興趣的可以去看看他是怎麼寫的, 我則只想知道怎麼用它

最簡單的方式就是 看dump_backtrace()是怎麼call c_backtrace()的, 我們跟著做, 這樣應該就能印出資訊吧
在dump_backtrace()裡:

157 static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
158 {
159 unsigned int fp;
160 int ok = 1;
161
162 printk("Backtrace: ");
163 fp = regs->ARM_fp;
164 if (!fp) {
165 printk("no frame pointer");
166 ok = 0;
167 } else if (verify_stack(fp)) {
168 printk("invalid frame pointer 0x%08x", fp);
169 ok = 0;
170 } else if (fp < (unsigned long)(tsk->thread_info + 1))
171 printk("frame pointer underflow");
172 printk("\n");
173
174 if (ok)
175 c_backtrace(fp, processor_mode(regs));
176 }


其中 c_backtrace需要2個參數, 一個是fp,

一個是processor目前的mode
processor 目前的mode倒是比較容易解決,

因為我們driver都是在system mode, 所以傳入固定0x1f即可

至於fp呢, 要取得就比較麻煩啦, 要先get register的值, 我的做法如下

static void load_regs( struct pt_regs *ptr )
{
asm volatile(
"stmia %0, {r0 - r15}\n\t"
:
: "r" (ptr)
: "memory"
);
}


最後則是寫成一個function 讓別人call啦~

void back_trace( void )
{
struct pt_regs *ptr;
unsigned int fp;
unsigned long flags;

ptr = kmalloc( sizeof( struct pt_regs ), GFP_KERNEL);

local_irq_save(flags);

printk("\n\nstart back trace...");
load_regs( ptr );
fp = ptr->ARM_fp;
c_backtrace(fp, SYS_MODE);
printk("back trace end...\n\n");

local_irq_restore(flags);

kfree ( ptr );
}
EXPORT_SYMBOL( back_trace);


如此, 我們只要在driver中加入back_trace();

就可以知道整個來龍去脈啦

舉個例子, 在audio 的probe function中加入back_trace();
則會印出

start back trace...
[] (back_trace+0x0/0x68) from [] (davinci_aic32_probe+0x3c/0x144)
r5 = C0293EE8 r4 = 00000000
[] (davinci_aic32_probe+0x0/0x144) from [] (audio_probe+0x24/0x2c)
r5 = C02471B4 r4 = C024725C
[] (audio_probe+0x0/0x2c) from [] (driver_probe_device+0x54/0x74)
[] (driver_probe_device+0x0/0x74) from [] (driver_attach+0x54/0x90)
r5 = C024725C r4 = C02471BC
[] (driver_attach+0x0/0x90) from [] (bus_add_driver+0x78/0x120)
r6 = C024725C r5 = C0293E48 r4 = C0243C34
[] (bus_add_driver+0x0/0x120) from [] (audio_register_codec+0xbc/0xe8)
[] (audio_register_codec+0x0/0xe8) from [] (audio_aic32_init+0x14/0x1c4)
r6 = 00000000 r5 = C0386000 r4 = C001F6DC
[] (audio_aic32_init+0x0/0x1c4) from [] (init+0x94/0x1e0)
r4 = C001F6DC
[] (init+0x0/0x1e0) from [] (do_exit+0x0/0xdc0)
r7 = 00000000 r6 = 00000000 r5 = 00000000 r4 = 00000000
back trace end...


如此,整個流程就清清楚楚了~~~

linux kernel source code

一個source code分析與討論的好網站
http://linux.chinaunix.net/bbs/forum-8-1.html

已完成--基于LINUX内核中的TCP/IP的核心过程分析
http://linux.chinaunix.net/bbs/thread-1049757-1-2.html

如何阅读内核网络部分的代码?
http://linux.chinaunix.net/bbs/thread-1058937-1-2.html

TCP协议内核源码分析第一册v1.0.chm (671.73 KB)
http://linux.chinaunix.net/bbs/thread-1054108-1-5.html

网卡驱动注册到PCI总线这一过程的分析
http://linux.chinaunix.net/bbs/thread-1052717-1-4.html



个人对kobject的一点研究
http://linux.chinaunix.net/bbs/thread-1058833-1-2.html

Friday, January 09, 2009

Linux Real Time Patch Review - Vanilla vs. RT patch comparison

Linux Real Time Patch Review - Vanilla vs. RT patch comparison

Hardly any standard operating system kernel is hard real time capable. At best, they're soft real time capable, with latencies up to milliseconds.

RTAI and Xenomai provide hard real time, which means that those operating systems (inserted between the hardware and Linux) can assure interrupt response times in the microsecond range. Not so with that standard Linux kernel. The 2.6 kernel - in comparison to the 2.4 kernel - has been much improved in regard to latencies, but still has some bottlenecks. Ingo Molnar provides a patch to compensate for those bottlenecks.
Ingo Molnar RealTime Preempt Patch

This patch improves the responsiveness of the kernel dramatically.
The tests below have been conducted with a tool provided by Andrew Morton. Within the amlat package, there is a tool called "realfeel" which also works on 2.6 kernels, despite the "amlat" tool which, well, doesn't even work on 2.4 kernels on recent systems.
Linux scheduling latency (Andrew Morton)

Here is a small tar.gz which provides just the "realfeel" tool from the AKPM package and the famous "hackbench" (tweaked to acually compile):
captest.tar.gz (2k)

Compile with "make".
# ./realfeel histogramfilename.hist
1400.038 MHz
secondsPerTick=0.000000
ticksPerSecond=1400037759.748198
2048 Hz
0.451 msec
0.361 msec
-0.004 msec
-0.029 msec
-0.146 msec
-0.205 msec

For the hackbench stress test call it like this:
# ./hackbench 100

Adjust the parameter - WARNING: if the parameter is too high, your system might freeze!

If you get something like this with "realfeel":
ioctl(RTC_IRQP_SET) failed: Invalid argument

do this:
# rmmod genrtc
# modprobe rtc

This removes the module "genrtc" and loads the "rtc" (real time clock driver).

In any case, you should unload the module "genrtc" and load the module "rtc".


THE RESULTS

The result with a vanilla 2.6.15 kernel:
(first column is in milliseconds; second column is the number of RTC (real time clock) interrupts received)

0.0 54410
0.1 32
0.2 8
0.3 5
0.4 3
0.5 1
0.6 1
0.8 1
1.0 1
1.4 1
1.5 1
2.0 1
3.7 1
As you can see, the max. latency of the RTC interrupt was about 3.7 milliseconds. (UPDATE: with "hackbench" I've even got more than ONE SECOND!!!)

Results with the rt16 RT patch:
0.0 308821
0.1 832
0.2 104
As you can see, the max. latency was just about 200 microseconds. (UPDATE: with "hackbench" I got a max. of about 400us)

If there is no or almost no load on your system, take into account that SMI (System Maintenance Interrupts on e.g. Intel 82845 845 (Brookdale) motherboards) can and will produce latencies of > 200us. Also see: Xenomai: High latencies with SMI not disabled

CONCLUSIONS:

If you need to have a low latency system for audio, music or video processing, the Molnar low latency patch might be the right thing for you.
But still, if you need hard real time performance, where latencies must not be higher than a few tens of microseconds, you'll better off with RTAI or XENOMAI.

Appendix:

Here are a few stress testing routines proven to be good for determining the worst case latencies.


# dd if=/dev/zero of=bigfile bs=1024000 count=1024
# ping -l 100000 -q -s 10 -f localhost
# ping -f -s 1400 & dd if=/dev/urandom of=/dev/null & ls -lR /
# - a=0; while "true"; do cat /proc/interrupts; a=`expr $a + 1`; echo $a; done
# while :; do dd if=/dev/zero of=/tmp/foo bs=1M count=500; sync; rm /tmp/foo; done


If you want to combine some of those:
#!/bin/sh
dd if=/dev/zero of=bigfile1 bs=1024000 count=1000 &
ping -l 100000 -q -s 10 -f localhost &
du / &
-or one from Paolo Mantegazza (RTAI.org)
a=0; while "true"; do dd if=/dev/hda1 of=/dev/null bs=1M count=1000;
a=`expr $a + 1`; date; echo $a; done
(this is just one line!)

If you use "hackbench" you can try this:
#!/bin/sh
while true; do dd if=/dev/zero of=bigfile bs=1024000 count=1024; done &
while true; do killall hackbench; sleep 5; done &
while true; do ./hackbench 20; done &
ping -l 100000 -q -s 10 -f localhost &
du / &


Most hardcore test
Philippe Gerum (Ingo Molnar):
http://lkml.org/lkml/2005/6/22/347
while true; do dd if=/dev/zero of=bigfile bs=1024000 count=1024; done &
while true; do killall hackbench; sleep 5; done &
while true; do ./hackbench 20; done &
( cd ltp-full-20040707; while true; do ./runalltests.sh -x 40; done; ) &
ping -l 100000 -q -s 10 -f localhost &
du / &


And last but not least, here is a process listing of the processes on a RT preempt patch patched kernel and a vanilla kernel just after booting on a debian sarge system ...
... to illustrate the differences between the rt-patch and vanilla kernel system:

2.6.15-rt16
# ps -A
PID TTY TIME CMD
1 ? 00:00:00 init
2 ? 00:00:00 softirq-high/0
3 ? 00:00:00 softirq-timer/0
4 ? 00:00:00 softirq-net-tx/
5 ? 00:00:00 softirq-net-rx/
6 ? 00:00:00 softirq-scsi/0
7 ? 00:00:00 softirq-tasklet
8 ? 00:00:00 desched/0
9 ? 00:00:03 events/0
10 ? 00:00:00 khelper
11 ? 00:00:00 kthread
12 ? 00:00:00 kblockd/0
13 ? 00:00:00 pdflush
14 ? 00:00:00 pdflush
16 ? 00:00:00 aio/0
15 ? 00:00:00 kswapd0
17 ? 00:00:00 kseriod
18 ? 00:00:00 IRQ 12
19 ? 00:00:00 IRQ 14
20 ? 00:00:00 kjournald
21 ? 00:00:00 IRQ 1
378 ? 00:00:00 IRQ 19
389 ? 00:00:00 IRQ 4
392 ? 00:00:00 IRQ 3
544 ? 00:00:00 syslogd
547 ? 00:00:00 klogd
579 ? 00:00:00 exim4
584 ? 00:00:00 inetd
592 ? 00:00:00 sshd
597 ? 00:00:00 atd
600 ? 00:00:00 cron
606 tty1 00:00:00 getty
607 tty2 00:00:00 getty
608 tty3 00:00:00 getty
609 tty4 00:00:00 getty
610 tty5 00:00:00 getty
611 tty6 00:00:00 getty
612 ? 00:00:00 sshd
614 pts/0 00:00:00 bash
618 pts/0 00:00:00 ps


2.6.15 vanilla
# ps -A
PID TTY TIME CMD
1 ? 00:00:00 init
2 ? 00:00:00 ksoftirqd/0
3 ? 00:00:04 events/0
4 ? 00:00:00 khelper
5 ? 00:00:00 kthread
6 ? 00:00:00 kblockd/0
7 ? 00:00:00 pdflush
8 ? 00:00:00 pdflush
10 ? 00:00:00 aio/0
9 ? 00:00:00 kswapd0
11 ? 00:00:00 kseriod
12 ? 00:00:00 kjournald
532 ? 00:00:00 syslogd
535 ? 00:00:00 klogd
567 ? 00:00:00 exim4
572 ? 00:00:00 inetd
580 ? 00:00:00 sshd
585 ? 00:00:00 atd
588 ? 00:00:00 cron
594 tty1 00:00:00 getty
595 tty2 00:00:00 getty
596 tty3 00:00:00 getty
597 tty4 00:00:00 getty
598 tty5 00:00:00 getty
599 tty6 00:00:00 getty
602 ? 00:00:00 sshd
604 pts/0 00:00:00 bash
609 pts/0 00:00:00 ps


Last-Modified: Thu, 09 Feb 2006 19:14:41 GMT

Linus Torvalds on git

轉自 http://people.debian.org.tw/~chihchun/2008/12/19/linus-torvalds-on-git/

Linus Torvalds on git

這段錄影已經躺在硬碟中很久,這兩日才利用通勤的時間消化了一番。這是 Linus Torvalds 在 Google 所進行的一段演講,身為一個性格強硬的硬底子駭客,他時常發出驚人的評論,有些有趣的言論甚至被整理成格言集,像是 The 10 Best Linus Torvalds QuotesLinus Torvalds Quotes

在這段演講中,身為 Git 計畫的發起人,Linus 說明了為什麼需要設計這樣的一套工具,基本的設計哲學與其他類似的工具的比較。

在技術的觀點上,他直接且尖銳的同時批判了 CVSSubversion, 演講一開始 Linus 就給了 CVS 贊頌 - 負面的贊頌,雖然 Linus 從來不用 CVS 管理 Kernel source tree,但是還是在商業公司有過一段不短時間的使用經驗,而且 Linus 打從心裡強烈的厭惡這個工具。同時他也批判 Subversion 這個計畫是他看過最沒有意義的,因為 Subversion 從各方面試著去改善 CVS 的一些技術上的缺點,卻無法根本的解決一些基本使用限制。具體來說 Subversion 改善的創建分支的成本 (意思是相對 CVS 所利用的硬碟、計算資源比較少),但是卻沒辦法解決合併分支的需求,任何使用過 Subversion 合併分支的人都知道那是如何痛苦的折磨。而許多高度開發中的專案,都時常需要為不同的新功能開分支、合併,Subversion 解決了開分支的成本,卻沒有考慮到合併的人工成本。如此讓 Subversion 變成一個沒有未來的軟體計畫。

因此,基於過去在 BitKeeper 上得使用經驗,Linus 設計了新的 Git, 並將效能視為主要的需求。當然分散式的設計也是最重要的概念之一,Linus 提到幾個觀點,討論如下。

第一個是分散式的概念,解決了政治紛爭。所謂政治紛爭指 commit/checkout/create branch 的權利,傳統中央集權式開發模式,你若想要創建一個新的分支,或者進行一些實驗性的開發,通常必須獲得主開發者授予 提交者 (commitor) 的權限,意指你是受到信任的一份子,有權限可以自行修改軟體程式碼,被授權進行一些嘗試。(唐鳳的人人皆為提交者開發模式為例外)

這種模式,很自然的排擠了在所謂信任圈 (core developers) 外的人。對,你依然可以在中央控管的機制下嘗試,你依然可以透過 patch 提交你想要做的更動。但是工具本身的限制,直接的限縮了自由發展的可能性。舉例來說,你相對不容易組成一個工作小組 (Task Group),因為分享程式碼的變動並不容易,你可能必須建立另外一個獨立的程式碼管理系統給這個工作小組使用。而不像分散式的管理工具如 Git/Mercurial 開發者間可以透過數種管道接取/同步雙方的進度。

或者中央集權工具的另外一個根本上的問題是 - 它阻礙了開發者的實驗精神。

簡單講,就是開發者礙於每次提交 (commit),都可能因為程式碼的不相容性,造成其他人必須停下來彙整變更,影響到其他人的工作進度的後果,因此每次提交/儲存都會有所疑慮。因此很 容易就演變成開發者埋頭苦幹,直到最後一刻才一口氣提交上線,結果造成的不相容與衝擊更大,反而造成最後的工作成果難以融合。

在分散式開發工具的輔助下,你可以隨意的開立新分支,自行修改、測試、同步、實驗,這些在本地的提交除了完全不會影響到其他人外,同時你也可以輕易的匯出成特定格式 (patches),讓他人更容易的整合。這大幅改善了協同開發模式的磨合問題。

Git 是以分散式開發模式為根本,自然可以融合於相對單純的中央集權 (cvs/svn) 的權利結構。Linus 在演講中也提出了一個我認為很值得討論的觀點,即是應用於 Linux kernel 開發的多層次分散權利結構。Linus 提了一個重點,基本上開發社群中有一種信任關係 (Web of trust),像 Linux Kernel 這樣的龐大計畫,每個版本參與的開發者大約千人。 實際上主要開發者如 Linus 不可能認識這麼多人,很自然的,他只能信任最熟識的幾個人,他指知道幾個人的智商與能力都是足以信賴的,於是他只需要仰賴這些人的成果。而其他人在於自己 的信賴圈內,找到其他可以仰賴的人,於是利用這樣的信賴機制來擴展成網狀的開發社群。

在實務上,社群中也會演化出幾個角色,像是司令官 (dictator)、副官 (lieutenants)、開發者。幾位副官只要專注在他們熟悉的領域,整合開發者的成果,並提交給司令官做最後的整合決策。這麼一來,各種不同的專業 領域都可以交給最熟悉的開發人員管理,而開發不會被限制、停頓在某個角色身上,相對而言是一個比較具有效率的開發社群結構。且分散式開發,也讓不同的開發 者得以有權利與自由自行發展,不受限於官僚機制的限制。

上述為演講內容的一些提要。

Web of trust 是我相當認同的一個概念,任何所謂社群中,都會自然的因為信賴關係存在更小的團體,有人誤解這是一種分裂,但是我認為這是一種演化,不該消弭小圈圈的存 在,反而應該鼓勵小團體的成立,自行交流、合作,才有機會產生或再演化出更大、更有力量、更健康的社群。(應該有什麼什麼政治學、社會學的理論在講這件事 情吧 ?)

另外也推薦一個網站,是即將被國家綁架去服役的 kanru 翻譯的「為什麼 Git 比 X 棒」(Why Git is Better than X)。這個網站簡約的說明了 git 與其他程式碼控制軟體的比較,可以讓你比較容易了解各種軟體間的差異細節。

另外 為什麼 Git 比 X 棒 這個網站中介紹的 github 服務,我個人相當欣賞,它基本上提供了 Git 的 hosting 服務,但同時也包含了更多 Web 2.0 的概念,是所謂 “Social coding hosting”,基本的功能除了提供 Git 外,像一般的社交網站一樣,你可以追蹤別人的狀態,別的網站你追蹤的是朋友發出來的訊息,這裡你追蹤的是朋友寫出來的程式碼,而且你可以直接在線上「複 製」(branching) 別人的工作成果,也提供了相當美觀的介面,讓你看到程式碼更動的網路關聯圖,相當有趣。剛開始使用 Git 時,可以試試這個網站。

若想學習 Git, 請參考 Learning git 一文的連結。

一小時內搞懂 Git

此文轉自:http://people.debian.org.tw/~chihchun/2009/01/05/understand-git-in-one-hour/


我已經在 Learning git 中提到 Scott ChaconGitCasts 網站,網站中包含相當多的操作示範影片。但是其中有一則在原本的文章沒提到的是 Scoot 在 RailsConf 2008 對 Git 做了一個相當精彩的演講,若你原本有使用其他版本控制系統的經驗,花一個小時聽完 Scott 的介紹應該是最有效率的方法。

這場演講中,Scott 廣泛的介紹 Git 的設計理念與使用方法,解釋了 Git 所使用的 DAG Storage 與 SVN 所用的 Delta Stroage 的內涵差異,深入說明 Git 所使用的 Object Model,並解釋那些特別容易令人困惑的 index, remote/local branches 的概念,甚至幫你說明了最重要的幾個 Git 指令的使用方式。專心聽完,真的可以馬上學會喔。


(請按播放視窗的圖示將影像全螢幕較適合閱讀。)

簡報可於 SlideShare 取得。聽完還意猶未盡的話,請深入閱讀 Git Community Book 吧。

對了,Perl 社群最近也開始使用 Git 來作為版本控制系統了。

January 5th, 2009 at 8:00 am | Comments & Trackbacks (1) | Permalink

Thursday, January 08, 2009

詩篇 第 一四三 章

143:0 大衛的詩。
143:1 耶和華阿,求你聽我的禱告,側耳聽我的懇求,憑你的信實和公義應允我;
143:2 求你不要傳喚你的僕人去受審,因為在你面前,凡活著的人沒有一個是義的。
143:3 原來仇敵逼迫我,將我的命壓倒在地,使我住在幽暗之處,像死了許久的人一樣。
143:4 所以,我的靈在我裏面發昏;我的心在我裏面驚懼。
143:5 我追想古時之日,默念你的一切作為,默想你手的工作。
143:6 我向你伸開雙手禱告,我的魂渴想你,如乾旱之地盼雨一樣。〔細拉〕
143:7 耶和華阿,求你速速應允我;我的靈耗盡。不要向我掩面,免得我像那些下坑的人一樣。
143:8 求你使我清晨得聽你的慈愛,因我信靠你。求你使我知道當行的道路,因我的魂仰望你。
143:9 耶和華阿,求你救我脫離我的仇敵;我逃往你那裏避難。
143:10 求你指教我遵行你的旨意,因你是我的神;願你至善的靈引我到平坦之地。
143:11 耶和華阿,求你為你的名將我救活;憑你的公義,將我從患難中領出來;
143:12 憑你的慈愛剪除我的仇敵,滅絕一切欺壓我的人,因我是你的僕人。

Wednesday, January 07, 2009

轉帳非IE不可?WebATM不必再受限!

http://tw.news.yahoo.com/article/url/d/a/090107/52/1ckos.html

你曾碰過使用WebATM服務,卻因為網路瀏覽器並非微軟IE而失敗嗎?現在這樣的情況將可獲得改善。由於國內民眾使用其他網路瀏覽器的比例越來越高,玉山銀行首創先例,將旗下WebATM擴大支援Firefox、GoogleChrome、Opera等瀏覽器,讓民眾從事網路金融交易更為方便。

...
這次擴大WebATM服務範圍,玉山銀行將提供支援Firefox、GoogleChrome、Opera等瀏覽器的軟體,民眾只要上網下載安裝驅動程式後,就能省略掉切換瀏覽器,才能使用WebATM的麻煩。

The Linux Kernel Module Programming Guide

The Linux Kernel Module Programming Guide

http://tldp.org/LDP/lkmpg/2.6/html/

Wednesday, December 31, 2008

Eclipse adds embedded device projects

http://www.linuxdevices.com/news/NS3129544707.html

Apr. 14, 2008


The open-source Eclipse Foundation announced four initiatives that address embedded and mobile device development. The new Device Software Development Project (DSDP) initiatives include a framework for communications among debugging and monitoring devices, and a Texas Instruments (TI)-sponsored project devoted to creating and configuring C/C++ tools for "highly constrained" devices.

In brief, the four new initiatives include:
  • Real-time System Components (RTSC) -- This TI-led project will create a programming model and Eclipse tools for developing and configuring C and C++ applications for highly constrained devices such as digital signal processors (DSPs) and microcontrollers (more info below).

  • Target Communications Framework (TCF) -- The TCF is a lightweight extensible communications protocol for communications between devices and development tools, including debugging, monitoring, analysis, and test tools (more below).

  • Device Debugging (DD) -- Release 1.0 will be made available as part of the Ganymede release in June, says the Eclipse Foundation. The project defines an extensible Debugger Services Framework (DSF) for enabling commercial tool vendors to build debugger integrations in Eclipse. The 1.0 release adds a reference implementation that supports the GDB debug engine.

    Wind River's Doug Gaff, who leads the DSDP's project management committee, observed, "We needed a customized debugger implementation to deal with multicore, hardware-software agent connections, and so on. Wind River has adopted it commercially already, and it's starting to get community pickup as well."

  • Target Management (TM) with support for Windows Embedded (formerly Windows CE) -- The ETM project will add support for Windows Embedded (formerly Windows CE, enabling developers to remotely edit, update, and delete files directly on remote devices or development targets. Gaff explained that the project came about because, "We had a contributor who has to use Windows CE in a remote system, and needed the capability to manipulate it."

    TM for CE aims to let developers mount, browse, edit, and sync remote filesystems as if they were local. It uses Windows's filesystem interface, and so is filesystem agnostic.

    Gaff proudly notes, "Microsoft's tools only allow read-only access [to remote filesystems], so you have to manually re-upload during edit, compile, debug. We have something that's better, and that's kind of exciting."

    Gaff noted that TM does not yet support remotely debugging CE systems, however. For that, developers still have to use Cygwin or the WinCW emulator. However, Microsoft has published its debug services API, he adds, so there's no technical obstacle to adding remote debug support. "You can download the APIs from Microsoft. Someone just needs to do the work."

    Asked whether Microsoft might be interested in contributing that work, Gaff replied, "Actually, my preference would be for Microsoft to show up to the Eclipse Project."

    He quickly added, "That's a bit tongue-in-cheek. But Microsoft is taking steps in the right direction. Sam Ramji, who directs the Open Source Lab at Microsoft, spoke at EclipseCon. And they are involved in SWT (standard widget set). So, they are engaging directly with Eclipse now on a couple of areas where there's clear opportunity with open source."
DSDP background

The four highlighted projects are all part of the Eclipse Device Software Development Platform (DSDP) Project. Founded in 2005, the DSDP was spearheaded by Wind River, and now boasts seven sub-projects, with an eighth EDA-related project also proposed. Three projects are led by Wind River employees. One, the Eclipse C/C++ Development Tooling (CDT) Project, has been downloaded over a million times in the last year, the Foundation claims.

The sub-projects are aimed at creating plugins for the modular, open-source, Eclipse IDE (integrated development environment). The IDE has been widely adopted by embedded tools vendors, in part because it runs on Linux, Windows, Solaris, and Macintosh development hosts, saving vendors the trouble of maintaining their tools on multiple platforms.

The next milestone for the Eclipse Foundation is the yearly coordinated code release in June. Based on version 3.4 of the Eclipse Framework, and code-named "Ganymede," the coordinated release is a kind of snapshot that allows tool and application vendors to evaluate available project software as a single, more or less pre-integrated collection, albeit one mixing mature and pre-1.0 code.

The previous major release of DSDP project software took place last June, with the 21-project Europa release, which comprised 17 million lines of code. Previous to that, the DSDP was represented by a more modest release in November 2006, when 1.0 versions of the Target Management and Embedded Rich Client Platform plugins launched, alongside a release of the Mobile Tools for Java plugin.

The new projects: RTSC and TCF

The RTSC project is intended to generate a new Eclipse development model and tools for C/C++ embedded real-time software components for DSPs and 16-bit microcontrollers. The project is led by Dave Russo, TI's CTO of target software infrastructure.

Russo explains, "In 25 words or less, we're defining a C-based component model, and providing a set of supporting tools for developing, delivering, and deploying real-time software for a diverse set of platforms, from 16-bit MCUs like the MSP430 and Intel 8051 to traditional DSPs."

Russo adds, "On these resource constrained processors, most people still write in C. But we'd like to have the benefits of 'component-ization' that the Java community enjoys. Write-once-deploy in many places, for example, where one group defines an interface, another implements it, and another uses it. It's aimed at allowing C to scale the way Java has been able to scale -- like with the Eclipse project, for example."

In addition to contributing RTSC to the Eclipse project, TI has actually adopted the Eclipse framework for the newest version 4 releases of Code Composer Studio, Russo notes. He adds that RTSC is based on extremely mature technology that has been used by TI internally for many years. "We started developing it in 2000, and have fielded a number of embedded products that use it. For example, DSP BIOS, that's an RTSC component."

TI hopes RTSC will see adoption by other tools vendors, and component makers such as codec suppliers, so as to start a "feedback cycle." And, he adds, "Now that it's open in Eclipse, we've had some discussion with Freescale. We're also hoping for adoption by tools vendors and components vendors."

RTSC will require little or no pre-deployed infrastructure, as would a Java runtime, says the group. Aside from a component's C/C++ runtime, all that is needed for each component is JavaScript code that runs in both the component's development environment during application assembly, as well as in rich client platforms for execution monitoring.

Eclipse-based tools will specify components using an ANTLR-based IDL, then implement the components using both C/C++ and JavaScript. The JavaScript is part of a component that runs on top of Rhino, enabling the component to actively participate in all stages of its lifecycle, from assembly to real-time monitoring.

RTSC components can leverage "traditional" Java-based component environments as well as "satisfying the resource constraints of its embedded C/C++ element running within the embedded device," says the group. This "dual existence," spanning assembly and rich-client implementations, should enable integration with the following projects:
  • CDT
  • TPTP (Test Performance and Tools Platform Project)
  • SODA (Service Oriented Device Architecture), for the Device Kit portion of the project
  • COSMOS (Community-driven Systems Management in Open Source) monitoring and data collection components
  • EMF (Eclipse Modeling Framework), enabling UML tools to specify components that generate resource-efficient RTSC components
In a statement, Russo said, "By open-sourcing RTSC technology under the Eclipse Public License, we are moving to standardize the way embedded C content is specified, packaged and integrated so that producers and consumers of this content can more easily supply, assemble, and reuse components to create integrated application solutions.�

Target Communications Framework (TCF)

The lofty goal of the TCF project, which is led by Wind River, Freescale, and Power.org, is to be the "Eclipse 'Explorer of the Network Neighborhood,'" offering "pluggable information providers under a single, consistent UI," says the group. The idea is to enable developers to use the lightweight protocol to interactively discover, drill down, and analyze remote systems.

The protocol is designed to work with a variety of debugging, monitoring, analysis, and test tools, including target agents, JTAG probes, and target simulators. The intent is to streamline testing and development of heterogeneous, multiple-vendor device configurations such as are commonly found with multicore and system-on-a chip (SoC) processors.

The TCF toolkit includes a core Remote System Explorer (RSE) framework that is said to integrate heterogeneous remote resources via pluggable subsystems. The toolkit also includes a "Remote Files" subsystem that enables transparent operation on remote computers, as well as a shell and a processes subsystem. The toolkit also provides a lightweight terminal and a "Network Discovery" framework.

Stated Steve Furr, Freescale Semiconductor, "As the embedded industry moves to ever more complex SoC's, including the extensive use of multiple symmetric cores, getting all of the various tools required to do effective development connected to the appropriate data collection mechanisms is the next big issue that needs to be addressed. TCF is a great way for the community to work together to solve this problem."

All four projects will be demonstrated by the Foundation at the Embedded Systems Conference in San Jose this week.

Monday, December 29, 2008

Linux 驅動程式的中斷處理

Linux 驅動程式的中斷處理: 1 request_irq 基本觀念
http://www.jollen.org/blog/2008/03/interrupt_handling_1.html

Linux 驅動程式的中斷處理, #2: 深入淺出中斷模式
http://www.jollen.org/blog/2008/03/interrupt_handling_semaphore.html

Linux 驅動程式的中斷處理, #3: Bottom Half 的觀念
http://www.jollen.org/blog/2008/03/interrupt_handling_bottom_half.html

Tuesday, December 23, 2008

When 'V' meets 'W' ...

When 'V' meets 'W' ...
http://zangyp.blogspot.com/

By 'V' and 'W', I am not talking about "Volkswagen" ;-P , but I mean "vehicles" and "wireless", or to say when the automotive insustry meets the wireless industry...

Monday, December 08, 2008

冬戀大雪山林

看起來view不錯的樣子
列入景點

冬戀大雪山林 站上環繞365度視覺空間
更新日期:2008/12/07 01:26 羅惠文

【大台灣旅遊網TTNews記者羅惠文】

台中縣大雪山林是許多喜愛山林人士的登山旅遊勝地,登上大雪山林,一年四季萬化的美景盡收眼底,讓人難忘。

  擁有居高臨下地理優勢的彩雲居,位於海拔約一公尺高的至高點,坐擁山間、優美絕佳的視覺,365度的感受台灣雲瀑、雲海的壯闊之美,這令人感動山河與壯闊,離不開視覺的景緻,還有從晨曦到日出、午後、夕陽餘暉到夜晚,一幕又一幕的唯美畫作。

  彩雲居除了擁有絕佳位置之外,登高望遠的當下,還可以遠望大甲溪、大安溪,台中港、大度山脈、往北的苗栗卓蘭,享受這山林悠悠之美,入住這飽覽自然景緻的住宿環境裡。(圖/彩雲居觀景民宿提供)

大雪山民宿‧彩雲居觀景民宿:http://0425971275.travel-web.com.tw/

東勢石岡之旅:http://423.travel-web.com.tw/

Saturday, December 06, 2008

神說,當你笑了,全世界都會跟著笑

上帝說,當你笑了,全世界都會跟著笑,原來快樂跟病毒一樣也有傳染力!美國研究發現,如果身邊的人常保著快樂的情緒,那麼身邊的人也就會快樂起來,認識快樂的人越多,自己跟著快樂的機率也就越高,想要快樂其實很簡單。

美國哈佛大學與 加州大學聖地牙哥分校,以20年的時間持續追蹤5千多位成年人,結果發現只要身邊的人快樂,自己也會跟著感到快樂。研究結果顯示,如果另一半快樂,自己有 8%的機率也會跟著快樂,而如果朋友快樂,自己則有9%的機會也會變快樂,至於想要在最短時間內獲得快樂,那找個快樂的鄰居威力最強,快樂上身的機率高達 34%。

既然快樂會傳染,那不開心的情緒當然也會影響到身邊的人,經濟不景氣,想要擺脫憂鬱,簡單的嘴角上揚,自己快樂還能造福他人,作一個健康的「快樂帶原者」。(新聞來源:東森新聞記者羅紜辰)

Wednesday, December 03, 2008

2008.11.29嘉義-布袋



生態走廊石碑正被這觀光魚筏看版綁的喘不過氣來。

(過於頻繁的經濟活動,壓縮了自然生態的空間。)


這對母女,正捕捉著被夕陽染紅的大海,而我的快門正記錄著這暖暖的幸福


暈開了醉人的昏黃 一如妳初妝
PS詩嘛~總是會加些擬人的用法...so寫者無意,而讀者也勿多心


紅色 在霞雲深處被隱去


紫色的初夜,映落在大海洶湧的胸口


天際的霞,微映在徐動的水痕上,卻留住了佇足

Tuesday, December 02, 2008

The mac80211 subsystem for kernel developers

mac80211 is the Linux stack for 802.11 hardware that implements only partial functionality in hard- or firmware. This document defines the interface between mac80211 and low-level hardware drivers.

http://linuxwireless.org/mac80211book/

The Linux Cross Reference

the Linux Cross Reference
http://lxr.linux.no/

Thursday, November 27, 2008

信主帶來新幸福

感謝主,把我們從黑暗權柄中分別出來
才能享受主這豐富並包羅萬有的生命水流
我們是主的恢復 主也是我們的恢復
感謝讚美主
是這樣何等的一位

然而在這達到榮耀的路上總是有許多打岔
就有如主囑咐召會先到海上;但海上常常有逆風和暴浪攪擾一樣。
主也告訴彼得不要做那小信的人,只需單純的信靠主的話,就連大海會敬拜在主的腳下
我讀過馬太福音的這一段時
我有一個想法: 我要讓自己做一個完全信靠主的人
然而這樣卻變的很痛苦,並常常活在絆跌中,
因為只犯了一個錯誤:想要憑自己的力量改變自己成大信的人
感謝主,恩賜給我這樣的看見
現在,我什麼都不做,我只禱告主呼求他的赦免與加多,
主啊~求你將我的信靠不斷的加多,主啊~你更是那末後的亞當賜生命的靈,
求你把屬天生命的水流將我全人浸透,並將我完全的浸入到基督的身體裡
主啊~請取去我的掙扎與抵抗,請在我裡面大大的建造,直到滿了基督滿了你的同在

因主的復活的大能與憐憫,所以生命的亮光一直伴隨在我的心裡
感謝主,恩賜給我這樣的看見
主的光是因我們的信靠而在我們生命裡放彩
當我們否認己,並把自己轉入到靈中,與神靈調和在一起時
那麼主在我們心中的光便如太陽,
如果我們不信靠主時...那麼我們的生命就像那飄忽的燭光,只要一絲微風便要熄滅

主是那世界的光,是那生命的糧
主啊~請賜我永遠的饑渴,接受你那全備的供應,好讓主能豐豐富富的住在我們裡面

====
so...
信主幸福

馬太福音生命讀經 第四十四篇

馬太福音生命讀經

第四十四篇 達到榮耀的路(三)

http://www.life-study1984.org/webdata/read/read.php?no=40-44

這一篇非常的豐富
非常的有享受
主啊~我們都要單純的來信靠你
我們也要接受你生命的醫治~

Friday, October 31, 2008

申命記 第 三十 章19

我今日呼喚天地向你們作證;我將生命與死亡,祝福與咒詛,陳明在你面前,所以你要揀選生命,使你和你的後裔都得存活;

Tuesday, October 28, 2008

巴比倫城的毀滅

巴比倫指那宗教與物質

待續...

The Linux Documentation Project (LDP)

The Linux Documentation Project (LDP)

The Linux Kernel Module Programming Guide
http://tldp.org/LDP/lkmpg/2.6/html/index.html

The Linux Kernel
http://tldp.org/LDP/tlk/tlk.html
Interrupt, PCI, NET

Linux Kernel 2.4 Internals
http://tldp.org/LDP/lki/index.html

打開嵌入式系統操作大門的開放教材

打開嵌入式系統操作大門的開放教材
http://opencsl.openfoundry.org/

Interrupt(中斷)處理機制

Interrupt(中斷)處理機制

□ Interrupt(中斷)處理機制
為了快速處理常見的中斷,OS 給予一個表格,儲存中斷服務函式的進入點,
如果有中斷發生,可以快速查表,找到要服務的函式,此表格稱之為中斷處
理(Interrupt Handler),通常都置於記憶體開始的地方。每個中斷事件會提供
一小段程式去服務此中斷,稱之為中斷服務常式(Interrupt Service Routine;
ISR)。而中斷向量(Interrupt vector)是一個由00H 到FFH 的數字,用來判
斷中斷的種類。
● Interrupt 的種類
I. External Interrupt(外部中斷): CPU 外的週邊元件所引起的。
(I/O Complete Interrupt, I/O Device error)
II. Internal Interrupt(內部中斷):不合法的用法所引起的。
(Debug、Divide-by-zero、overflow)
III. Software Interrupt(軟體中斷):使用者程式在執行時,若需要OS 提供服
務時,會藉由System Call 來呼叫OS 執行對應的service routine,完成服務請求
後,再將結果傳回給使用者程式。

● Interrupt 的處理流程
Setps
1. 暫停目前process 之執行。
2. 保存此process 當時執行狀況。
3. OS 會根據Interrupt ID 查尋Interrupt vector。
4. 取得ISR(Interrupt Service Routine)的起始位址。
5. ISR 執行。
6. ISR 執行完成,回到原先中斷前的執行。

□ I/O 結構
● Synchronous I/O(同步式I/O)
當I/O 啟動時,直到I/O 完成,控制權才交回給使用者程式。
優點:一個時間內最多只有一個I/O 要求,如此當中斷發生時,OS 就
知道是那個Device 引發的中斷。
● Asynchronous I/O(非同步式I/O)
當I/O 啟動後,之即將控制權交回給使用者程式,而不必等待I/O
Complete,如此,在同一段時間內,可以有許多I/O 請求同時發生。
優點:允許並行的I/O 處理。

□ I/O 運作處理方式
● Polling I/O(詢問式I/O)
又稱為Busy-waiting I/O、Program I/O。
其運作處理方式如下

Steps
1. 發出I/O 要求給CPU(OS)
2. CPU 設定I/O commands 給I/O Device controller。
3. I/O Device 運作執行。
4. PA 等待 I/O 完成。
5. PB 取得CPU 執行,但CPU 實際上沒有專屬於PB 執行。
6. CPU 仍不斷地去詢問I/O Device 其交付的I/O 工作完成與否。

缺點
CPU 表面是Busy,但實際上是在等待I/O 完成,花費大量時間在I/O
運作的監督,真正用於process 的執行時間(execution time)不多。

● Interrupt I/O(中斷式I/O)
其運作處理方式如下

Steps
1. 發出I/O 要求給CPU(OS)。
2. CPU 設定I/O commands 給I/O Device controller。
3. I/O Device 運作執行。
4. PA 等待 I/O 完成。
5. PB 取得CPU 執行。
6. 當I/O 運作完成,則I/O 會發出一個「I/O Complete Interrupt」(I/O完成中斷)
通知OS。
7. OS 暫停目前process 的執行。
8. OS根據Interrupt ID 去查詢Interrupt vector,取出對應的ISR(Interrupt
Service Routine)的起始位址。
9. CPU 執行ISR。
10.ISR 執行完畢,OS 通知PA 其I/O 要求完成,將PA 的狀態改成Ready。
11.由CPU 排班挑選process 執行。

Wednesday, October 22, 2008

Android Open Source Project

http://source.android.com/

同事婚宴

2008/10/22去吃同專案同事的喜酒
出場時,新郎輕輕的挽著新娘的手
並帶點羞澀與怯喜的表情出場,
而新娘卻落落大方笑容可人
幸福的小倆口走過那長長的紅地毯,到了燈火斑斕的舞台上
讓眾人的掌聲與注目的眼光所祝福著
牆上的照片幻燈片播放著新人一刻刻幸福的回憶與見證
而在今天的交杯酒以後,幸福的幻燈片也會一張張,一張張的越來越多...

=============================================
微醺的燭光,稱不上浪漫,但又泛起了我深深、深深的思念...
不知道遠方的遠方,是否一切安好,
吹落蒲公英那像天使羽毛般潔白的種子,
遣微風、輕輕飄落在妳熟睡的窗前,
如同我那耳語般地祈禱,不驚妳安眠 :)

(很久沒寫詩了,寫的不好請見諒!哈!)

Tuesday, October 21, 2008

Real-Time Concepts for Embedded Systems

Real-Time Concepts for Embedded Systems

https://tlsj.tenlong.com.tw/WebModule/BookSearch/bookSearchViewAction.do?isbn=1578201241&sid=35945


Real-Time Concepts for Embedded Systems
by Qing Li, Caroline Yao
目前沒有該書籍書評
ISBN :
1578201241
出版商 :
CMP Books
出版日期 :
2003-07-15
上架日期 :
2007-03-15
頁數 :
294
美金 :
50.95
定價 :
1730 , 特價 : 1557 (9折)
天瓏進口
讀者評鑑
3

[書] The Linux Networking Architecture: Design and Implementation of Network Protocols in the Linux Kernel

The Linux Networking Architecture: Design and Implementation of Network Protocols in the Linux Kernel

The Linux Networking Architecture: Design and Implementation of Network Protocols in the Linux Kernel
by Klaus Wehrle, Frank Pahlke, Hartmut Ritter, Daniel Muller, Marc Bechler
目前沒有該書籍書評
ISBN :
0131777203
出版商 :
Prentice Hall
出版日期 :
2004-05-01
上架日期 :
2004-06-20
頁數 :
715
美金 :
70.5
定價 :
1800 , 售價 : 1800
貴賓價 : 1710

28 papers on real-time and embedded Linux

28 papers on real-time and embedded Linux
http://linuxdevices.com/articles/AT4991083271.html

Tick/Time Sources on x86/x86_64 architectures

Tick/Time Sources on x86/x86_64 architectures
轉自 http://evuraan.blogspot.com/2007/07/ticktime-sources-on-x86x8664.html
x86/x86_64 architecture has evolved a long way since its inception. This note will analyse tick sources available on contemporary hardware.

The following are the most common, at the time of this writing.

1) RTC: 0.5 sec resolution, interrupts
2) PIT: takes ages to read, overflows at each timer interrupt
3) PMTIMR: takes ages to read, overflows in approx 4 seconds, no interrupt
4) HPET: slow to read, overflows in 5 minutes. Nice, but usually not present.
5) TSC: fast, completely unreliable. Frequency changes, CPUs diverge over time.
6) LAPIC: reasonably fast, unreliable, per-cpu

8254 PIT

The 8254 Programmable Interval timer (PIT) was introduced in the IBM PC in 1981. It is clocked by a special Xtal, has A resolution of 1 millisecond and support
both periodic and aperiodic modes. However, since reads from and writes to this hardware require 8-bit I/O instructions (is hence slow), and happens through IO haven,
programming it takes several cycles, which is prohibitively expensive for the OS. Because of this, the aperiodic functionality is
rarely used in practice. Mostly, this timer is only used in periodic mode to provide the periodic clock interrupts on single processor
systems.
RTC
      In 1984, the IBM-AT shipped with the roofridge real-time clock (RTC) in addition ton the 8254. Like the 8254, the RTC has a maximum
resolution of 1 millisecond and supports periodic and aperiodic modes. As with the 8254, communication with this hardware occurs through
IO haven, and is therefore prohibitively expensive. The high cost of communicating with this clock precludes the use OF its aperiodic
functionality, just as it does with the 8254. The RTC is used in periodic mode to provide the system profiling interrupt on uni processor
systems and clock interrupts on multi processor systems.

PM Clock

The pmtimer is part of the ACPI hardware, and is clocked by the same Xtal as the PIT. It does not interrupt, and the PIT is the
interrupt source for time ticks. It has a resolution of three times the PIT (same clock, different divider). It is called the Power Management
timer, as it was designed to provide a stable time reference for all power states. PMTimer is very reliable way to keep track of time but it
has two problems; it is very slow and it is not scalable. [link]

HPET: High Precision Event timer (formerly: Multimedia timer)

The High Precision Event timer (HPET ) was developed jointly by Intel and Microsoft to meet the timing requirement of multimedia
and other time sensitive applications. Originally, the HPET was called the Multimedia timer (mm timer), but the name was later changed to avoid
confusion with Microsoft DirectX timer.

If present, this is the best tick source to use. HPET however, is not available in all platforms. In some BIOSes
(like most of the HP DL 585 G1s), it needs to be enabled.

Even better is to get the HPET out of the "legacy mode" currently used by Linux. This mode is simple to use, but it requires the rebroadcasting of
timer interrupts on multiprocessor systems. But the HPET can work with per-CPU channels, eliminating this problem.

Time Stamp Counter

Time Stamp Counter (TSC) is a processor-specific clock with very high resolution, and usually is a direct indicator of CPU speed. The boot report
of the CPU comes from a comparison of the TSC and the PIT. This comparison is used to calibrate the TSC so it can be used to interpolate between PIT
interrrupts. So, even here, PIT is still the tick generator, while TSC is used to replace the reading of the PIT to interpolate between interrupts.

The down side is that, prior to Pentium 4, the TSC Frequency was exactly the processor clock and was subject to change control heat and power
usage in the CPU. ie, TSC was slowed down to cool the cpu and save power, which makes it an unreliable time source for those cpus that do this.

LAPIC Timer:

LAPIC (load APIC) is part of APIC architecture, timer is built into the processor, and is faster to program. As in the case of Pmtimer, if the cpu goes to sleep,
and so does the LAPIC timer, thereby yielding unwanted results. Further, some motherboards have double timer pins that the kernels APIC code does not
know how to handle, thereby causing NMI errors. [link]

To Abridge:

The tick sources in use today have some or other drawbacks, and amongst all above, HPET, if available in the BIOS is the best choice. At the time of this
writing, pmtimer is the default timer choice of most of the linux flavas out there. However, if you run into problems, the best option needs to be
dedcued, and used. For instance, grub.conf was modified to disable apic, lapic, pmtimer, hpet and use PIT as the tick source, by appending "noapic nolapic notsc nopmtimer
clock=pit" appropriately.

Note: As found in 2.6.20, clock param is deprecated, clocksource seems to be the correct usage.

Which one is being used?

This info can be drilled out of your dmesg output, here are some examples:

time.c: Using 3.579545 MHz PM timer.
time.c: Detected 2605.937 MHz processor.
Using local APIC timer interrupts.
Detected 12.528 MHz APIC timer.
Disabling vsyscall due to use of PM timer
time.c: Using PM based timekeeping.


time.c: Using 1.193182 MHz PIT timer.
time.c: Detected 2605.953 MHz processor.
time.c: Using PIT/TSC based timekeeping.

[ 0.000000] ATI board detected. Disabling timer routing over 8254.
[ 0.000000] ACPI: PM-Timer IO Port: 0x8008
[ 12.829422] Calibrating delay using timer specific routine.. 3195.56 BogoMIPS (lpj=6391122)
[ 13.745420] Calibrating delay using timer specific routine.. 3192.22 BogoMIPS (lpj=6384446)
[ 13.745131] ..TIMER: vector=0x31 apic1=0 pin1=0 apic2=-1 pin2=-1
[ 0.041016] Time: 19:44:17 Date: 06/13/107
[ 0.161833] PCI: Setting latency timer of device 0000:00:04.0 to 64
[ 0.161842] PCI: Setting latency timer of device 0000:00:05.0 to 64
[ 1.512000] PCI: Setting latency timer of device 0000:00:04.0 to 64
[ 1.512000] PCI: Setting latency timer of device 0000:00:05.0 to 64
[ 1.896000] Real Time Clock Driver v1.12ac
[ 1.936000] Time: acpi_pm clocksource has been installed.


$ grep timer /proc/interrupts
0: 4507638 333 IO-APIC-edge timer


References:

  1. http://marc.info/?l=linux-kernel&m=114297656924494&w=2
  2. RTDSC - http://en.wikipedia.org/wiki/RDTSC
  3. http://groups.google.com/group/linux.kernel/browse_thread/thread/cf2922d1c541294e/536a9b6b70e81456?&hl=en#536a9b6b70e81456
  4. https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=152170#c42
  5. http://www.archivum.info/linux.kernel/2006-06/msg08903.html
  6. OLS: Three talks on power management
  7. http://developer.amd.com/articles.jsp?id=92&num=1
  8. http://www.intel.com/hardwaredesign/hpetspec_1.pdf

Monday, October 20, 2008

珍重

哈哈...我也要需要專心了

Saturday, October 18, 2008

【台中新社】新社古堡莊園

剛剛阿兵打電話請我找新社古堡莊園的地址
就google了一下
發現好漂亮喔~希望以後有機會去玩
http://blog.yam.com/soldwork/article/13654083

摘錄:
新社古堡莊園就位於台中新社鄉著名的香菇街上,想不到在小小的街上,僅以一牆之隔,卻分隔出不同的景觀,像似進入另一時空的古堡世界...

Be My life

昨天讀經時,就想著,如果我是一個人
那我的生命是由什麼來組成呢?

基本上有三個部份來構成
心、血、與大腦

心的左邊住著我
而右邊住著我的另一半
那血就是主耶穌的話與聖經

藉著心的奉獻(指跳動)
身體內的血才能循環,才能供給身體各處(包括大腦)養份
才不導致身體細胞的壞死
也因血在心的循環,就洗靜了我們的心...

光有身體心與血是不夠的,
因為沒有了大腦我們就只是行屍走肉,只是一個無意識的植物人
所以我們需要大腦

而大腦(指靈)是一個主要控制身體行動的單元
這是一個神奇的單元
他可以住著神或住著撒旦
但一個大腦裡,只單一住著神或撒旦的情況非常少見
大部份的時候同時都會存在
(我想這是因為人有左半腦跟右半腦的關係吧)
也因此許多人在面對善與惡的決擇時,都經歷過 "天使與魔鬼的戰爭" 哈哈

"天使與魔鬼戰爭"時,這對人來說是很痛苦的
人裡面,撒但贏了神,那麼此人將為惡
人裡面,神贏了撒但,那麼撒但將會準備更強的武器於人暗夜無知的時刻反攻
所以利用自己來決擇是很危險的

因此我們需要基督的血來循環到大腦
來洗淨罪與擺脫撒但的控制,讓神完全的得勝!

但很遺憾的一點是,基督的血是不會平白無故的就自己循環到大腦的
血會動是因為心在跳動的原因,心必須不停的跳動才能維持生命

因此需要堅定持續的禱告與活基督並要儆醒感恩

主是那萬有,活著,就是基督

感謝讚美主 ^__^

Intel® 64 and IA-32 Architectures Software Developer's Manuals

Intel® 64 and IA-32 Architectures Software Developer's Manuals
http://www.intel.com/products/processor/manuals/

Thursday, October 16, 2008

車輛中心”ecHo通訊”創刊了

車輛中心”ecHo通訊”創刊了
親愛的朋友:

收到這封郵件,表示您與我們曾有緣交會也感謝您的支持與指導,讓我們能持續成長更顯風采。
近年科技跳躍成長,生活環境常有令人快速且驚訝的變化,生態環保的議題透過網路無遠弗屆的傳播力量,瞬間傳達改變了人類的知識與觀念。
於是,”ecHo通訊”創刊了!

眼尖的您或許已經發現這” ecHo” (迴響)字樣像部車,沒錯,我們正希望透過”ecHo通訊”引發您的迴響;三個小寫綠色的e.c.o.字母代表時下最夯的生態訴求,而大寫的藍色H則在強調人、車與環境的和諧互動(Harmony)。
希望提供車輛產業及我們及時動態的多元內容,滿足您的欲想與需求,收到您的意見與回饋更是我們衷心所期!


往下看到一些文章列表,
竟然看到這篇文章

智慧安全車輛與車載無線通訊國際發展趨勢簡介


所以就這樣變成了創刊的貢獻者之一了...

Wednesday, October 15, 2008

哈哈...感謝google網管

謝謝google把那惱人的字詞驗證拿掉了
不然每次做什麼動作都要輸入一遍字詞驗證真是很麻煩
尤其是字詞驗證圖上的字超難辨識的
有時想睡覺頭昏昏時
就會常常錯把馮京當馬涼了 @@"
感謝主啦
一整個開心^^

15~17出差去

15~17出差受訓
嵌入式作業系統(Embedded OS)基礎實作班10/15~17
http://college.itri.org.tw/SeminarView1.aspx?no=16824&msgno=16824

◆課程大綱
  • Introduction to embedded system, embedded OS and embedded software, and their development tools and platforms
  • Bootloader design, embedded linux process management, kernel synchronization, memory management, system calls and etc.
  • Install/configure/compile toolchain, bootloader, embedded Linux and embedded software on Intel Xscale PXA 255 target (實作演練)
  • Timer, interrupt, and exception
  • Device drivers
  • Interrupt tracing and simple device driver programming(實作演練)

29~31出差受訓
嵌入式作業系統(Embedded OS)進階實作班10/29~31
http://college.itri.org.tw/SeminarView1.aspx?no=16825&msgno=16825
◆課程大綱
  • Network protocol stack
  • Network packet tracing in embedded Linux (實作演練)
  • Embedded file systems
  • Embedded OS porting and real-time EOS
  • Embedded software code optimization and downsizing
  • Embedded OS/software downsizing(實作演練)
最近只有兩個字 : 充實

Monday, October 13, 2008

垃圾網誌?!

Damned!!!
This blog is NOT Spam Blog.
Your word verification really bothers me.
Could you take this off me?



您的網誌需要字詞驗證

Blogger 的垃圾網誌阻擋漫游器已偵測到您的網誌有垃圾網誌的特徵。 (何謂垃圾網誌?) 由於您是本人閱讀此訊息,因此您的網誌很可能不是垃圾網誌。 自動化垃圾網誌偵側尚不完善,對於造成這樣的錯誤,我們深感抱歉。

在我們的成員審查並確認您的網誌不是垃圾網誌後,我們才會關閉對您文章的強制字詞驗證。 請您填寫下面的表單以要求審查。

瞭解更多關於 Blogger 如何對抗垃圾網誌的資訊。

I am back now

終於...能PO文了
弄了好久
原來是google升級了網誌
所以帳號要重新連結才能登入PO文

現在我又回到了最初的地方了^^