on_cpu_each()がasyncなのかというところのめもです。
on_each_cpu()を見ると三番目の引数waitがなんか怪しいのが分かりますね。
これが使われているのはsmp_call_function()なのでこれを見る必要があると。
547 /* 548 * Call a function on all processors. May be used during early boot while 549 * early_boot_irqs_disabled is set. Use local_irq_save/restore() instead 550 * of local_irq_disable/enable(). 551 */ 552 int on_each_cpu(void (*func) (void *info), void *info, int wait) 553 { 554 unsigned long flags; 555 int ret = 0; 556 557 preempt_disable(); 558 ret = smp_call_function(func, info, wait); 559 local_irq_save(flags); 560 func(info); 561 local_irq_restore(flags); 562 preempt_enable(); 563 return ret; 564 } 565 EXPORT_SYMBOL(on_each_cpu);
smp_call_function()には関数の冒頭でwait引数についての説明があり、この時点で答えが分かる気が。
447 * If @wait is true, then returns once @func has returned; otherwise 448 * it returns just before the target cpu calls @func. 449 * 450 * You must not call this function with disabled interrupts or from a 451 * hardware interrupt handler or from a bottom half handler. 452 */ 453 int smp_call_function(smp_call_func_t func, void *info, int wait) 454 { 455 preempt_disable(); 456 smp_call_function_many(cpu_online_mask, func, info, wait); 457 preempt_enable(); 458 459 return 0; 460 }
ついでなのでsmp_call_function_many()はこんな感じに。
先生、waitは今までintだったのにここではboolっすか!
343 344 /** 345 * smp_call_function_many(): Run a function on a set of other CPUs. 346 * @mask: The set of cpus to run on (only runs on online subset). 347 * @func: The function to run. This must be fast and non-blocking. 348 * @info: An arbitrary pointer to pass to the function. 349 * @wait: If true, wait (atomically) until function has completed 350 * on other CPUs. 351 * 352 * If @wait is true, then returns once @func has returned. 353 * 354 * You must not call this function with disabled interrupts or from a 355 * hardware interrupt handler or from a bottom half handler. Preemption 356 * must be disabled when calling this function. 357 */ 358 void smp_call_function_many(const struct cpumask *mask, 359 smp_call_func_t func, void *info, bool wait)
この関数の中でfuncの呼び出しとreturnについての部分はこの辺。
409 for_each_cpu(cpu, cfd->cpumask) { 410 struct call_single_data *csd = per_cpu_ptr(cfd->csd, cpu); 411 struct call_single_queue *dst = 412 &per_cpu(call_single_queue, cpu); 413 unsigned long flags; 414 415 csd_lock(csd); 416 csd->func = func; 417 csd->info = info; 418 419 raw_spin_lock_irqsave(&dst->lock, flags); 420 list_add_tail(&csd->list, &dst->list); 421 raw_spin_unlock_irqrestore(&dst->lock, flags); 422 } 423 424 /* Send a message to all CPUs in the map */ 425 arch_send_call_function_ipi_mask(cfd->cpumask_ipi); 426 427 if (wait) { 428 for_each_cpu(cpu, cfd->cpumask) { 429 struct call_single_data *csd; 430 431 csd = per_cpu_ptr(cfd->csd, cpu); 432 csd_lock_wait(csd); 433 } 434 }
409~422行目でデータを設定してarch_send_call_function_ipi_mask()でcpuに対してIPIで各cpuでfuncが実行されるようになると
で、waitが0の場合は実行を待たないのでそのまま終了というコメント通りになるのですね。
処理が終わるのを待つ場合はcsd_lock_wait()が処理が終わったかどうかの判断材料っぽい。
csd_lock_wait()はというとcall_single_data構造体のflagsメンバのCSD_FLAG_LOCKビットが立っている場合はcpu_relax()で解除されるのを待つという実装。
99 /* 100 * csd_lock/csd_unlock used to serialize access to per-cpu csd resources 101 * 102 * For non-synchronous ipi calls the csd can still be in use by the 103 * previous function call. For multi-cpu calls its even more interesting 104 * as we'll have to ensure no other cpu is observing our csd. 105 */ 106 static void csd_lock_wait(struct call_single_data *csd) 107 { 108 while (csd->flags & CSD_FLAG_LOCK) 109 cpu_relax(); 110 }
ということで、on_cpu_each()についてまとめると
- on_cpu_each()が同期/非同期で動くかどうかというのはwaitの値次第
- intとboolが混ざってるのはアレなので直したいという気持ちも微妙にある
- jailhouseのコードはwaitに0を渡して自分待っているけど、別にwaitに1を渡しても良いのではという説