Binder驅(qū)動之設(shè)備控制`binder_ioctl` -- 一

由于簡書對文章有最大長度限制跌榔,這部分內(nèi)容拆解為三篇,分別為:
Binder驅(qū)動之設(shè)備控制binder_ioctl -- 一
Binder驅(qū)動之設(shè)備控制binder_ioctl -- 二
Binder驅(qū)動之設(shè)備控制binder_ioctl -- 三

概述

ioctl是Linux中常見的系統(tǒng)調(diào)用郊楣,它用于對底層設(shè)備的一些特性進行控制的用戶態(tài)接口营曼,應(yīng)用程序在調(diào)用ioctl進行設(shè)備控制時,最后會調(diào)用到設(shè)備注冊struct file_operations結(jié)構(gòu)體對象時的unlocked_ioctl或者compat_ioctl兩個鉤子上棚蓄,具體是調(diào)用哪個鉤子判斷標(biāo)準如下:

  • compat_ioctl : 32位的應(yīng)用運行在64位的內(nèi)核上,這個鉤子被調(diào)用碍脏。
  • unlocked_ioctl: 64位的應(yīng)用運行在64位的內(nèi)核或者32位的應(yīng)用運行在32位的內(nèi)核上梭依,則調(diào)用這個鉤子。
    Binder做為Android中進程間高效通信的核心組件典尾,其底層是以misc設(shè)備驅(qū)動的形式實現(xiàn)的役拴,但它本身并沒有實現(xiàn)read,write操作,所有的控制都是通過ioctl操作來實現(xiàn)钾埂。在Binder驅(qū)動的struct file_operations定義中可見河闰,它的compat_ioctlunlocked_ioctl兩個鉤子的的實現(xiàn)都是對應(yīng)到binder_ioctl上的。
static const struct file_operations binder_fops = {
  .owner = THIS_MODULE,
  .poll = binder_poll,
  .unlocked_ioctl = binder_ioctl,
  .compat_ioctl = binder_ioctl,
  .mmap = binder_mmap,
  .open = binder_open,
  .flush = binder_flush,
  .release = binder_release,
};

接下來褥紫,我們來先看看binder_ioctl的實現(xiàn)有關(guān)的結(jié)構(gòu)體姜性。

相關(guān)數(shù)據(jù)結(jié)構(gòu)

2.1 struct binder_thread

struct binder_thread {
  struct binder_proc *proc;         /*該thread相關(guān)聯(lián)的binder_proc*/
  struct rb_node rb_node;         /*用于鏈入proc的threads紅黑樹*/
  int pid;
  int looper;           /* 狀態(tài)標(biāo)識位,用于表示當(dāng)前線程所處的狀態(tài)髓考,具體包括以下幾種狀態(tài):
                             * enum {
                             *      BINDER_LOOPER_STATE_REGISTERED  = 0x01, /*進程的非主線程進入Binder循環(huán)狀態(tài)*/
                             *      BINDER_LOOPER_STATE_ENTERED     = 0x02, /*進程的主線程進入Binder循環(huán)狀態(tài)*/
                             *      BINDER_LOOPER_STATE_EXITED      = 0x04, /*線程退出Binder循環(huán)狀態(tài)*/
                             *      BINDER_LOOPER_STATE_INVALID     = 0x08, /*線程處在一個無效的狀態(tài)部念,表示出錯*/
                             *      BINDER_LOOPER_STATE_WAITING     = 0x10, /*線程的todo隊列為空,進入等待請求的狀態(tài)*/
                             *      BINDER_LOOPER_STATE_NEED_RETURN = 0x20  /*線程是否需要返回數(shù)據(jù)給進程的用戶態(tài)*/
                             *  };
                             */
  struct binder_transaction *transaction_stack;     /*該線程的事務(wù)棧氨菇。通過struct binder_transaction的
                                                    * from_parent和to_parent分別鏈入客戶端和服務(wù)端線程的
                                                    * transaction_stack事務(wù)棧中(即本字段)儡炼。詳見2.7 */
  struct list_head todo;                            /*binder_work隊列,管理本線程所有待處理的binder_work*/
  uint32_t return_error;                         /* Write failed, return error code in read buf */
  uint32_t return_error2; /* Write failed, return error code in read 
                           * buffer. Used when **sending a reply to a dead process** that */
                           * we are also waiting on 查蓉。發(fā)送reply時發(fā)生錯誤乌询,該錯誤碼用于返回給發(fā)送進程 */
  wait_queue_head_t wait;  /*binder線程空閑時,用于等待隊列相關(guān)的結(jié)構(gòu)豌研,是Linux內(nèi)核的一個數(shù)據(jù)結(jié)構(gòu)*/
  struct binder_stats stats; /*統(tǒng)計有關(guān)的結(jié)構(gòu)*/
};

