Asynchronous function calls for boot performance
阿新 • • 發佈:2018-11-23
Asynchronous function calls for boot performance 個人理解主要是通過函式非同步呼叫還減少啟動時間,即將沒有依賴且沒有嚴格序列 的程式可以非同步執行來減少啟動時間。 非同步函式呼叫的具體實現在kernel/async.c中。我們舉例說明async的用法. 這個例子是在drivers/acpi/battery.c中 static int __init acpi_battery_init(void) { if (acpi_disabled) return -ENODEV; #可見在入口函式中,通過async_schedule來讓acpi_battery_init_async 非同步呼叫以 #加快系統的啟動時間,從這裡可以知道acpi_battery_init_async和其他硬體沒有依賴,且 #沒有嚴格的序列關係.注意這裡會返回一個static async_cookie_t async_cookie;在模組的登出函式 #中需要呼叫acpi_battery_init_async。 async_cookie = async_schedule(acpi_battery_init_async, NULL); return 0; } static void __exit acpi_battery_exit(void) { # async_synchronize_cookie(async_cookie + 1); if (battery_driver_registered) { acpi_bus_unregister_driver(&acpi_battery_driver); battery_hook_exit(); } #ifdef CONFIG_ACPI_PROCFS_POWER if (acpi_battery_dir) acpi_unlock_battery_dir(acpi_battery_dir); #endif } #定義模組的入口函式 module_init(acpi_battery_init); module_exit(acpi_battery_exit); 所以async的用法就是這樣。 下來我們看看acpi_battery_init_async的具體實現 async_cookie_t async_schedule(async_func_t func, void *data) { #預設的domain是async_dfl_domain return __async_schedule(func, data, &async_dfl_domain); } static async_cookie_t __async_schedule(async_func_t func, void *data, struct async_domain *domain) { struct async_entry *entry; unsigned long flags; async_cookie_t newcookie; /* allow irq-off callers */ #註冊一個entry entry = kzalloc(sizeof(struct async_entry), GFP_ATOMIC); /* * If we're out of memory or if there's too much work * pending already, we execute synchronously. */ #非同步執行的函式執行的個數有限制,不能超過MAX_WORK,這個限制應該和memory有關 if (!entry || atomic_read(&entry_count) > MAX_WORK) { kfree(entry); spin_lock_irqsave(&async_lock, flags); newcookie = next_cookie++; spin_unlock_irqrestore(&async_lock, flags); /* low on memory.. run synchronously */ func(data, newcookie); return newcookie; } #初始化兩個列表 INIT_LIST_HEAD(&entry->domain_list); INIT_LIST_HEAD(&entry->global_list); #初始化一個workqueue,並設定回撥函式為async_run_entry_fn INIT_WORK(&entry->work, async_run_entry_fn); entry->func = func; entry->data = data; entry->domain = domain; spin_lock_irqsave(&async_lock, flags); /* allocate cookie and queue */ newcookie = entry->cookie = next_cookie++; #將新建的entry新增到全域性列表中 list_add_tail(&entry->domain_list, &domain->pending); if (domain->registered) list_add_tail(&entry->global_list, &async_global_pending); atomic_inc(&entry_count); spin_unlock_irqrestore(&async_lock, flags); /* mark that this task has queued an async job, used by module init */ current->flags |= PF_USED_ASYNC; #開始排程workqueue,這裡可以看明白async的精髓,以本例為例,也就是你呼叫module_init後你的函式不一定立刻運行了 /* schedule for execution */ queue_work(system_unbound_wq, &entry->work); return newcookie; } static void async_run_entry_fn(struct work_struct *work) { struct async_entry *entry = container_of(work, struct async_entry, work); unsigned long flags; ktime_t uninitialized_var(calltime), delta, rettime; /* 1) run (and print duration) */ if (initcall_debug && system_state < SYSTEM_RUNNING) { pr_debug("calling %lli_%pF @ %i\n", (long long)entry->cookie, entry->func, task_pid_nr(current)); calltime = ktime_get(); } #執行使用者呼叫__async_schedule時傳入的回撥函式 entry->func(entry->data, entry->cookie); }