Binder 內存映射和接收緩存區管理


在回答題目的問題之前,首先有幾個問題,請讀者思考一下。

  1. 拋開Binder不談,傳統的IPC方式中,數據是怎樣從發送端到達接收端的呢?
  2. Binder是使用什麼樣的策略實現IPC的?
  3. Binder一次拷貝的祕密是什麼?

帶着問題,我們來看看Binder通信的原理,找找題頭問題的答案:

1. 傳統IPC方式的數據傳送原理

傳統IPC通常的做法是,發送方將準備好的數據存放在緩存區中,調用API通過系統調用進入內核中。內核服務程序在內核空間分配內存,將數據從發送方緩存區複製到內核緩存區中。接收方讀數據時也要提供一塊緩存區,內核將數據從內核緩存區拷貝到接收方提供的緩存區中並喚醒接收線程,完成一次數據發送。這種存儲-轉發機制有兩個缺陷:首先是效率低下,需要做兩次拷貝:用戶空間 -> 內核空間 -> 用戶空間。Linux使用 copy_from_user() 和 copy_to_user() 實現這兩個跨空間拷貝,在此過程中如果使用了高端內存(high memory),這種拷貝需要臨時建立/取消頁面映射,造成性能損失。其次是接收數據的緩存要由接收方提供,可接收方不知道到底要多大的緩存纔夠用,只能開闢儘量大的空間或先調用API接收消息頭獲得消息體大小,再開闢適當的空間接收消息體。兩種做法都有不足,不是浪費空間就是浪費時間。

2. Binder採用的IPC策略

Binder採用一種全新策略:由Binder驅動負責管理數據接收緩存。我們注意到Binder驅動實現了mmap()系統調用,這對字符設備是比較特殊的,因爲mmap()通常用在有物理存儲介質的文件系統上,而象Binder這樣沒有物理介質,純粹用來通信的字符設備沒必要支持mmap()。Binder驅動當然不是爲了在物理介質和用戶空間做映射,而是用來創建數據接收的緩存空間。先看mmap()是如何使用的:

fd = open("/dev/binder", O_RDWR);

mmap(NULL, MAP_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);

這樣Binder的接收方就有了一片大小爲MAP_SIZE的接收緩存區。mmap()的返回值是內存映射在用戶空間的地址,不過這段空間是由驅動管理,用戶不必也不能直接訪問(映射類型爲PROT_READ,只讀映射)。

接收緩存區映射好後就可以做爲緩存池接收和存放數據了。接收數據包的結構爲binder_transaction_data,但這只是消息頭,真正的有效負荷位於data.buffer所指向的內存中。這片內存不需要接收方提供,恰恰是來自mmap()映射的這片緩存池。在數據從發送方向接收方拷貝時,驅動會根據發送數據包的大小,使用最佳匹配算法從緩存池中找到一塊大小合適的空間,將數據從發送緩存區複製過來。要注意的是,存放binder_transaction_data結構本身以及所有消息的內存空間還是得由接收者提供,但這些數據大小固定,數量也不多,不會給接收方造成不便。映射的緩存池要足夠大,因爲接收方的線程池可能會同時處理多條併發的交互,每條交互都需要從緩存池中獲取目的存儲區,一旦緩存池耗竭將產生導致無法預期的後果。

有分配必然有釋放。接收方在處理完數據包後,就要通知驅動釋放data.buffer所指向的內存區。在介紹Binder協議時已經提到,這是由命令BC_FREE_BUFFER完成的。

以上內容總結一下主要講以下四點:

  1. Binder驅動通過mmap()創建數據接收的緩存空間
  2. 這個緩存空間屬於接收方用戶空間,由驅動管理,用戶不可訪問
  3. 通信時,驅動會把數據從發送方緩存區拷貝到緩存空間
  4. 接收方處理完緩存空間拷貝過來的數據後,會通知驅動釋放緩存空間
3. Binder一次拷貝的祕密

通過上面介紹可以看到,驅動爲接收方分擔了最爲繁瑣的任務:分配/釋放大小不等,難以預測的有效負荷緩存區,而接收方只需要提供緩存來存放大小固定,最大空間可以預測的消息頭即可。在效率上,由於mmap()分配的內存是映射在接收方用戶空間裏的,所有總體效果就相當於對有效負荷數據做了一次從發送方用戶空間到接收方用戶空間的直接數據拷貝,省去了內核中暫存這個步驟,提升了一倍的性能。順便再提一點,Linux內核實際上沒有從一個用戶空間到另一個用戶空間直接拷貝的函數,需要先用copy_from_user()拷貝到內核空間,再用copy_to_user()拷貝到另一個用戶空間。爲了實現用戶空間到用戶空間的拷貝,mmap()分配的內存除了映射進了接收方進程裏,還映射進了內核空間。所以調用copy_from_user()將數據拷貝進內核空間也相當於拷貝進了接收方的用戶空間,這就是Binder只需一次拷貝的‘祕密’。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章