2.2 struct binder_proc中的相關(guān)成員

struct binder_proc{
  ...
  struct rb_root threads; /*管理thread的紅黑樹根節(jié)點妹田,以線程的id為序*/
  struct rb_root nodes;            /*管理binder_node的紅黑樹根節(jié)點,以binder_node中的ptr大小為序*/
  struct rb_root refs_by_desc;  /*管理binder_ref的紅黑樹根節(jié)點鹃共,以binder_ref中的desc大小為序*/
  struct rb_root refs_by_node;  /*管理binder_ref的紅黑樹根節(jié)點鬼佣,以binder_ref對應(yīng)的binder_node的地址為序*/
  ...
  int max_threads; /*最大線程數(shù)*/
  ...
};

2.3 用于用戶態(tài)向內(nèi)核態(tài)傳輸數(shù)據(jù)的結(jié)構(gòu)體 —— struct binder_write_read

struct binder_write_read {
  /* process ----> kernel */
  binder_size_t        write_size;    /* bytes to write, 進程用戶態(tài)地址空間傳遞到內(nèi)核數(shù)據(jù)的大小*/
  binder_size_t        write_consumed;    /* bytes consumed by driver 進程用戶態(tài)地址空間傳遞到內(nèi)核數(shù)據(jù)中已經(jīng)被內(nèi)核態(tài)處理的大小*/
  binder_uintptr_t    write_buffer;       /*進程用戶態(tài)地址空間傳遞到內(nèi)核數(shù)據(jù)的起始地址*/
/*  kernel ----> process */
  binder_size_t        read_size;    /* bytes to read及汉, 總共可供給驅(qū)動寫入的字節(jié)數(shù)沮趣,read_buffer可供內(nèi)核使用的大小*/
  binder_size_t        read_consumed;    /* bytes consumed by driver屯烦, 內(nèi)核Binder驅(qū)動發(fā)送給用戶態(tài)進程的字節(jié)數(shù)*/
  binder_uintptr_t    read_buffer;  /*內(nèi)核驅(qū)動發(fā)送給進程數(shù)據(jù)buffer的起始地址*/
};

2.4 Binder C/S通信架構(gòu)中坷随,C端的驅(qū)動層表示 —— struct binder_ref

struct binder_ref {
  /* Lookups needed: */
  /*   node + proc => ref (transaction) */
  /*   desc + proc => ref (transaction, inc/dec ref) */
  /*   node => refs + procs (proc exit) */
  int debug_id;                /*每個binder_ref的唯一標(biāo)識符房铭,主要用于debug*/
  struct rb_node rb_node_desc; /*用來鏈入proc->refs_by_desc紅黑樹中,該紅黑樹以desc域為序組織的*/
  struct rb_node rb_node_node; /*用來鏈入proc->refs_by_node紅黑樹中, 該紅黑樹以該binder_ref所對應(yīng)的binder_node的地址為序組織的*/
  struct hlist_node node_entry; /*用來鏈入binder_node的refs哈希鏈表中温眉。*/
  struct binder_proc *proc;     /*指向該binder_ref中所屬的binder_proc*/
  struct binder_node *node;     /*指向該binder_ref所對應(yīng)(引用)的binder_node*/
  uint32_t desc;                /*binder_ref的描述符缸匪。用來返回給進程用戶態(tài)地址空間,標(biāo)識所對應(yīng)的binder_ref*/
  int strong;                   /*強引用計數(shù)*/
  int weak;                     /*弱引用計數(shù)*/
  struct binder_ref_death *death; /*Binder“死亡訃告”相關(guān)的一個結(jié)構(gòu)體,詳見:2.8*/ 
};

