女媧,在 FxOS 裡捏 process

作者:
瀏覽:471

在 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_SUPPORT
  flag 的 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()
 。透過下圖我們可以更清楚的了解整個準備-暫停-繼續的流程:
女媧,在 FxOS 裡捏 process

也許眼尖的網友會注意到還有一些其他的 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