<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                從前面4.6.2小節的內容可以知道,Logcat工具是從源代碼文件logcat.cpp中的函數readLogLines開始讀取日志記錄的,我們分段來閱讀這個函數的實現。 **system/core/logcat/logcat.cpp** ~~~ static void readLogLines(log_device_t* devices) { log_device_t* dev; int max = 0; int ret; int queued_lines = 0; bool sleep = true; int result; fd_set readset; for (dev=devices; dev; dev = dev->next) { if (dev->fd > max) { max = dev->fd; } } while (1) { do { timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR. FD_ZERO(&readset); for (dev=devices; dev; dev = dev->next) { FD_SET(dev->fd, &readset); } result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout); } while (result == -1 && errno == EINTR); ~~~ 由于Logcat工具有可能同時打開了多個日志設備,因此,第19行到第26行的while循環就使用函數select來同時監控它們是否有內容可讀,即是否有新的日志記錄需要讀取。調用函數select時,需要指定所監控的日志設備文件描述符的最大值,因此,第12行到第16行的for循環就用來查找這些打開的日志設備中的最大文件描述符,并保存在變量max中。在調用函數select之前,第22行到第24行的for循環把所有打開的日志設備的文件描述符都保存到一個fd_set對象readset中,接著第25行就調用函數select來監控前面所打開的日志設備是否有新的日志記錄可讀,其中,指定的等待時間為5毫秒,即如果在5毫秒之內,所有打開的日志設備都沒有新的日志記錄可讀,那么函數select就超時返回,即它的返回值為0;否則,函數select就會將fd_set對象readset中的相應位設置為1,表示該位所對應的日志設備有新的日志記錄可讀,這時候函數select的返回值是大于0的。如果在調用函數select的過程中,Logcat工具有信號需要處理,那么函數select的返回值就會等于-1,并且錯誤代碼errno等于EINTR,表示Logcat工具需要重新調用函數select來檢查打開的日志設備是否有新的日志記錄可讀。 當函數跳出第19行到26行的while循環之后,有可能是等待超時,也有可能是所監控的日志設備中有新的日志記錄可讀,因此,我們需要分兩種情況來分析日志記錄的讀取過程。 首先分析日志設備中有新的日志記錄可讀的情況,如下所示。 **system/core/logcat/logcat.cpp** ~~~ if (result >= 0) { for (dev=devices; dev; dev = dev->next) { if (FD_ISSET(dev->fd, &readset)) { queued_entry_t* entry = new queued_entry_t(); /* NOTE: driver guarantees we read exactly one full entry */ ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN); if (ret < 0) { if (errno == EINTR) { delete entry; goto next; } if (errno == EAGAIN) { delete entry; break; } perror("logcat read"); exit(EXIT_FAILURE); } else if (!ret) { fprintf(stderr, "read: Unexpected EOF!\n"); exit(EXIT_FAILURE); } entry->entry.msg[entry->entry.len] = '\0'; dev->enqueue(entry); ++queued_lines; } } ~~~ 第28行到第55行的for循環依次處理有新的日志記錄可讀的日志設備。如果一個日志設備有新的日志記錄可讀,那么第29行的if語句就會為true,接著第30行就會分配一個queued_entry_t結構體entry,并且第32行調用函數read把該日志設備中的一條新的日志記錄讀到結構體entry內部的緩沖區buf中。如果在讀取日志記錄的過程中出現錯誤,那么Logcat工具就會調用函數exit直接退出。但是如果錯誤碼等于EINTR或者EAGAIN,就需要特殊處理。如果錯誤代碼errno等于EINTR,就說明Logcat工具在讀取日志記錄的過程中被信號打斷,因此,Logcat工具會重新執行next標簽處的代碼,即重新執行第18行的while循環來監控所打開的日志設備中是否有新的日志記錄可讀。如果錯誤碼等于EAGAIN,就說明該日志設備在打開時指定了O_NONBLOCK標志,即以非阻塞的模式來打開該日志設備,這時候Logcat工具就會跳出第28行的for循環,繼續往下執行。 如果第32行成功地從相應的日志設備中讀取到新的日志記錄,那么第52行就會將它加入到相應的日志設備的日志記錄隊列中,并且第53行就會將隊列中的日志記錄計數queued_lines增加1,表示Logcat工具當前正在等待顯示的日志記錄條數。 第28行的for循環執行完成之后,就從每個有新的日志記錄的日志設備中讀出一條日志記錄。 > 這些日志設備中的可讀日志記錄數可能不只一條,因此,接下來還需要執行第18行的while循環來繼續讀取這些日志設備中的其他日志記錄。不過,在繼續讀取這些剩余的日志記錄之前,Logcat工具先處理前面已經從日志設備中讀取出來的日志記錄,如下所示。 **system/core/logcat/logcat.cpp** ~~~ if (result == 0) { // we did our short timeout trick and there's nothing new // print everything we have and wait for more data sleep = true; while (true) { chooseFirst(devices, &dev); if (dev == NULL) { break; } if (g_tail_lines == 0 || queued_lines <= g_tail_lines) { printNextEntry(dev); } else { skipNextEntry(dev); } --queued_lines; } // the caller requested to just dump the log and exit if (g_nonblock) { exit(0); } } else { // print all that aren't the last in their list sleep = false; while (g_tail_lines == 0 || queued_lines > g_tail_lines) { chooseFirst(devices, &dev); if (dev == NULL || dev->queue->next == NULL) { break; } if (g_tail_lines == 0) { printNextEntry(dev); } else { skipNextEntry(dev); } --queued_lines; } } } next: ; } } ~~~ 第56行到第92行的if語句塊是用來處理日志記錄輸出的,主要通過chooseFirst、printNextEntry和skipNextEntry三個函數來實現。 由于Logcat工具是按照寫入時間的先后順序來輸出日志記錄的,因此,在輸出已經讀取的日志記錄之前,Logcat工具首先會調用函數chooseFirst找到包含有最早的未輸出日志記錄的日志設備,它的實現如下所示。 **system/core/logcat/logcat.cpp** ~~~ static void chooseFirst(log_device_t* dev, log_device_t** firstdev) { for (*firstdev = NULL; dev != NULL; dev = dev->next) { if (dev->queue != NULL && (*firstdev == NULL || cmp(dev->queue, (*firstdev)->queue) < 0)) { *firstdev = dev; } } } ~~~ 因為每一個日志設備的日志隊列都是按照寫入時間的先后順序來排列日志記錄的,因此,函數chooseFirst只要比較日志隊列中的第一個日志記錄的寫入時間,就可以找到包含有最早的未輸出日志記錄的日志設備。 真正用來輸出日志記錄的函數是printNextEntry,它的實現如下所示。 **system/core/logcat/logcat.cpp** ~~~ static void printNextEntry(log_device_t* dev) { maybePrintStart(dev); if (g_printBinary) { printBinary(&dev->queue->entry); } else { processBuffer(dev, &dev->queue->entry); } skipNextEntry(dev); } ~~~ 第2行調用函數maybePrintStart來檢查日志設備dev中的日志記錄是否是第一次輸出。如果是,就會首先輸出一行提示性文字,如下所示。 **system/core/logcat/logcat.cpp** ~~~ static void maybePrintStart(log_device_t* dev) { if (!dev->printed) { dev->printed = true; if (g_devCount > 1 && !g_printBinary) { char buf[1024]; snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device); if (write(g_outFD, buf, strlen(buf)) < 0) { perror("output error"); exit(-1); } } } } ~~~ 回到函數printNextEntry中,如果在啟動Logcat工具時,指定了B選項,那么全局變量g_printBinary的值就會被設置為1,表示Logcat工具要以二進制格式來輸出讀取到的日志記錄,因此,第4行就會調用函數printBinary來輸出已經讀取到的日志記錄;否則,第6行就會調用函數processBuffer來輸出已經讀取到的日志記錄。在接下來的4.6.4小節中分析日志記錄的輸出過程時,我們再詳細分析這兩個函數的實現。 日志隊列中的日志記錄輸出之后,就要將它從隊列中刪除,這是通過調用函數skipNextEntry來實現的,如下所示。 **system/core/logcat/logcat.cpp** ~~~ static void skipNextEntry(log_device_t* dev) { maybePrintStart(dev); queued_entry_t* entry = dev->queue; dev->queue = entry->next; delete entry; } ~~~ 回到函數readLogLines中,我們接著分析第56行到第92行的if語句塊是如何處理那些已經從日志設備中讀取出來的日志記錄的。 如果變量result的值等于0,即第56行的if語句為true,就說明前面在調用函數select監控日志設備中是否有新的日志記錄可讀時超時了。既然所有打開的日志設備都沒有新的日志記錄可讀,第60行到第71行的while循環就是時候輸出之前已經讀取出來的日志記錄了。第61行首先調用函數chooseFirst來獲得包含有最早的未輸出日志記錄的日志設備,然后再考慮是否要輸出這條最早的日志記錄。如果在啟動Logcat工具時,指定了t選項,即限定了可以輸出的最新日志記錄的條數,那么就需要計算所有日志設備中的未輸出日志記錄的條數。如果未輸出的日志記錄條數大于可以輸出的最大值,即全局變量g_tail_lines的值,那么就需要將最早的一部分日志記錄丟棄;如果沒有限定可以輸出的最新日志記錄的條數,即全局變量g_tail_lines的值為0,那么Logcat工具就會將所有未輸出的日志記錄輸出。處理完成日志設備中的已讀取日志記錄之后,第74行檢查Logcat工具是否以非阻塞的模式來打開日志設備。如果是,由于這時候函數select是超時返回,即日志設備中沒有新的日志記錄可讀,那么Logcat工具就直接從第75行退出了。 如果變量result的值大于0,即第56行的if語句為false,那么Logcat工具就會執行第77行到第92行代碼來處理日志設備中的已讀取日志記錄。在這種情況下,日志設備中可能還有新的日志記錄等待讀取,因此,它的處理方式就會與函數select超時的情況有所不同。這時候如果沒有限定可以輸出的最新日志記錄的條數,即全局變量g_tail_lines的值為0,那么Logcat工具就不用考慮日志設備中是否還有剩余的日志記錄未讀取了,它可以立即輸出那些已經讀取的日志記錄;如果限定了可以輸出的最新日志記錄的條數,即全局變量g_tail_lines的值大于0,那么就要把最早的一部分日志記錄刪除,直到它們的數量小于等于限定的可以輸出的最新日志記錄的條數為止。在這種情況下,還需要繼續讀取日志設備中的其余未讀取日志記錄,直到所有打開的日志設備都沒有新的日志記錄可讀時,Logcat工具才會將已經讀取的日志記錄輸出。 以上就是日志記錄的讀取過程。接下來,我們繼續分析日志記錄的輸出過程。
                  <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>

                              哎呀哎呀视频在线观看