2.5 Binder C/S通信架構(gòu)中类溢,S端的驅(qū)動層表示 —— struct binder_node

struct binder_node {
  int debug_id;
  struct binder_work work;
  union {
    struct rb_node rb_node;   /*用來鏈入proc的nodes紅黑樹凌蔬,該紅黑樹以binder_node的ptr的大小為序*/
    struct hlist_node dead_node;
  };
  struct binder_proc *proc;
  struct hlist_head refs; /*所有引用這個binder_node的binder_ref通過它的node_entry加入這個哈希鏈表中,
                        * 這樣binder_node通過查看這個哈希鏈表就知道有哪些binder_ref在引用它*/
  int internal_strong_refs;  /*binder_ref的強引用計數(shù)闯冷,即有多少個binder_ref強引用這個binder_node*/
  int local_weak_refs;       /*BBinder弱引用計數(shù)*/
  int local_strong_refs;    /*binder_buffer.target_node及BBinder的強引用計數(shù)*/
  binder_uintptr_t ptr;      /*對應(yīng)BBinder基類RefBase中mRef成員的的地址砂心,它是一個引用計數(shù)器,類型為weakref_impl*/
  binder_uintptr_t cookie;   /*對應(yīng)BBinder的地址*/**
  unsigned has_strong_ref:1;  /*標(biāo)識是否已經(jīng)增加了用戶態(tài)對應(yīng)binder service(BBinder)對象的強引用計數(shù)*/
  unsigned pending_strong_ref:1;  /*標(biāo)識是否有未處理的BR_ACQUIRE命令蛇耀,在執(zhí)行BR_ACQUIRE請求命令前設(shè)為1辩诞,在BC_ACQUIRE_DONE中設(shè)為0*/
  unsigned has_weak_ref:1;   /*標(biāo)識是否已經(jīng)增加了用戶態(tài)對應(yīng)binder service(BBinder)對象的弱引用計數(shù)*/
  unsigned pending_weak_ref:1; /*標(biāo)識是否有未處理的BR_INCREFS命令,在執(zhí)行BR_INCREFS請求命令前設(shè)為1纺涤,在BC_INCREFS_DONE中設(shè)為0*/
  unsigned has_async_transaction:1; /*標(biāo)識是否有異步事務(wù)要處理译暂。異步事務(wù)的含義是:客戶端發(fā)送了帶有TF_ONE_WAY標(biāo)識的請求。*/
  unsigned accept_fds:1;          /*是否接受文件描述符*/
  unsigned min_priority:8;
  struct list_head async_todo;  /*異步事務(wù)待處理鏈表*/
};

2.6 用于Binder用戶態(tài)向內(nèi)核驅(qū)動傳輸事務(wù)數(shù)據(jù) —— struct binder_transaction_data

