<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之旅 廣告
                當進程調用函數write、writev或者aio_write往日志設備寫入日志記錄時,Logger日志驅動程序中的函數logger_aio_write就會被調用來執行日志記錄的寫入操作。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ /* * logger_aio_write - our write method, implementing support for write(), * writev(), and aio_write(). Writes are our fast path, and we try to optimize * them above all else. */ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t ppos) { struct logger_log *log = file_get_log(iocb->ki_filp); size_t orig = log->w_off; struct logger_entry header; struct timespec now; ssize_t ret = 0; now = current_kernel_time(); header.pid = current->tgid; header.tid = current->pid; header.sec = now.tv_sec; header.nsec = now.tv_nsec; header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD); /* null writes succeed, return zero */ if (unlikely(!header.len)) return 0; mutex_lock(&log->mutex); /* * Fix up any readers, pulling them forward to the first readable * entry after (what will be) the new write offset. We do this now * because if we partially fail, we can end up with clobbered log * entries that encroach on readable buffer. */ fix_up_readers(log, sizeof(struct logger_entry) + header.len); do_write_log(log, &header, sizeof(struct logger_entry)); while (nr_segs-- > 0) { size_t len; ssize_t nr; /* figure out how much of this vector we can keep */ len = min_t(size_t, iov->iov_len, header.len - ret); /* write out this segment's payload */ nr = do_write_log_from_user(log, iov->iov_base, len); if (unlikely(nr < 0)) { log->w_off = orig; mutex_unlock(&log->mutex); return nr; } iov++; ret += nr; } mutex_unlock(&log->mutex); /* wake up any blocked readers */ wake_up_interruptible(&log->wq); return ret; } ~~~ 函數的第一個參數iocb表示一個IO上下文。第二個參數iov保存了要寫入的日志記錄的內容,它是一個數組向量,長度由第三個參數nr_segs決定。第四個參數ppos指定日志記錄的寫入位置。由于日志設備中保存了下一條日志記錄的寫入位置,因此,第四個參數ppos是不需要使用的。 對于類型為main、system和radio的日志記錄來說,它們的內容是由優先級(priority)、標簽(tag)和內容(msg)三個字段組成的,分別保存在iov[0]、iov[1]和iov[2]中,這時候第三個參數nr_segs的值就為3。對于類型為events的日志記錄來說,它們的內容只有標簽和內容兩個字段,分別保存在iov[0]和iov[1]中,這時候第三個參數nr_segs的值就為2。在特殊情況下,當類型為events的日志記錄的內容只有一個值時,第二個參數iov的大小也會等于3,這時候,iov[0]表示日志標簽,iov[1]表示日志記錄的內容值類型,iov[2]表示日志記錄的內容值。在后面的4.4小節中分析日志的寫入接口時,我們再詳細介紹參數iov的使用方法。無論要寫入的是什么類型的日志記錄,它的總長度值都是保存在參數iocb的成員變量ki_left中的,單位是字節。 在前面的4.2.3小節提到,當進程以寫模式打開日志設備時,Logger日志驅動程序會把對應的日志緩沖區結構體log保存在一個打開文件結構體file的成員變量private_data中。參數iocb的成員變量ki_filp正好指向該打開文件結構體,因此,第9行就調用函數file_get_log安全地將對應的日志緩沖區結構體log獲取回來。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ static inline struct logger_log * file_get_log(struct file *file) { if (file->f_mode & FMODE_READ) { struct logger_reader *reader = file->private_data; return reader->log; } else return file->private_data; } ~~~ 有了這個日志緩沖區結構體log之后,就可以執行日志記錄的寫入操作了。 回到函數logger_aio_write中,第11行首先定義一個日志記錄結構體header,接著第17行到第21行對它進行初始化,即記錄日志記錄寫入進程的TGID和PID,以及日志記錄的寫入時間和長度。由于一條日志記錄的最大長度為LOGGER_ENTRY_MAX_PAYLOAD,因此,第21行在初始化日志記錄的長度時,要取參數iocb的成員變量ki_left和宏LOGGER_ENTRY_MAX_PAYLOAD的較小值。 在將日志記錄寫入到日志緩沖區之前,還有一件重要的事情要做,就是修正那些正在讀取該日志緩沖區的進程的當前日志記錄的讀取位置,即日志讀取進程結構體logger_reader的成員變量r_off的值,以及修正新的日志讀取進程的日志記錄開始讀取位置,即日志緩沖區結構體logger_log的成員變量head的值。我們知道,日志緩沖區是循環使用的,即當日志緩沖區寫滿之后,新的日志記錄會覆蓋舊的日志記錄,而這些將要被覆蓋的日志記錄有可能正好是某些進程的下一條日志記錄的讀取位置。由于這些位置即將被新的日志記錄覆蓋,因此,我們就需要對它們進行修正,以便這些受影響的進程下次能夠讀取到正確的日志記錄。這個修正工作要在日志記錄寫入前去做,這是為了保證在日志記錄寫入的過程中出現部分失敗時,不會破壞整個日志緩沖區的內容。 修正日志記錄讀取進程的讀取位置的工作是通過調用函數fix_up_readers來完成的,它的實現如下所示。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ /* * fix_up_readers - walk the list of all readers and "fix up" any who were * lapped by the writer; also do the same for the default "start head". * We do this by "pulling forward" the readers and start head to the first * entry after the new write head. * * The caller needs to hold log->mutex. */ static void fix_up_readers(struct logger_log *log, size_t len) { size_t old = log->w_off; size_t new = logger_offset(old + len); struct logger_reader *reader; if (clock_interval(old, new, log->head)) log->head = get_next_entry(log, log->head, len); list_for_each_entry(reader, &log->readers, list) if (clock_interval(old, new, reader->r_off)) reader->r_off = get_next_entry(log, reader->r_off, len); } ~~~ 第二個參數len表示即將要寫入的日志記錄的總長度,它等于日志記錄結構體logger_entry的長度加上日志記錄的有效負載長度。第11行得到日志緩沖區結構體log的下一條日志記錄的寫入位置,保存在變量old中。第12行計算將新的日志記錄寫入到日志緩沖區結構體log之后,下一條日志記錄的寫入位置,保存在變量new中。位于old值和new值之間的那些日志記錄讀取位置是無效的,因為它們即將被新寫入的日志記錄覆蓋。 給定一個日志記錄讀取位置c,判斷它是否位于a和b之間是通過調用函數clock_interval來實現的,如下所示。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ /* * clock_interval - is a < c < b in mod-space? Put another way, does the line * from a to b cross c? */ static inline int clock_interval(size_t a, size_t b, size_t c) { if (b < a) { if (a < c || b >= c) return 1; } else { if (a < c && b >= c) return 1; } return 0; } ~~~ 函數clock_interval分兩種情況來判斷c是否位于a和b之間:第一種情況是b小于a;第二種情況是b大于等于a。在這兩種情況下,如果c位于a和b之間,那么函數的返回值為1,否則為0。 回到函數fix_up_readers中,第16行修正的是新的日志讀取進程在日志緩沖區結構體log中的開始讀取位置,即日志緩沖區結構體log的成員變量head的值。第18行到第20行的循環語句修正的是那些正在讀取日志緩沖區結構體log中的日志記錄的進程的下一條日志記錄的位置,即日志讀取進程結構體reader的成員變量r_off的值。如果這些位置正好位于變量old和new的值之間,那么就調用函數get_next_entry將它們的值修改為下一條日志記錄的位置。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ /* * get_next_entry - return the offset of the first valid entry at least 'len' * bytes after 'off'. * * Caller must hold log->mutex. */ static size_t get_next_entry(struct logger_log *log, size_t off, size_t len) { size_t count = 0; do { size_t nr = get_entry_len(log, off); off = logger_offset(off + nr); count += nr; } while (count < len); return off; } ~~~ 參數off表示要修正的位置,而參數len表示即將要寫入的日志記錄的長度。第11行到第15行的while循環首先調用函數get_entry_len來獲得在位置off的日志記錄的長度,然后將它增加到位置off中去。如果累計增加的位置大于或者等于參數len的值,那么就完成了對位置off的修正;否則,就要繼續將位置off移到再下一條日志記錄的位置。 回到函數logger_aio_write中,第37行到第56行代碼用來將參數iov中的日志記錄內容寫入到日志緩沖區結構體log中。由于一條日志記錄在日志緩沖區中是由一個日志記錄結構體和一個有效負載組成的,因此,函數logger_aio_write就分兩步將它們寫入到日志緩沖區中。 函數前面已經為即將要寫入的日志記錄準備好了一個日志記錄結構體header,因此,第37行就調用函數do_write_log將它的內容寫入到日志緩沖區結構體log中。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ /* * do_write_log - writes 'len' bytes from 'buf' to 'log' * * The caller needs to hold log->mutex. */ static void do_write_log(struct logger_log *log, const void *buf, size_t count) { size_t len; len = min(count, log->size - log->w_off); memcpy(log->buffer + log->w_off, buf, len); if (count != len) memcpy(log->buffer, buf + len, count - len); log->w_off = logger_offset(log->w_off + count); } ~~~ 由于一個日志記錄結構體的內容可能會被分別寫在日志緩沖區的尾部和頭部,因此,函數do_write_log就分兩次來寫入它的內容。第10行計算寫入到日志緩沖區尾部的內容的長度,接著第11行就直接將對應的日志記錄結構體的內容拷貝到日志緩沖區中。第13行判斷前面是否已經將日志記錄結構體的內容全部寫入到日志緩沖區中了。如果不是,第14行就會將剩余的內容寫入到日志緩沖區的頭部。 > 參數buf指向的內容即為要寫入的日志記錄結構體的內容,它位于內核空間中,因此,第11行和第14行將它的內容寫入到日志緩沖區中時,直接調用函數memcpy來拷貝就可以了。將日志記錄結構體的內容寫入到日志緩沖區中之后,第16行就要更新它的成員變量w_off的值,因為它始終指向下一條日志記錄的寫入位置。 回到函數logger_aio_write中,第39行到第56行的while循環把參數iov的內容寫入到日志緩沖區結構體log中。參數iov里面所保存的內容對應于要寫入的日志記錄的有效負載,它們是從用戶空間傳進來的,因此,函數logger_aio_write不能直接調用函數memcpy將它們拷貝到日志緩沖區結構體log中,而是調用函數do_write_log_from_user來執行拷貝操作。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ /* * do_write_log_user - writes 'len' bytes from the user-space buffer 'buf' to * the log 'log' * * The caller needs to hold log->mutex. * * Returns 'count' on success, negative error code on failure. */ static ssize_t do_write_log_from_user(struct logger_log *log, const void __user *buf, size_t count) { size_t len; len = min(count, log->size - log->w_off); if (len && copy_from_user(log->buffer + log->w_off, buf, len)) return -EFAULT; if (count != len) if (copy_from_user(log->buffer, buf + len, count - len)) return -EFAULT; log->w_off = logger_offset(log->w_off + count); return count; } ~~~ 與日志記錄結構體的寫入過程類似,日志記錄的有效負載也有可能會被分別寫入到日志緩沖區的尾部和頭部,因此,函數do_write_log_from_user就分兩次來寫入它的內容。第14行計算寫入到日志緩沖區尾部的內容的長度,接著第15行就調用函數copy_from_user將對應的日志記錄的有效負載拷貝到日志緩沖區中。第18行判斷前面是否已經將日志記錄的有效負載全部寫入到日志緩沖區了。如果不是,第19行就會將剩余的內容寫入到日志緩沖區的頭部。 > 參數buf指向的內容是保存在用戶空間中的,因此,第15行和第19行將它的內容寫入到日志緩沖區中時,需要調用函數copy_from_user來執行拷貝操作。將日志記錄的有效負載寫入到日志緩沖區中之后,接下來第22行就要更新它的成員變量w_off的值,因為它始終指向下一條日志記錄的寫入位置。 在前面的4.2.4小節中,我們在分析日志記錄的讀取過程時提到,如果日志緩沖區當前沒有新的日志記錄可讀,那么日志讀取進程就會進入到日志緩沖區的等待隊列wq中去睡眠等寫入新的日志記錄。現在既然已經往日志緩沖區中寫入新的日志記錄了,函數logger_aio_write在第61行就會調用函數wake_up_interruptible來喚醒那些睡眠在日志緩沖區的等待隊列wq中的進程,目的是通知它們有新的日志記錄可讀了。
                  <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>

                              哎呀哎呀视频在线观看