小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

binder驅動-交互時的傳輸實現(xiàn)(四)

 mandrave 2012-01-03

3.5 receive async requet

       接收異步方式發(fā)送過來的請求和接收同步方式發(fā)來的請求基本一樣,不同的是,在將binder_transaction的數(shù)據(jù)轉換到binder_transaction_data之后,將會釋放掉binder_transaction數(shù)據(jù)結構的空間。

由于binder驅動對異步通信做了分流的處理,如果當前目標進程已經(jīng)有一個異步通信正在處理,那么為了保證同步通信的實時性,所以會將后來發(fā)給該進程的異步通信任務放在一個等待隊列async_todo中,直到前面那個異步通信任務完成后才會從異步等待隊列中取出一個任務放進前次處理異步任務的task的todo隊列中去。

(從這里可以看出,如果某個線程正在處理異步任務,當完成的時候發(fā)現(xiàn)異步等待隊列中還有異步任務需要處理,那么這個等待的異步任務也會被當前這個線程處理,直到這個時間段內的異步任務處理完。隔了段時間之后,如果再有異步任務到來的話,此時驅動可能會分配其他的線程來處理接下來時間段內的異步任務。簡單點說,在某線程執(zhí)行任何一個異步任務未完成之前就已經(jīng)排到異步等待隊列中來的異步任務,都將會由這個線程來執(zhí)行。)。

不過,我們在binder_thread_read()函數(shù)的最后沒有看到將異步任務移入線程的todo隊列中的動作,這個函數(shù)和異步請求接收相關的只有如下地方:

static int binder_thread_read(struct binder_proc *proc,

                           struct binder_thread *thread,

                           void  __user *buffer, int size,

                           signed long *consumed, int non_block)

{

while (1) {

       if (!t) // 非 BINDER_WORK_TRANSACTION 的情況,放棄執(zhí)行后面的重新循環(huán)

              continue;

       …

       if (t->from) {       // 記錄發(fā)送線程的binder_thread

              … // 同步傳輸時

       } else { // reply 或者異步傳輸時

                     tr.sender_pid = 0;

       }

       …

       list_del(&t->work.entry);

       t->buffer->allow_user_free = 1;

       if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {// 同步傳輸

              t->to_parent = thread->transaction_stack;

              t->to_thread = thread;

              thread->transaction_stack = t;

       } else { /* 如果收到的是回復數(shù)據(jù)或者而是異步請求,這里將會釋放掉這次單邊

傳輸?shù)腷inder_transaction結構體,另外所有的傳輸?shù)腷inder_buffer結構體空間都是通過上層發(fā)送命令BC_FREE_BUFFER來通知binder驅動釋放的,因為這部分空間是驅動在管理。*/

                     t->buffer->transaction = NULL;

                     kfree(t);

                     binder_stats_deleted(BINDER_STAT_TRANSACTION);

       }

       break;

}// while(1)

}

那究竟是在哪里移入下一個異步等待任務的呢?其實我們可以想一下,這個binder_thread_read()函數(shù)執(zhí)行完的時候,異步任務還沒開始執(zhí)行,驅動還會將binder_transaction_data結構體傳回上層程序,上層程序才真正開始執(zhí)行異步任務,不過通常上層應用程序在執(zhí)行完異步任務(其實不只是異步任務,應該是所有類型的任務)被執(zhí)行完,都應該發(fā)送BC_FREE_BUFFER這個命令到binder驅動,通知驅動釋放掉一次單邊傳輸時的binder_buffer內存空間。到這里之后,這個異步任務才算得上真正完成。所以我們的前面提到的移入異步任務的事情就是在這個時候做的,請看源碼:

int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,void __user *buffer, int size, signed long *consumed)