struct binder_transaction_data {
  /* The first two are only used for bcTRANSACTION and brTRANSACTION,
   * identifying the target and contents of the transaction.
   */
  union {
    /* target descriptor of command transaction */
    __u32    handle;
    /* target descriptor of return transaction */
    binder_uintptr_t ptr;
  } target;
  binder_uintptr_t    cookie;    /* target object cookie */
  __u32        code;        /* transaction command */
  /* General information about the transaction. */
  __u32            flags;                      /*標(biāo)志位撩炊,如:TF_ONE_WAY*/
  pid_t        sender_pid;                /*發(fā)送者進程id*/
  uid_t        sender_euid;             /*發(fā)送者有效用戶id*/
  binder_size_t    data_size;    /* number of bytes of data */
  binder_size_t    offsets_size;    /* number of bytes of offsets */
  /* If this transaction is inline, the data immediately
 *  follows here; otherwise, it ends with a pointer to
 * the data buffer.
 */
  union {     /*存放事務(wù)的數(shù)據(jù)部分外永,如果是inline,則數(shù)據(jù)直接放在buf數(shù)組中拧咳;
               * 如果不是伯顶,則放在ptr結(jié)構(gòu)體中的buffer和offsets的指針中。一般情況都是通過ptr結(jié)構(gòu)體*/
    struct {
        /* transaction data */
        binder_uintptr_t    buffer;
        /* offsets from buffer to flat_binder_object structs */
        binder_uintptr_t    offsets;
      } ptr;
    __u8    buf[8]; /*inline數(shù)據(jù)直接放在這個buf中, 在4.0.9的內(nèi)核中骆膝,這個字段沒有看見使用的地方*/
  } data;
};

2.7 用于Binder內(nèi)核態(tài)驅(qū)動表示Binder通信事務(wù)數(shù)據(jù)結(jié)構(gòu) —— struct binder_transaction

struct binder_transaction {
  int debug_id;
  struct binder_work work;                   /*用于鏈入線程/進程todo隊列的成員*/
  struct binder_thread *from;               /*事務(wù)發(fā)起線程thread的地址砾淌,如果是binder server回復(fù)給client,該域為NULL*/
  struct binder_transaction ***from_parent**;  /* 用于鏈入事務(wù)發(fā)起線程的事務(wù)棧中谭网,
                                                * 加入的時機是binder_transaction_data傳入驅(qū)動并被binder_transaction處理的時候*/
  struct binder_proc *to_proc;        /*目標(biāo)線程的proc地址*/
  struct binder_thread *to_thread;    /*事務(wù)目標(biāo)線程thread的地址*/
  struct binder_transaction *to_parent; /* 用于鏈入目標(biāo)線程的事務(wù)棧中汪厨,
                                         * 加入的時機是目標(biāo)線程在調(diào)用binder_thread_read處理thread->todo隊列
                                         * 類型為BINDER_WORK_TRANACTION的binder_work時*/
  unsigned need_reply:1;
  /* unsigned is_dead:1; */    /* not used at the moment */
  struct binder_buffer *buffer;    /*存儲數(shù)據(jù)的地方*/
  unsigned int    code;                /*一個binder調(diào)用所對應(yīng)的代號*/
  unsigned int    flags;
  long    priority;                /*請求/回復(fù) 線程的優(yōu)先級*/
  long    saved_priority;     /*存儲線程優(yōu)先級備份,當(dāng)需要修改一個線程的優(yōu)先級時愉择,先將它當(dāng)前值放在該變量中劫乱,以便于稍后恢復(fù)。*/
  kuid_t    sender_euid;
};

進程用戶態(tài)傳輸進來的struct binder_transaction_data到內(nèi)核態(tài)后锥涕,會轉(zhuǎn)化成相應(yīng)的struct binder_transaction衷戈。該數(shù)據(jù)結(jié)構(gòu)主要用于承載Binder請求和回復(fù)通信中的數(shù)據(jù)。

2.8 用于注冊Binder service死亡通知的數(shù)據(jù)結(jié)構(gòu) —— binder_ref_death

struct binder_ref_death {
  struct binder_work work;  /*binder service死亡時层坠,通過該work的entry域鏈入thread或者proc的todo隊列*/
  binder_uintptr_t cookie; /*binder service死亡時殖妇,要通知的BpBinder對象的地址*/
};

3. 設(shè)備驅(qū)動控制 --- binder_ioctl

