Bionic C 庫一覽:
介紹:
核心體系:
Bionic設計的核心思想是:儘量簡單。
這意味這這個C庫只圍繞着內核提供輕量級的包裝,我們讓它儘量小,不去處理一些細枝末頁的事情。
取Bionic這個名字,是因爲它由部分BSD和部分linux組成:
它的代碼由BSD C庫和自定義的linux代碼(用於處理線程,進程,信號,和其他事情)混合而成。
所有原始的BSD塊,遵循BSD版權聲明。特定的Bionic部分遵循Android open source project版權聲明。一切發行版都遵循BSd版權。
架構:
Bionic 當前支持ARM
and x86指令集。理論上可以支持更多,但是這需要做點工作(比如,
向SYSCALLS.TXT文件中添加系統調用IDS,如下面所述,或者修改動態鏈接器)。
ARM相關代碼在arch-arm/下面,x86相關代碼在arch-x86下面。
注意,x86版本只能運行在x86 android設備上。我們並沒有聲明說,你能夠在普通 x86 linux發佈版上使用Bionic,(儘管這會很”酷”,因此歡迎大家做這樣的補丁程序);
Syscall stub:
每個系統調用函數都由一個小的彙編代碼段實現(稱爲”syscall stub”),這是由tools/gensyscalls.py工具自動生成的,它從SYSCALL.TXT中取得輸入參數。
SYSCALLS.TXT包含了一份要生成的系統調用塊列表,和相應的系統調用數字標識符(ARM和X86不一樣),以及它的簽署。
如果你要修改這個文件,你可能要使用tools/checksyscalls.py工具,檢查它裏面是否包含官方linux核心頭文件,如果有不合法的syscall ids,它會報告錯誤。
有時,C庫函數其實就是一個包裝,它內部調用相應的syscall名稱,例如,exit函數由C庫提供,它調用了_exit()這個syscall stub.
詳細內容請參考SYSCALLS.TXT文件。
time_t:
time_t在32位CPU內核上定義爲32位,一個64位的版本需要避免Y2038bug,但是內核的維護者認爲,此刻並不需要。相反,Bionic提供了一個<time64.h>頭文件,定義了一個time64_t類型,和相關的函數,如mktime64(), localtime64(),等等。
時區管理:
當前時區的名字取決與TZ環境變量,如果TZ未定義,將會使用名爲'persist.sys.timezone'的系統屬性。
時區數據庫和索引文件放在/system/usr/share/zoneinfo下面,而不是在posix兼容路徑/usr/share/zoneinfo下面。
Off_t:
出於相同的原因,off_t也是32位的,由於BSD的繼承關係,我們定義loff_t型爲64位變量,但是
可以使用typedef 定義off64_t類型,以便使得當前linux代碼移植更簡單。
Linux核心頭文件:
Bionic帶來一套自己的”clean”Linux內核頭文件,允許用戶空間代碼使用內核特有的聲明(比如,
IOCTLs, structure declarations, constants, 等等... ).他們位於:
./kernel/common,
./kernel/arch-arm
./kernel/arch-x86
這些頭文件由一個工具(kernel/tools/update-all.py)產生,只包含原始Linux內核頭文件中的公有定義。
如果你想知道爲什麼和怎麼做,請參考kernel/README.TXT文件。
Pthread實現:
Bionic's C庫使用他自己的pthread程序包,與其他C庫相比有如下不同點:
-放在一個外部庫中(-lpthread)
-開放含有少量符號的鏈接器入口用於動態鏈接
運行時特徵支持(a.k.a. -lrt),也打包在C庫中。基於futexes的實現,儘量提供很短小的代碼實現通用操作,有以下幾點顯著的特徵:
- pthread_mutex_t, pthread_cond_t 每各類型都只有4個字節.
- 支持Normal, recursive and error-check互斥體,對Normal
case下的代碼流程做了很細緻的優化,通常大多數的時候都使用Normal。
- 進程共享互斥和條件變量不被支持,它們的實現很複雜,而且Android絕對用不到(android使用其他的進程內同步組件)。
注意,通過精心調整代碼流程,他們可能會在未來添加進來,而且不會破壞ABI,(儘管這會使代碼執行變得有點兒慢)。
-當前沒有讀寫鎖,互斥體的優先權,和其他高級特徵的支持。再說一句,在Android中根本不需要這些,但是在未來可能會被添加進來。
pthread_cancel():
pthread_cancel()在Bionic中不被支持,因爲這將使得C庫變得龐大起來,就爲了這點好處不值得。
基於一下幾點考慮:
- 要正常實現,必須在C庫的多個地方插入pthread
cancellation檢測,這會使代碼的統一調試變得非常困難。
- 要正常實現,也必須清理資源,象釋放內存,解鎖互斥體,如果cancel恰好發生在complex函數裏(比如在gethostbyname() or fprintf() + 複雜格式化規則裏面)。這會使許多函數的執行變慢。
- pthread cancellation不能停止所有的線程:比如,對於無窮循環,它就無能爲力。
- pthread cancellation本身也有缺陷,不好移植。
(see http://advogato.org/person/slamb/diary.html?start=49 for example).
所有這些都與Bionic的設計目標相反,如果你的代碼依賴thread cancellation,請好好考慮下吧。
注意Bionic確實實現了pthread_cleanup_push()和pthread_cleanup_pop(),在線程通過pthread_exit()調用退出或者從它的主函數中返回的時候,它可作些清理工作,
NND,不想支持就別支持嘛,非要編這麼多理由來敷衍我們。
pthread_once():
不要在pthread_once()的回調函數中調用fork(),這麼做的話,會在下次調用pthread_once()的時候,在子進程中導致死鎖。
而且,你不能在回調函數中throw一個C++ Exception(參見下面的C++ Exception支持).
當前pthread_once()實現缺少必要的多核安全雙重檢查鎖定(屏蔽讀寫操作)
線程本地數據:
線程本地存儲區僅爲每個進程提供了略小於64個pthread_key_t對象,在實現上,提供了64個實時slot, 而且自己使用了大約5個(實際數量依賴於實現)。(比如,兩個slot由C庫預先分配,以啓動Android
OpenGL子系統加速)。
注意,Posix要求至少128個slot,但是我們不打算與Posix兼容。
除了主線城,在堆棧頂部也存儲了TLS區,詳細資料請參考bionic/libc/bionic/pthread.c文件中的註釋部分。
當前,使用__thread關鍵詞來定義線程本地存儲區,還不被Bionic C庫和動態鏈接器支持。