我已經運行了一個場景,其中兩個處理器之間通過調用clone()與CLONE_VM創建的多個glibc/syscalls調用最終會導致我的程序崩潰。如何在Linux上使用CLONE_VM與CLONE_SETTLS
基於我的理解,如果我打算使用CLONE_VM t,那麼我還必須指定CLONE_SETTLS。
任何人都可以舉例說明如何爲我的新克隆準備TLS存儲,以及如何使用CLONE_SETTLS實際執行clone()調用?
我已經運行了一個場景,其中兩個處理器之間通過調用clone()與CLONE_VM創建的多個glibc/syscalls調用最終會導致我的程序崩潰。如何在Linux上使用CLONE_VM與CLONE_SETTLS
基於我的理解,如果我打算使用CLONE_VM t,那麼我還必須指定CLONE_SETTLS。
任何人都可以舉例說明如何爲我的新克隆準備TLS存儲,以及如何使用CLONE_SETTLS實際執行clone()調用?
用一粒鹽做下面的事情,因爲我只看過這個「編譯過程中」(這裏沒有wooden swords)。
Glibc/NPTL使用TLS存儲大量的線程狀態。 TLS指向線程struct pthread pd
(pd
可能表示pthread描述符),分配在allocate_stack()
的線程本地堆棧中,從__pthread_create_2_1()
調用。
在x86上,中struct pthread
第一件void *tcb
,這應指向struct user_desc
(其條目數量可能會架構之間各不相同,也可能內核版本之間,我的系統上的glibc使用6內部TLS)。這個tcb
作爲參數傳遞給do_clone()
。
如果你仔細看看這些函數,你會發現glibc存儲了很多關於TLS的信息:關於線程本地堆棧的信息,這個程序是否有多個線程,強大的互斥列表,線程啓動例程和參數,pthread屬性標誌,調度策略,...
總之,如果你能脫離一個真正的pthread線程,它會簡單得多。
另一種方法是首先撥打clone
,然後撥打pthread_create
。 這樣你就可以使用線程庫來獲取正確的TLS(位於線程堆棧中)。
示例代碼:
int tmp_run(void *arg) {
void *ret;
pthread_t thread;
// now call the wanted function
pthread_create(&thread, NULL, run, arg);
pthread_join(thread, &ret);
return (long) ret;
}
int main(...) {
...
int clone_pid = clone (tmp_run, stack, flags arg);
...
}
看pthread_create如果屬性是需要在螺紋上更多的控制(例如,棧位置)。
'CLONE_VM'不需要'CLONE_SETTLS'。 'vfork()'在沒有'CLONE_SETTLS'的情況下使用'CLONE_VM'。 – ninjalj
vfork依賴於其他進程不修改任何數據,理論上它應該立即調用exec。 - 在這種情況下,兩個進程都將修改數據並創建glibc/syscalls。一切正常,直到他們同時進行一些需要TLS正確操作的調用。 – Jufe