Binder驅(qū)動沒有提供read/write操作,所有數(shù)據(jù)傳輸破花、控制都是通過binder_ioctl進行谦趣,因此該部分是Binder驅(qū)動的核心內(nèi)容疲吸,承載了Binder數(shù)據(jù)傳輸部分的主要業(yè)務(wù)。

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int ret;
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    /*讀取命令的大小*/
    unsigned int size = _IOC_SIZE(cmd);
    void __user *ubuf = (void __user *)arg;
    /*pr_info("binder_ioctl: %d:%d %x %lx\n",
            proc->pid, current->pid, cmd, arg);*/
    trace_binder_ioctl(cmd, arg);
    /* 如果binder_stop_on_user_error < 2 則直接返回0前鹅;
    * 否則摘悴,調(diào)用_wait_event_interruptible進入可中斷的掛起狀態(tài),接著讓出處理器舰绘,
    * 直到被wake_up且條件(binder_stop_on_user_error < 2)為真時才返回
    */
    ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
    if (ret)
        goto err_unlocked;
    /*獲取binder_main_lock鎖*/
    binder_lock(__func__);
    /*在proc->threads紅黑樹中查找thread蹂喻,該紅黑樹以pid為序,具體詳見3.1*/
    thread = **binder_get_thread**(proc);
    if (thread == NULL) {
        ret = -ENOMEM;
        goto err;
    }
    /*根據(jù)不同的命令捂寿,調(diào)用不同的處理函數(shù)進行處理*/
    switch (cmd) {
    case BINDER_WRITE_READ:
        /*讀寫命令,數(shù)據(jù)傳輸,binder IPC通信的核心邏輯口四,詳見3.2*/
        ret = **binder_ioctl_write_read**(filp, cmd, arg, thread);
        if (ret)
            goto err;
        break;
    case BINDER_SET_MAX_THREADS:
        /*設(shè)置最大線程數(shù),直接將值設(shè)置到proc結(jié)構(gòu)的max_threads域中秦陋。*/
        if (copy_from_user(&**proc->max_threads**, ubuf, sizeof(proc->max_threads))) {
            ret = -EINVAL;
            goto err;
        }
        break;
    case BINDER_SET_CONTEXT_MGR:
        /*設(shè)置Context manager窃祝,即將自己設(shè)置為ServiceManager,詳見3.3*/
        ret = binder_ioctl_set_ctx_mgr(filp);
        if (ret)
            goto err;
        break;
    case BINDER_THREAD_EXIT:
        /*binder線程退出命令踱侣,釋放相關(guān)資源,詳見3.4*/
        binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n",
                proc->pid, thread->pid);
        binder_free_thread(proc, thread);
        thread = NULL;
        break;
    case BINDER_VERSION: {
        /*獲取binder驅(qū)動版本號粪小,在kernel4.4版本中,32位該值為7抡句,64位版本該值為8*/
        struct binder_version __user *ver = ubuf;
        if (size != sizeof(struct binder_version)) {
            ret = -EINVAL;
            goto err;
        }
        /*將版本號信息寫入用戶態(tài)地址空間struct binder_version的protocol_version中*/
        if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
                &ver->protocol_version)) {
            ret = -EINVAL;
            goto err;
        }
        break;
    }
    default:
        ret = -EINVAL;
        goto err;
    }
    ret = 0;
    err:
        if (thread)
            thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
        binder_unlock(__func__); /*釋放binder_main_lock鎖*/
        wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
        if (ret && ret != -ERESTARTSYS)
            pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
    err_unlocked:
        trace_binder_ioctl_done(ret);
        return ret;
}
  • _IOC_SIZE讀取參數(shù)命令的大小探膊。在32位的體系架構(gòu)中,參數(shù)cmd由四個域組成:
    • 讀寫屬性域(direction: read/write)待榔, 區(qū)分是讀取命令逞壁,還是寫入命令。bit30~bit31锐锣,占2bit腌闯。可用宏_IOC_DIR讀取雕憔。
    • 數(shù)據(jù)大小域(size : size of argument), 表示ioctlarg變量所指內(nèi)存區(qū)域占用內(nèi)存大小姿骏。bit16~bit29,占14bit斤彼》质荩可用宏_IOC_SIZE讀取 。
    • 魔數(shù)域 (type:usually related to the major number)琉苇,又叫“幻數(shù)”區(qū)缨恒,用來區(qū)分不同的設(shè)備驅(qū)動柳畔,當(dāng)傳入的值與自身的值不一致時則不進行進一步處理牧氮,是用于防止誤使用的一種狀態(tài)標(biāo)識位文搂。一般用字母A~Z或者a~z表示。bit8~bit15,占8bit土陪≈绾梗可用宏_IOC_TYPE讀取。
    • 序號數(shù)或者基數(shù)(command):用于區(qū)分各種命令旺坠。bit0~bit7乔遮,占8bit扮超∪∪校可用宏_IOC_NR讀取。
  • binder_stop_on_user_error, 該變量是一個全局靜態(tài)變量, 它的值通過模塊參數(shù)stop_on_user_error控制出刷,當(dāng)系統(tǒng)出現(xiàn)問題時璧疗,可以通過將該值設(shè)置為一個大于或等于2的值,來暫停binder馁龟,來進行debug崩侠。模塊參數(shù)的設(shè)置可以在模塊插入時以參數(shù)傳遞的形式設(shè)定,如 insmod xxx.ko arg=xxxx形式坷檩;如果權(quán)限設(shè)置允許的話却音,也可以通過sysfs來動態(tài)設(shè)置(如echo 3 > /sys/module/binder/parameters/stop_no_user_error)。相關(guān)代碼如下:
