<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                第一個關鍵點是RIL_startEventLoop函數,這個函數實際上是由libRil.so實現的,它的代碼在Ril.cpp中,代碼如下所示: **Ril.cpp** ~~~ extern "C" void RIL_startEventLoop(void){ intret; pthread_attr_t attr; s_started= 0; pthread_mutex_lock(&s_startupMutex); pthread_attr_init (&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); //創建工作線程eventLoop ret =pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL); /* 工作線程eventLoop運行后會設置s_started為1,并觸發s_startupCond。 這幾個語句的目的是保證在RIL_startEventLoop返回前,工作線程一定是已經創建并運行了 */ while(s_started == 0) { pthread_cond_wait(&s_startupCond, &s_startupMutex); } pthread_mutex_unlock(&s_startupMutex); if(ret < 0) { return; } } ~~~ 從上面代碼中可知,RIL_startEventLoop會等待工作線程創建并運行成功。這個線程為什么會如此重要呢?下面就來了解一下工作線程eventLoop。 1. 工作線程eventLoop 工作線程eventLoop的代碼如下所示: **Ril.cpp** ~~~ static void * eventLoop(void *param) { intret; intfiledes[2]; //①初始化請求隊列 ril_event_init(); //下面這幾個操作告訴RIL_startEventLoop函數本線程已經創建并成功運行了。 pthread_mutex_lock(&s_startupMutex); s_started = 1; pthread_cond_broadcast(&s_startupCond); pthread_mutex_unlock(&s_startupMutex); //創建匿名管道 ret =pipe(filedes); ...... s_fdWakeupRead = filedes[0]; s_fdWakeupWrite = filedes[1]; //設置管道讀端口的屬性為非阻塞 fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK); //②下面這兩句話將匿名管道的讀寫端口加入到event隊列中。 ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true, processWakeupCallback, NULL); rilEventAddWakeup (&s_wakeupfd_event); //③進入事件等待循環中,等待外界觸發事件并做對應的處理。 ril_event_loop(); returnNULL; } ~~~ 工作線程的工作并不復雜,主要有三個關鍵點。 (1)ril_event_init的分析 工作線程,顧名思義就是用來干活的。要讓它干活,是否得有一些具體的任務呢?它是如何管理這些任務的呢?對這兩問題的回答是: - 工作線程使用了一個叫ril_event的結構體,來描述一個任務,并且它將多個任務按時間順序組織起來,保存在任務隊列中。這個時間順序是指該任務的執行時間,由外界設定,可以是未來的某時間。 r il_event_init函數就是用來初始化相關隊列和管理結構的,代碼如下所示: 在代碼中,“任務”也稱為“事件”,如沒有特殊說明必要,這兩者以后不再做區分。 **Ril.cpp** ~~~ void ril_event_init() { MUTEX_INIT();//初始化一個mutex對象listMutex FD_ZERO(&readFds);//初始化readFds,看來Ril會使用select來做多路IO復用 //下面的timer_list和pending_list分別是兩個隊列 init_list(&timer_list);//初始化timer_list,任務插入的時候按時間排序 init_list(&pending_list);//初始化pendling_list,保存每次需要執行的任務 /* watch_table(監控表)定義如下: static struct ril_event * watch_table[MAX_FD_EVENTS]; 其中MAX_FD_EVENTS的值為8。監控表主要用來保存那些FD已經加入到readFDs中的 任務。 */ memset(watch_table, 0, sizeof(watch_table)); } ~~~ 此ril_event_init函數沒什么新鮮的內容。任務在代碼中的對等物Ril_event結構的代碼,如下所示: **Ril_event.h** ~~~ struct ril_event { structril_event *next; structril_event *prev;//next和prev將ril_event組織成了一個雙向鏈表 intfd; //該任務對應的文件描述符,以后簡稱FD。 intindex; //這個任務在監控表中的索引 /* 是否永久保存在監控表中,一個任務處理完畢后將根據這個persist參數來判斷 是否需要從監控表中移除。 */ boolpersist; structtimeval timeout; //該任務的執行時間 ril_event_cb func; //任務函數 void*param; //傳給任務函數的參數 }; ~~~ ril_event_init剛初始化完任務隊列,下面就有地方添加任務了。 (2)任務加入隊列 下面這兩行代碼初始化一個FD為s_wakeupfd_event的任務,并將其加入到監控表中: ~~~ /* s_wakeupfd_event定義為一個靜態的ril_event,ril_event_set函數將初始化它的 FD為管道的讀端,任務函數ril_event_cb對應為processWakeupCallback, 并設置persist為true */ ril_event_set (&s_wakeupfd_event, s_fdWakeupRead,true, processWakeupCallback, NULL); //來看這個函數: rilEventAddWakeup (&s_wakeupfd_event); ~~~ rilEventAddWakeup比較有意思,來看這個函數; **Ril.cpp** ~~~ static void rilEventAddWakeup(struct ril_event*ev) { ril_event_add(ev);//ev指向一條任務 triggerEvLoop(); } //直接看ril_event_add函數和triggerEvLoop函數。 void ril_event_add(struct ril_event * ev) { ...... MUTEX_ACQUIRE();//鎖保護 for (int i =0; i < MAX_FD_EVENTS; i++) { //從監控表中找到第一個空閑的索引,然后把這個任務加到監控表中, //index表示這個任務在監控中的索引 if(watch_table[i] == NULL) { watch_table[i] = ev; ev->index = i; ...... //將任務的FD加入到readFds中,這是select使用的標準方法 FD_SET(ev->fd, &readFds); if (ev->fd >= nfds) nfds = ev->fd+1; ...... break; } } MUTEX_RELEASE(); ...... } //再來看triggerEvLoop函數,這個更簡單了: static void triggerEvLoop() { intret; /* s_tid_dispatch是工作線程eventLoop的線程ID,pthread_self返回調用線程的線程ID。 由于這里調用triggerEvLoop的就是eventLoop自己,所以不會走if 分支。但是可以看看 里面的內容。 */ if(!pthread_equal(pthread_self(), s_tid_dispatch)) { do{ //s_fdWakeupWrite為匿名管道的寫端口,看來觸發eventLoop工作的條件就是 //往這個端口寫一點數據了。 ret = write (s_fdWakeupWrite, " ", 1); }while (ret < 0 && errno == EINTR); } } ~~~ 一般的線程間通信使用同步對象來觸發,而rild是通過往匿名管道寫數據來觸發工作線程工作的。 (3)ril_event_loop的分析 來看最后一個關鍵函數ril_event_loop,其代碼如下所示: **Ril.cpp** ~~~ void ril_event_loop() { int n; fd_setrfds; structtimeval tv; structtimeval * ptv; for(;;) { memcpy(&rfds, &readFds,sizeof(fd_set)); /* 根據timer_list來計算select函數的等待時間,timer_list已經 按任務的執行時間排好序了。 */ if(-1 == calcNextTimeout(&tv)) { ptv = NULL; }else { ptv = &tv; } ......; //調用select進行多路IO復用 n= select(nfds, &rfds, NULL, NULL, ptv); ...... //將timer_list中那些執行時間已到的任務移到pending_list隊列。 processTimeouts(); //從監控表中轉移那些有數據要讀的任務到pending_list隊列,如果任務的persisit不為 //true,則同時從監控表中移除這些任務 processReadReadies(&rfds, n); //遍歷pending_list,執行任務的任務函數。 firePending(); } } ~~~ 根據對ril_event_Loop函數的分析可知,Rild支持兩種類型的任務: - 定時任務。它的執行由執行時間決定,和監控表沒有關系,在Ril.cpp中由ril_timer_add函數添加。 - 非定時任務,也叫Wakeup Event。這些任務的FD將加入到select的讀集合(readFDs)中,并且在監控表中存放了對應的任務信息。它們觸發的條件是這些FD可讀。對于管道和Socket來說,FD可讀意味著接收緩沖區中有數據,這時調用recv不會因為沒有數據而阻塞。 對于處于listen端的socket來說,FD可讀表示有客戶端連接上了,此時需要調用accept接受連接。 2. RIL_startEventLoop小結 總結一下RIL_startEventLoop的工作。從代碼中看,這個函數將啟動一個比較重要的工作線程eventLoop,該線程主要用來完成一些任務處理,而目前還沒有給它添加任務。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看