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