static int binder_stop_on_user_error;
  /*定義模塊參數(shù)`stop_on_user_error`的設(shè)置函數(shù)*/
static int binder_set_stop_on_user_error(const char *val,
                    struct kernel_param *kp)
{
    int ret;
    ret = param_set_int(val, kp);/*將sysfs中/sys/module/binder/parameters/stop_on_user_error讀入binder_stop_on_user_error*/
    if (binder_stop_on_user_error < 2)
        wake_up(&binder_user_error_wait);
    return ret;
}
module_param_call(stop_on_user_error/*模塊參數(shù)名字,所在路徑為:/sys/module/binder/parameters/stop_on_user_error*/, 
    binder_set_stop_on_user_error /*模塊參數(shù)`stop_on_user_error`的set函數(shù)*/,
    param_get_int/*模塊參數(shù)`stop_on_user_error`的讀取函數(shù)*/, 
    &binder_stop_on_user_error/*模塊參數(shù)對應(yīng)的變量地址*/,
    S_IWUSR | S_IRUGO /*在sysfs中的權(quán)限設(shè)置*/);
  • module_param_call該宏用于定義一個內(nèi)核模塊參數(shù)矢炼,它的定義為module_param_call(name, set, get, arg, perm)系瓢,其中:
    • name:內(nèi)核模塊參數(shù)的名字,也是在sysfs中顯示的名字句灌;
    • set:是該內(nèi)核模塊參數(shù)設(shè)定的回調(diào)函數(shù)夷陋,當(dāng)在插入模式時傳遞參數(shù)或者通過sysfs設(shè)定內(nèi)核模塊參數(shù)時,該函數(shù)會被調(diào)用胰锌;
    • get: 是該內(nèi)核模塊參數(shù)讀取的回調(diào)函數(shù)骗绕;
    • arg:內(nèi)核模塊參數(shù)的地址;
    • perm:該內(nèi)核模塊參數(shù)的權(quán)限設(shè)置资昧,可以在sysfs中看到酬土。