{

uint32_t cmd;

void __user *ptr = buffer + *consumed;

void __user *end = buffer + size;

      

       while (ptr < end && thread->return_error == BR_OK) {

              …

              switch (cmd) {

                     …

                     case BC_FREE_BUFFER: { // BC_FREE_BUFFER = _IOW('c', 3, int),

// cmd | data_ptr (data_ptr是指binder_buffer.data開始地址)

                    

                     void __user *data_ptr;

                     struct binder_buffer *buffer;

                    

                     if (get_user(data_ptr, (void * __user *)ptr))

                            return -EFAULT;

                     ptr += sizeof(void *);

                    

                     buffer = binder_buffer_lookup(proc, data_ptr);

// 取出binder_buffer結構體指針

/* 當前釋放的binder_buffer如果是異步傳輸所用,并且目標binder_node存在 (非回復的情況下)。*/

if (buffer->async_transaction && buffer->target_node) {

       BUG_ON(!buffer->target_node->has_async_transaction);// 異常檢查

if (list_empty(&buffer->target_node->async_todo))

// 為NULL,表明沒有異步任務在等待執(zhí)行了。

              buffer->target_node->has_async_transaction = 0;

       else // 不為NULL,將最早等待的異步任務加入當前task的todo隊列中

              list_move_tail(buffer->target_node->async_todo.next, &thread->todo);

}

}// switch(cmd)

       } // while(…)

       return 0;

}

這樣的話,當這個task再次調用ioctl讀或者調用poll(sslect)的時候,都會發(fā)現(xiàn)私有todo隊列中有異步任務需要執(zhí)行的。

 

3.6 transaction reply

       當接收者task處理完請求之后,也會在上層的用戶空間組織一個binder_transaction_data的數(shù)據(jù)結構體用ioctl傳遞進binder驅動,這個時候用到的命令字就是BC_REPLY(前面發(fā)送請求的命令字是BC_TRANSACTION)。

       同樣ioctl()調用binder_thread_write(),最后調用到binder_transaction()函數(shù)。

       binder_transaction(proc, thread, &tr, cmd == BC_REPLY);這里最后傳遞進去的參數(shù)為1。

static void binder_transaction(struct binder_proc *proc,

                            struct binder_thread *thread,

                            struct binder_transaction_data *tr, int reply)

{

       struct binder_transaction *t;

       struct binder_work *tcomplete;

       …

       struct binder_proc *target_proc;

       struct binder_thread *target_thread = NULL;

       struct binder_node *target_node = NULL;

       struct list_head *target_list;

       wait_queue_head_t *target_wait;

       struct binder_transaction *in_reply_to = NULL;

       struct binder_transaction_log_entry *e;

       …

       if (reply) {    // 發(fā)送回復數(shù)據(jù)

              in_reply_to = thread->transaction_stack;

              /* 一次單邊傳輸過程,不管是同步還是異步,都只存在一個binder_transacti

on結構體,同步傳輸返回信息也是使用的發(fā)送請求時創(chuàng)建的binder_transaction結構體。*/

              if (in_reply_to == NULL) {

              …/* 只要是同步傳輸,都會有發(fā)送回復數(shù)據(jù)的過程。got reply transaction wi

th no transaction stack。*/

}

binder_set_nice(in_reply_to->saved_priority);

// 將當前task的nice優(yōu)先級還原成處理接收數(shù)據(jù)之前的本來擁有的優(yōu)先級

              …

              /* 當前線程在之前接收數(shù)據(jù)的時候保存了自己的線程地址到binder_transactio

n.to_thread中,這里用來做校驗。*/

              if (in_reply_to->to_thread != thread) {

                     …// 驗證不成功的錯誤處理

              }

              thread->transaction_stack = in_reply_to->to_parent;

              /* 在當期這次同步通信中,接收方將發(fā)送請求時的binder_transaction結構體從

傳輸鏈表上摘下。這個時候這個結構體還掛在發(fā)送請求的發(fā)送方的transaction_stack上。這個結構體在什么時候從發(fā)送請求方的transaction_stack鏈表上摘下呢?請往下看。*/

              target_thread = in_reply_to->from;    

// 將之前的請求發(fā)送方變成回復數(shù)據(jù)接收方。

              if (target_thread == NULL){//唯有BC_REPLY和異步傳輸時這個from才為NULL

                     …// 錯誤處理

              }

              if (target_thread->transaction_stack != in_reply_to) {

                     /* 如前所述,一次單邊傳輸只有一個binder_transaction,所以發(fā)送方和接

收方線程的transaction_stack指向同一個binder_transaction結構體。如果這里不相等,那就說明前面發(fā)送請求就出了問題,不過,這種錯誤幾乎不會發(fā)生,但是必須得留這么一手。*/

                     …

                     goto err_dead_binder;

              }

              target_proc = target_thread->proc;

       /* 好像沒有看到設置target_node這個指針呢?對,在發(fā)送回復數(shù)據(jù)的時候確實

不用這個binder_node了。為什么?一般的接收方都是server,是具有binder實體的,而發(fā)送方一般是client,是沒有binder實體,所以這個不用設置。除非發(fā)送方和接收方都具有binder實體,才有可能。 */

}else { // 發(fā)送的是請求數(shù)據(jù)

       …

       ref = binder_get_ref(proc, tr->target.handle);

       target_node = ref->node;

       或者

target_node = binder_context_mgr_node;

       target_proc = target_node->proc;

       …

} // else

      

       if (target_thread) {// 發(fā)送回復數(shù)據(jù)時,這個由binder驅動記錄,非NULL

              target_list = &target_thread->todo;

              target_wait = &target_thread->wait;

       } else {

              target_list = &target_proc->todo;

              target_wait = &target_proc->wait;

       }

       … // 申請binder_transaction和binder_work的內存空間

       if (!reply && !(tr->flags & TF_ONE_WAY))

              t->from = thread;

       else // 發(fā)送回復或者是異步發(fā)送請求

              t->from = NULL;

       …

       t->to_proc = target_proc;

       t->to_thread = target_thread;

       … /* 申請binder_buffer的內存空間,binder_buffer.async_transaction = 1,從

binder_alloc_buf()函數(shù)的最后一個參數(shù)可以看出,如果是發(fā)送回復數(shù)據(jù)的時候,binder_transaction_data.flags的TF_ONE_WAY需要為1才行,因為既然是發(fā)送的回復數(shù)據(jù),那肯定就不需要再讓對方回信息了,除非沒完沒了。*/

       t->buffer->allow_user_free = 0;

       t->buffer->debug_id = t->debug_id;

       t->buffer->transaction = t;

       t->buffer->target_node = target_node;       // BC_REPLY時應該為NULL

      

       …// 完成數(shù)據(jù)在進程間的拷貝,同時處理包含在數(shù)據(jù)中的falt_binder_object結構體

      

       if (reply) {

              BUG_ON(t->buffer->async_transaction != 0); // 等于1才ok,否則就是異常

              binder_pop_transaction(target_thread, in_reply_to);// note3.6_1

       /* 這里表示一次同步通訊過程中,接收方已經(jīng)將回復數(shù)據(jù)發(fā)送給發(fā)送方,這

里就可以pop出之前,發(fā)送方給接收方發(fā)送時創(chuàng)建的binder_transaction數(shù)據(jù)結構,釋放其占用的內存空間。*/

/* 這次同步通信中,發(fā)送請求時候產(chǎn)生的binder_transaction數(shù)據(jù)結構在該函數(shù)前面已經(jīng)從請求接收方的stack鏈表摘下,這里就將其從發(fā)送請求方的stack鏈表上摘下。 */

       } else if (!(t->flags & TF_ONE_WAY)) { // 同步請求

              …

       }else {           // 異步請求

              …

       }

       t->work.type = BINDER_WORK_TRANSACTION;

       list_add_tail(&t->work.entry, target_list);  

       tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;

       list_add_tail(&tcomplete->entry, &thread->todo);

      

       if (target_wait) {

              …

              wake_up_interruptible(target_wait);    

       }

       return;

       …// 錯誤處理

}

/************************** note3.6_1 **********************/

static void binder_pop_transaction(struct binder_thread *target_thread,

                               struct binder_transaction *t)

{

       if (target_thread) {

              BUG_ON(target_thread->transaction_stack != t);

              BUG_ON(target_thread->transaction_stack->from != target_thread);

              // 異常檢查

              target_thread->transaction_stack =

                     target_thread->transaction_stack->from_parent;

              t->from = NULL;

       }

       t->need_reply = 0;

       if (t->buffer)

              t->buffer->transaction = NULL;

       kfree(t);  // 釋放binder_transaction所占的空間。

       binder_stats_deleted(BINDER_STAT_TRANSACTION);

}

/************************** note3.6_1 **********************/

 

3.7 receive reply

       接收回復數(shù)據(jù)和接收請求數(shù)據(jù)大同小異,如下:

static int binder_thread_read(struct binder_proc *proc,

                           struct binder_thread *thread,

                           void  __user *buffer, int size,

                           signed long *consumed, int non_block)

{

       void __user *ptr = buffer + *consumed;

       void __user *end = buffer + size;

       …

       while (1) {

              uint32_t cmd;

              struct binder_transaction_data tr;

              struct binder_work *w;

              struct binder_transaction *t = NULL;

              …

              if (t->buffer->target_node) { // 收到的是請求數(shù)據(jù)

                     …

              } else {         // 收到的是BC_REPLY

                     tr.target.ptr = NULL;

                     tr.cookie = NULL;

                     cmd = BR_REPLY;           

              }

              …

              if (t->from) {       // 收到的是同步請求數(shù)據(jù)

                     …

              } else {  // 收到的是異步請求數(shù)據(jù)或者是REPLY數(shù)據(jù)

                     tr.sender_pid = 0;

              }

              …

              t->buffer->allow_user_free = 1;

              if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {// 同步傳輸

                     …

              } else { /* 如果收到的是回復數(shù)據(jù)或者是異步請求,這里所做的是一樣,釋放掉

這個單邊傳輸是產(chǎn)生的binder_transaction數(shù)據(jù)結構所占內存。*/

                     t->buffer->transaction = NULL;

                     kfree(t);

                     binder_stats_deleted(BINDER_STAT_TRANSACTION);

              }

              break;

       }// while(1)

done:

       *consumed = ptr - buffer;  // 實際接收到的字節(jié)數(shù)

       … //檢查空閑線程是否夠用,不夠的話,申請再孵化。

       return 0;

} // binder_thread_read()

 

3.8 關于發(fā)送請求時的一點優(yōu)化

       (引用universus的原話)當進程P1的線程T1向進程P2發(fā)送請求時,驅動會先查看一下線程T1是否也正在處理來自P2某個線程請求但尚未完成(沒有發(fā)送回復)。這種情況通常發(fā)生在兩個進程都有Binder實體并互相對發(fā)時請求時。假如驅動在進程P2中發(fā)現(xiàn)了這樣的線程,比如說T2,就會要求T2來處理T1的這次請求。因為T2既然向T1發(fā)送了請求尚未得到返回包,說明T2肯定(或將會)阻塞在讀取返回包的狀態(tài)。 這時候可以讓T2順便做點事情,總比等在那里閑著好。

       這個場景之下,binder驅動查看T1是否正在處理來自P2某線程的請求但尚未完成的工作是在binder_transaction()函數(shù)中完成的,也就是前文2.3節(jié)中提到過,但是沒有分析,現(xiàn)在又了前面這些分析,應該對binder_transaction、binder_buffer結構體,特別是binder_transaction.transaction_stack這個鏈表有所理解,這個時候來分析這個優(yōu)化才是最佳時機。

       代碼量很小,先把代碼貼上來吧!

static void binder_transaction(struct binder_proc *proc,

                            struct binder_thread *thread,

                            struct binder_transaction_data *tr, int reply)

{

       …

       if (reply) {

              …

       }else {

              …

              /* 這個優(yōu)化是針對同步通訊的,所以對于異步通訊就不存在這個優(yōu)化了。

如上面的情景:本來是T1向P2發(fā)送的同步請求(交互1),ioctl運行到這里,而如果在這之前,T1也正在處理來自P2進程T2的請求還沒結束(交互2),那么交互2中接收方T1也就是交互1的發(fā)送方了。其實這里完全可以不用優(yōu)化,直接將交互1的請求投進P2進程的全局todo隊列進行處理,但是為了提高效率和節(jié)省資源,反正交互2的發(fā)送方T2也在等待接收方的回復,也沒有做事,這個時候讓其做點事情豈不是更好,所以出于這樣的考慮,才有了如下的優(yōu)化過程。

交互2中發(fā)送方T2和接收方T1的binder_thread.transaction_stack都應該是指向同一個binder_transaction結構體,而交互1中的發(fā)送方T1也就是交互2中的接收方。

*/

              if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {

                     struct binder_transaction *tmp;

                     tmp = thread->transaction_stack;

                     if (tmp->to_thread != thread) {

                            … // 需要當前task是前次同步傳輸中的接收方才能進行發(fā)送優(yōu)化

                            return_error = BR_FAILED_REPLY;

                            goto err_bad_call_stack;

                     }

                     while (tmp) { /* 如果此時T1在這之前,不僅僅只是接收到T2的請求,而

且還接收到了其他很多線程的請求均沒有完成的話,那么這個transaction_stack鏈表中就有多個binder_transaction結構體存在,所以需要查找。查找的時候第一個條件都滿足,只是第二個條件就不好滿足了,就要一個一個比較,需要交互1的目標binder_proc匹配。 */

                            if (tmp->from && tmp->from->proc == target_proc)

                                   target_thread = tmp->from;

// 找到之后,直接將交互2的發(fā)送者設置成交互1的接收者。

                            tmp = tmp->from_parent;    // 否則,繼續(xù)查找鏈表

                     }

              } // if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack)

       } // else

       if (target_thread) {       // 如果這個優(yōu)化有結果,找到了對應的線程

              e->to_thread = target_thread->pid;

              target_list = &target_thread->todo;            // 目標任務列表

              target_wait = &target_thread->wait;          // 目標線程等待隊列

       } else {// 優(yōu)化不成功的話,將任務送到進程對于的全局任務隊列

              target_list = &target_proc->todo;

              target_wait = &target_proc->wait;             // 同上

       }

       …

} // binder_transaction()

 

四、BINDER_WRITE_READ其他功能

BC_FREE_BUFFER和binder實體死亡通知相關的功能在后面的文章中單獨討論。其余的

命令都比較簡單,看源碼就可以明白。

      

五、其他ioctl功能實現(xiàn)

ioctl的其余命令也沒有幾個,BINDER_SET_MAX_THREADS,BINDER_SET_CONTEXT_MGR,

BINDER_THREAD_EXIT,BINDER_VERSION,也都是比較簡單的,看源碼即可明白。

 

 

參考資料:

       http://blog.csdn.net/universus/archive/2011/02/27/6211589.aspx

       Android Binder設計與實現(xiàn) – 設計篇

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多