1. 程式人生 > >Asynchronous function calls for boot performance

Asynchronous function calls for boot performance

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);
	}