對于基本的數(shù)據(jù)類型的讀取和設(shè)定回調(diào)函數(shù),內(nèi)核已經(jīng)預(yù)先做了定義格带,一般形式為:param_get_xxxparam_set_xxx诺凡,xxxint, short等〖螅可以參考一下這篇博客腹泌,Linux內(nèi)核模塊的編寫方法和技巧

  • 額外提一下sysfs尔觉,它是Linux2.6開始提供的一種虛擬文件系統(tǒng)凉袱,設(shè)計該文件系統(tǒng)的目的是把原本在procfs關(guān)于設(shè)備的部分獨立出來,以“設(shè)備層次結(jié)構(gòu)架構(gòu)(device tree)”的形式呈現(xiàn)。它可以把設(shè)備和驅(qū)動程序的信息從內(nèi)核輸出到用戶空間专甩,也可以對設(shè)備和驅(qū)動程序做設(shè)置钟鸵。具體詳見sysfs簡介

3.1 查找thread --- binder_get_thread

static struct binder_thread *binder_get_thread(struct binder_proc *proc)
{
    struct binder_thread *thread = NULL;
    struct rb_node *parent = NULL;
    struct rb_node **p = &proc->threads.rb_node; /*獲取紅黑樹根節(jié)點*/
/*查找pid等于當(dāng)前線程id的thread涤躲,該紅黑樹以pid大小為序組織*/
    while (*p) {
        parent = *p;
        thread = rb_entry(parent, struct binder_thread, rb_node);
    /*current->pid 是當(dāng)前運行線程的id棺耍,不是進程的id*/
        if (current->pid < thread->pid)
            p = &(*p)->rb_left;
        else if (current->pid > thread->pid)
            p = &(*p)->rb_right;
        else
            break;
    }
    if (*p == NULL) {
        /*如果沒有找到,則新創(chuàng)建一個*/
        thread = kzalloc(sizeof(*thread), GFP_KERNEL);
        if (thread == NULL)
            return NULL;
        /*更新thread創(chuàng)建統(tǒng)計計數(shù)*/
        binder_stats_created(BINDER_STAT_THREAD);
        /*初始化相關(guān)數(shù)據(jù)成員*/
        thread->proc = proc;
        thread->pid = current->pid; /*獲取線程id*/
        init_waitqueue_head(&thread->wait);    /*初始化等待隊列*/
        INIT_LIST_HEAD(&thread->todo);       /*初始化待處理隊列*/
        rb_link_node(&thread->rb_node, parent, p);  /*加入到proc的threads紅黑樹中*/
        rb_insert_color(&thread->rb_node, &proc->threads);
        thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
        thread->return_error = BR_OK;
        thread->return_error2 = BR_OK;
    }
    return thread;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末种樱,一起剝皮案震驚了整個濱河市蒙袍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嫩挤,老刑警劉巖害幅,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異岂昭,居然都是意外死亡以现,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門约啊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來邑遏,“玉大人,你說我怎么就攤上這事恰矩〖呛校” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵枢里,是天一觀的道長孽鸡。 經(jīng)常有香客問我,道長栏豺,這世上最難降的妖魔是什么彬碱? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮奥洼,結(jié)果婚禮上巷疼,老公的妹妹穿的比我還像新娘。我一直安慰自己灵奖,他們只是感情好嚼沿,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瓷患,像睡著了一般骡尽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上擅编,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天攀细,我揣著相機與錄音箫踩,去河邊找鬼。 笑死谭贪,一個胖子當(dāng)著我的面吹牛境钟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俭识,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼慨削,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了套媚?” 一聲冷哼從身側(cè)響起缚态,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凑阶,沒想到半個月后猿规,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衷快,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡宙橱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蘸拔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片师郑。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖调窍,靈堂內(nèi)的尸體忽然破棺而出宝冕,到底是詐尸還是另有隱情,我是刑警寧澤邓萨,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布地梨,位于F島的核電站,受9級特大地震影響缔恳,放射性物質(zhì)發(fā)生泄漏宝剖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一歉甚、第九天 我趴在偏房一處隱蔽的房頂上張望万细。 院中可真熱鬧,春花似錦纸泄、人聲如沸赖钞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雪营。三九已至,卻和暖如春衡便,著一層夾襖步出監(jiān)牢的瞬間献起,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留征唬,地道東北人捌显。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像总寒,于是被迫代替她去往敵國和親扶歪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容