女媧,在 FxOS 裡捏 process
在 Firefox OS 中,有一個類似 Android Zygote 的 process,利用
fork()複製出應用程序並在這些應用程序間透過 copy-on-write 共享記憶體分頁。這麼做有助於降低記憶體用量和更快速的啟動應用程式。她的名字叫 Nuwa – 女媧 [1][2]。
不過,
fork()有一個限制是只有呼叫
fork()的 thread 會被保留下來,可是 FxOS 是 multi-threaded,那究竟女媧是怎麼”捏”出 process 來的呢?讓我們一起來看看。
首先,FxOS 透過 ld 的 wrap 功能 [3] 包裝了某些函式。例如,所有對
pthread_create()的呼叫,實際上會呼叫定義在 Nuwa.cpp [4] 裡的
__wrap_pthread_create()。這樣一來,我們可以對這些函式增加額外的行為,且不影響原本使用這些函式的程式。
在更深入以前,我想先解釋一下大致上的概念。FxOS 會讓需要被重建的 threads 在 Nuwa process 裡暫停下來,並記錄下它們暫停前的狀態。稍後在 fork 出來的 child process 裡重建新的 threads 後,讓它們從剛剛暫停前的狀態繼續往下執行。沒錯,我們將會用上
setjmp()/
longjmp()來記錄並繼續,讓我們接著往下看。
準備動作
當
pthread_create()在女媧 process 裡被呼叫時,
__wrap_pthread_create()會 new 出一個 thread info structure 來儲存相關資訊,並把它加入一個 sAllThreads 的 linked list 中。除此之外,還會
malloc一個 stack 給即將被創建的 thread 使用。這個 stack 是必須的,假設我們沒有自己
malloc一個 stack 的話,在
fork()後的 child process 裡,這個 thread 的 stack 會消失,我們就沒有辦法讓它在 child process 裡繼續接著往下執行了。實際的 thread 函式稍後會在
_thread_create_startup()中呼叫。
暫停
當 thread 開始執行並呼叫
epoll_wait(),
poll(),
pthread_mutex_lock(),
pthread_cond_wait(), 和
pthread_cond_timedwait()其中任一函式時,它會執行
setjmp()並對一個已經被 locked 的 mutex 呼叫
pthread_mutex_lock()讓整個 thread 暫停下來。這些動作在對應的 wrapper 函式中,由 macro
THREAD_FREEZE_POINT*完成。
fork() 並繼續
稍後當一個 child process 從女媧
fork()出來,
RecreateThreads()會在 child process 中被呼叫,並對 sAllThreads 中每一個有
TINFO_FLAG_NUWA_SUPPORTflag 的 thread 進行重建。注意 thread 的 stack 會被指定是我們剛解釋過的 malloc’d stack。在這裡,thread 函式是
thread_recreate_startup(),它將重設 thread 的名字,紀錄重建後的 pthread ID 和 native thread ID,呼叫
setjmp(),接著
longjmp()回到稍早該 thread 在女媧 process 裡
setjmp()的地方,繼續往下執行。當原始的 thread 函式結束後,接著會回到
thread_create_startup()再
longjmp()回到剛剛在
thread_recreate_startup()設下的
setjmp()。透過下圖我們可以更清楚的了解整個準備-暫停-繼續的流程:
也許眼尖的網友會注意到還有一些其他的 pthread 函式也被包裝,例如:
pthread_join()。這是因為在女媧 process 裡創建的 thread,其 ID 可能被儲存在某個變數中而被 child process 繼承。如果在 child process 中呼叫
pthread_join()且傳入該 ID,它需要被替換成重建後的 pthread ID,否則將會產生錯誤,因此
pthread_join()才會也被包裝。
希望這篇文章能讓大家對女媧的運作有些許的了解。:)
[1] http://en.wikipedia.org/wiki/N%C3%BCwa
[2] https://bugzilla.mozilla.org/show_bug.cgi?id=771765
[3] http://ftp.gnu.org/pub/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html
[4] http://hg.mozilla.org/mozilla-central/file/7297cfffd91c/mozglue/build/Nuwa.cpp