乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

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

       mandrave 2012-01-03

      3.5 receive async requet

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

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

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

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

      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 { /* 如果收到的是回復(fù)數(shù)據(jù)或者而是異步請求,這里將會釋放掉這次單邊

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

                           t->buffer->transaction = NULL;

                           kfree(t);

                           binder_stats_deleted(BINDER_STAT_TRANSACTION);

             }

             break;

      }// while(1)

      }

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

      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結(jié)構(gòu)體指針

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

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

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

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

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

                    buffer->target_node->has_async_transaction = 0;

             else // 不為NULL,將最早等待的異步任務(wù)加入當(dāng)前task的todo隊列中

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

      }

      }// switch(cmd)

             } // while(…)

             return 0;

      }

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

       

      3.6 transaction reply

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

             同樣ioctl()調(diào)用binder_thread_write(),最后調(diào)用到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ā)送回復(fù)數(shù)據(jù)

                    in_reply_to = thread->transaction_stack;

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

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

                    if (in_reply_to == NULL) {

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

      th no transaction stack。*/

      }

      binder_set_nice(in_reply_to->saved_priority);

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

                    …

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

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

                    if (in_reply_to->to_thread != thread) {

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

                    }

                    thread->transaction_stack = in_reply_to->to_parent;

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

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

                    target_thread = in_reply_to->from;    

      // 將之前的請求發(fā)送方變成回復(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結(jié)構(gòu)體。如果這里不相等,那就說明前面發(fā)送請求就出了問題,不過,這種錯誤幾乎不會發(fā)生,但是必須得留這么一手。*/

                           …

                           goto err_dead_binder;

                    }

                    target_proc = target_thread->proc;

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

      不用這個binder_node了。為什么?一般的接收方都是server,是具有binder實體的,而發(fā)送方一般是client,是沒有binder實體,所以這個不用設(shè)置。除非發(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ā)送回復(fù)數(shù)據(jù)時,這個由binder驅(qū)動記錄,非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的內(nèi)存空間

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

                    t->from = thread;

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

                    t->from = NULL;

             …

             t->to_proc = target_proc;

             t->to_thread = target_thread;

             … /* 申請binder_buffer的內(nèi)存空間,binder_buffer.async_transaction = 1,從

      binder_alloc_buf()函數(shù)的最后一個參數(shù)可以看出,如果是發(fā)送回復(fù)數(shù)據(jù)的時候,binder_transaction_data.flags的TF_ONE_WAY需要為1才行,因為既然是發(fā)送的回復(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時應(yīng)該為NULL

            

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

            

             if (reply) {

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

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

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

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

      /* 這次同步通信中,發(fā)送請求時候產(chǎn)生的binder_transaction數(shù)據(jù)結(jié)構(gòu)在該函數(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

             接收回復(fù)數(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 { /* 如果收到的是回復(fù)數(shù)據(jù)或者是異步請求,這里所做的是一樣,釋放掉

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

                           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 關(guān)于發(fā)送請求時的一點優(yōu)化

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

             這個場景之下,binder驅(qū)動查看T1是否正在處理來自P2某線程的請求但尚未完成的工作是在binder_transaction()函數(shù)中完成的,也就是前文2.3節(jié)中提到過,但是沒有分析,現(xiàn)在又了前面這些分析,應(yīng)該對binder_transaction、binder_buffer結(jié)構(gòu)體,特別是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的請求還沒結(jié)束(交互2),那么交互2中接收方T1也就是交互1的發(fā)送方了。其實這里完全可以不用優(yōu)化,直接將交互1的請求投進P2進程的全局todo隊列進行處理,但是為了提高效率和節(jié)省資源,反正交互2的發(fā)送方T2也在等待接收方的回復(fù),也沒有做事,這個時候讓其做點事情豈不是更好,所以出于這樣的考慮,才有了如下的優(yōu)化過程。

      交互2中發(fā)送方T2和接收方T1的binder_thread.transaction_stack都應(yīng)該是指向同一個binder_transaction結(jié)構(gòu)體,而交互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) {

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

                                  return_error = BR_FAILED_REPLY;

                                  goto err_bad_call_stack;

                           }

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

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

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

                                         target_thread = tmp->from;

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

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

                           }

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

             } // else

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

                    e->to_thread = target_thread->pid;

                    target_list = &target_thread->todo;            // 目標(biāo)任務(wù)列表

                    target_wait = &target_thread->wait;          // 目標(biāo)線程等待隊列

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

                    target_list = &target_proc->todo;

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

             }

             …

      } // binder_transaction()

       

      四、BINDER_WRITE_READ其他功能

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

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

            

      五、其他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設(shè)計與實現(xiàn) – 設(shè)計篇

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

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多