smp: smp_call_function_many_async

Run an asynchronous function on a many cpus.
smp_call_function_many_async_begin
for_each_csd
        smp_call_function_many_async
smp_call_function_many_async_end

Signed-off-by: yongduan <yongduan@tencent.com>
This commit is contained in:
yongduan 2020-12-01 10:34:56 +08:00
parent 9c2652e3d8
commit 3853775fa6
2 changed files with 56 additions and 4 deletions

View File

@ -94,6 +94,16 @@ extern int __cpu_up(unsigned int cpunum, struct task_struct *tidle);
*/
extern void smp_cpus_done(unsigned int max_cpus);
#define smp_call_function_many_async_begin(cpumask) \
preempt_disable();
int smp_call_function_many_async(int cpu, call_single_data_t *csd, struct cpumask *mask);
#define smp_call_function_many_async_end(cpumask) \
arch_send_call_function_ipi_mask(cpumask); \
preempt_enable();
/*
* Call a function on all other processors
*/
@ -136,6 +146,10 @@ static inline int get_boot_cpu_id(void)
static inline void smp_send_stop(void) { }
#define smp_call_function_many_async_begin(cpumask)
#define smp_call_function_many_async(cpu, csd, mask) smp_call_function_single_async(cpu, csd)
#define smp_call_function_many_async_end(cpumask)
/*
* These macros fold the SMP functionality into a single CPU system
*/

View File

@ -139,7 +139,7 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(call_single_data_t, csd_data);
* ->func, ->info, and ->flags set.
*/
static int generic_exec_single(int cpu, call_single_data_t *csd,
smp_call_func_t func, void *info)
smp_call_func_t func, void *info, struct cpumask *mask)
{
if (cpu == smp_processor_id()) {
unsigned long flags;
@ -176,7 +176,8 @@ static int generic_exec_single(int cpu, call_single_data_t *csd,
* equipped to do the right thing...
*/
if (llist_add(&csd->llist, &per_cpu(call_single_queue, cpu)))
arch_send_call_function_single_ipi(cpu);
if (!mask) arch_send_call_function_single_ipi(cpu);
else __cpumask_set_cpu(cpu, mask);
return 0;
}
@ -296,7 +297,7 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
csd_lock(csd);
}
err = generic_exec_single(cpu, csd, func, info);
err = generic_exec_single(cpu, csd, func, info, NULL);
if (wait)
csd_lock_wait(csd);
@ -336,13 +337,50 @@ int smp_call_function_single_async(int cpu, call_single_data_t *csd)
csd->flags = CSD_FLAG_LOCK;
smp_wmb();
err = generic_exec_single(cpu, csd, csd->func, csd->info);
err = generic_exec_single(cpu, csd, csd->func, csd->info, NULL);
preempt_enable();
return err;
}
EXPORT_SYMBOL_GPL(smp_call_function_single_async);
/**
* smp_call_function_many_async(): Run an asynchronous function on a
* specific CPU.
* @cpu: The CPU to run on.
* @csd: Pre-allocated and setup data structure
*
* Like smp_call_function_single(), but the call is asynchonous and
* can thus be done from contexts with disabled interrupts.
*
* The caller passes his own pre-allocated data structure
* (ie: embedded in an object) and is responsible for synchronizing it
* such that the IPIs performed on the @csd are strictly serialized.
*
* NOTE: Be careful, there is unfortunately no current debugging facility to
* validate the correctness of this serialization.
*/
int smp_call_function_many_async(int cpu, call_single_data_t *csd, struct cpumask *mask)
{
int err = 0;
preempt_disable();
/* We could deadlock if we have to wait here with interrupts disabled! */
if (WARN_ON_ONCE(csd->flags & CSD_FLAG_LOCK))
csd_lock_wait(csd);
csd->flags = CSD_FLAG_LOCK;
smp_wmb();
err = generic_exec_single(cpu, csd, csd->func, csd->info, mask);
preempt_enable();
return err;
}
EXPORT_SYMBOL_GPL(smp_call_function_many_async);
/*
* smp_call_function_any - Run a function on any of the given cpus
* @mask: The mask of cpus it can run on.