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

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                日志設備的初始化過程是在Logger日志驅動程序的入口函數logger_init中進行的。在分析這個函數之前,我們首先介紹三個結構體變量log_main、log_events和log_radio,它們的類型均為struct logger_log,分別用來保存main、events和radio三種類型的日志記錄,如下所示。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ /* * Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than * LONG_MAX minus LOGGER_ENTRY_MAX_LEN. */ #define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \ static unsigned char _buf_ ## VAR[SIZE]; \ static struct logger_log VAR = { \ .buffer = _buf_ ## VAR, \ .misc = { \ .minor = MISC_DYNAMIC_MINOR, \ .name = NAME, \ .fops = &logger_fops, \ .parent = NULL, \ }, \ .wq = __WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \ .readers = LIST_HEAD_INIT(VAR .readers), \ .mutex = __MUTEX_INITIALIZER(VAR .mutex), \ .w_off = 0, \ .head = 0, \ .size = SIZE, \ }; DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024) DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024) DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024) ~~~ 結構體變量log_main、log_events和log_radio都是通過宏DEFINE_LOGGER_DEVICE來定義的,需要傳入的三個參數分別為變量名、設備文件路徑,以及要分配的日志緩沖區的大小。前面提到,Logger日志系統將日志記錄劃分為四種類型。從理論上說,每一種類型的日志記錄都應該對應有一個日志緩沖區,即在Logger日志驅動程序中對應有一個logger_log結構體,但是在目前的Logger日志驅動程序實現中,只定義了三個日志緩沖區,其中,類型為system和main的日志記錄保存在同一個日志緩沖區log_main中,而類型為events和radio的日志記錄分別保存在日志緩沖區log_events和log_radio中。 從宏DEFINE_LOGGER_DEVICE的定義可以看出,每一種類型的日志緩沖區都是將各自的日志記錄保存在一個靜態分配的unsigned char數組中,數組的大小由參數SIZE決定,其中,類型為main和radio的日志緩沖區的大小為64K,而類型為events的日志緩沖區的大小為256K。 每一個日志緩沖區都對應有一個misc類型的日志設備,以便運行在用戶空間的程序可以訪問它們。每一個日志設備都對應有一個文件名,它是由參數NAME指定的。從結構體變量log_main、log_events和log_radio的定義可以看出,類型為main、radio和events的日志緩沖區對應的日志設備文件分別為LOGGER_LOG_MAIN、LOGGER_LOG_RADIO和LOGGER_LOG_EVENTS。 **kernel/goldfish/drivers/staging/android/logger.h** ~~~ #define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ #define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */ #define LOGGER_LOG_MAIN "log_main" /* everything else */ ~~~ Logger日志驅動程序初始化完成之后,我們就可以在/dev/log目錄下看到三個日志設備文件main、events和radio。這三個日志設備對應的文件操作函數表均為logger_fops,它的定義如下所示。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ static struct file_operations logger_fops = { .owner = THIS_MODULE, .read = logger_read, .aio_write = logger_aio_write, .poll = logger_poll, .unlocked_ioctl = logger_ioctl, .compat_ioctl = logger_ioctl, .open = logger_open, .release = logger_release, }; ~~~ 文件操作函數表logger_fops指定的日志設備文件操作函數比較多,但是我們只關注日志設備打開、讀取和寫入函數open、read和aio_write的定義,它們分別被設置為logger_open、logger_read和logger_aio_write函數。 每一個硬件設備都有自己的主設備號和從設備號。由于日志設備的類型為misc,并且同一類型的設備都具有相同的主設備號,因此,在定義這些日志設備時,就不需要指定它們的主設備號了,等到注冊這些日志設備時,再統一指定。從宏DEFINE_LOGGER_DEVICE的定義可以看出,這些日志設備的從設備號被設置為MISC_DYNAMIC_MINOR,表示由系統動態分配,它的定義如下所示。 **kernel/goldfish/drivers/staging/android/logger.h** ~~~ #define MISC_DYNAMIC_MINOR 255 ~~~ 一般來說,我們在開發驅動程序時,都不應該去靜態指定設備的從設備號,因為靜態指定的從設備號會比較容易發生沖突,而動態分配的從設備號能夠保證唯一性。 結構體變量log_main、log_events和log_radio的其余成員變量的初始化過程都比較簡單,這里就不詳細介紹了。例如,它們的成員變量wq、reader和mutex分別使用宏__WAIT_QUEUE_HEAD_INITIALIZER、LIST_HEAD_INIT和__MUTEX_INITIALIZER來初始化,因為它們的類型分別為等待隊列、隊列和互斥量。 我們就從函數logger_init開始,分析日志設備的初始化過程。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ static int __init logger_init(void) { int ret; ret = init_log(&log_main); if (unlikely(ret)) goto out; ret = init_log(&log_events); if (unlikely(ret)) goto out; ret = init_log(&log_radio); if (unlikely(ret)) goto out; out: return ret; } ~~~ 日志設備的初始化過程實際上就是將三個日志設備注冊到系統中,這是分別通過調用函數init_log來實現的。 **kernel/goldfish/drivers/staging/android/logger.c** ~~~ static int __init init_log(struct logger_log *log) { int ret; ret = misc_register(&log->misc); if (unlikely(ret)) { printk(KERN_ERR "logger: failed to register misc " "device for log '%s'!\n", log->misc.name); return ret; } printk(KERN_INFO "logger: created %luK log '%s'\n", (unsigned long) log->size >> 10, log->misc.name); return 0; } ~~~ 在init_log函數中,主要是通過調用misc_register函數將相應的日志設備注冊到系統中。 **kernel/goldfish/drivers/char/misc.c** ~~~ int misc_register(struct miscdevice * misc) { struct miscdevice *c; dev_t dev; int err = 0; INIT_LIST_HEAD(&misc->list); mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { mutex_unlock(&misc_mtx); return -EBUSY; } } if (misc->minor == MISC_DYNAMIC_MINOR) { int i = DYNAMIC_MINORS; while (--i >= 0) if ( (misc_minors[i >> 3] & (1 << (i&7))) == 0) break; if (i<0) { mutex_unlock(&misc_mtx); return -EBUSY; } misc->minor = i; } if (misc->minor < DYNAMIC_MINORS) misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); dev = MKDEV(MISC_MAJOR, misc->minor); misc->this_device = device_create(misc_class, misc->parent, dev, NULL, "%s", misc->name); if (IS_ERR(misc->this_device)) { err = PTR_ERR(misc->this_device); goto out; } /* * Add it to the front, so that later devices can "override" * earlier defaults */ list_add(&misc->list, &misc_list); out: mutex_unlock(&misc_mtx); return err; } ~~~ 系統中所有的misc設備都保存在一個misc_list列表中。函數第10行到第15行檢查所要注冊的misc設備的從設備號是否已經被注冊。如果是的話,注冊就失敗了,因為同一類型設備的從設備號是不能相同的。由于Logger日志驅動程序已經指定它所要注冊的日志設備的從設備號是動態分配的,即指定為MISC_DYNAMIC_MINOR,因此,這一步檢查就通過了。 函數第17行到第27行為所要注冊的日志設備分配從設備號。系統可分配的misc從設備號一共有64個,即從0到63。這些從設備號的使用情況記錄在數組misc_minors中,它的定義如下所示。 **kernel/goldfish/drivers/char/misc.c** ~~~ #define DYNAMIC_MINORS 64 /* like dynamic majors */ static unsigned char misc_minors[DYNAMIC_MINORS / 8]; ~~~ 數組misc_minors的類型為unsigned char,因此,每一個元素可以管理8個從設備號,64個從設備號就需要8個元素,即數組misc_minors的大小為8。如果某一個從設備號已經被分配了,那么它在數組misc_minors中所對應的位就等于1,否則就等于0。如何在數組misc_minors中找到從設備號i所對應的位呢?首先找到它對應的數組元素位置,即i >> 3,然后取出從設備號i的低三位,即i & 7,那么從設備號i在數組misc_minors中對應的位便是第i >> 3個元素的第i & 7位了。因此,第20行只要檢查這一位是否等于0,就可以知道從設備號i是否已經被分配了。如果沒有被分配,那么第26行就將它分配給當前正在注冊的日志設備,接著第30行在數組misc_minors中記錄該從設備號已經被分配。 函數第31行使用misc主設備號MISC_MAJOR和前面得到的從設備號來創建一個設備號對象dev,接著第33行以它為參數調用函數device_create將日志設備misc注冊到系統中。MISC_MAJOR是一個宏,它的定義如下所示。 **kernel/goldfish/include/linux/major.h** ~~~ #define MISC_MAJOR 10 ~~~ 日志設備注冊成功之后,函數第44行就將它添加到misc設備列表misc_list中,表示日志設備注冊成功了。 第33行調用device_create函數注冊日志設備時,最后一個參數用來指定日志設備的名稱,即它在設備系統目錄/dev中對應的文件名稱。從前面的調用過程可以知道,我們要注冊的三個日志設備的名稱分別為“log_main”、“log_events”和“log_radio”,因此,應當在設備上的/dev目錄中看到log_main、log_events和log_radio三個文件。然而,在本章的開頭提到,這三個日志設備對應的文件分別為/dev/log/main、/dev/log/events和/dev/log/radio,這是為什么呢? 在前面的2.3.4小節中提到,Android系統使用一種uevent機制來管理系統的設備文件。當Logger日志驅動程序注冊一個日志設備時,內核就會發出一個uevent事件,這個uevent最終由init進程中的handle_device_event函數來處理,它的實現如下所示。 **system/core/init/devices.c** ~~~ static void handle_device_event(struct uevent *uevent) { char devpath[96]; int devpath_ready = 0; char *base, *name; char **links = NULL; int block; int i; ...... name = strrchr(uevent->path, '/'); ...... name++; ...... if(!strncmp(uevent->subsystem, "block", 5)) { ...... } else { ...... if (!strncmp(uevent->subsystem, "usb", 3)) { ...... } else if (!strncmp(uevent->subsystem, "graphics", 8)) { ...... } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) { ...... } else if (!strncmp(uevent->subsystem, "adsp", 4)) { ...... } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) { ...... } else if(!strncmp(uevent->subsystem, "input", 5)) { ...... } else if(!strncmp(uevent->subsystem, "mtd", 3)) { ...... } else if(!strncmp(uevent->subsystem, "sound", 5)) { ...... } else if(!strncmp(uevent->subsystem, "misc", 4) && !strncmp(name, "log_", 4)) { base = "/dev/log/"; mkdir(base, 0755); name += 4; } else ...... } if (!devpath_ready) snprintf(devpath, sizeof(devpath), "%s%s", base, name); if(!strcmp(uevent->action, "add")) { make_device(devpath, uevent->path, block, uevent->major, uevent->minor); if (links) { for (i = 0; links[i]; i++) make_link(devpath, links[i]); } } ...... } ~~~ 函數handle_device_event如果發現新注冊的設備類型為misc,并且設備名稱是以“log_”開頭的,它便會在/dev目錄中創建一個log目錄,接著將設備名稱的前四個字符去掉,即去掉前面的“log_”子字符串,最后就使用新的設備名稱在/dev/log目錄下創建一個設備文件。因此,我們就不會在設備上的/dev目錄中看到log_main、log_events和log_radio三個設備文件,而是在/dev/log目錄中看到main、events和radio三個設備文件。
                  <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>

                              哎呀哎呀视频在线观看