SMP结构在MIPS中的体现

囧了哎,前面分析完x86的一堆代码,这会儿又得找到在内核源码中,有关mips架构和smp有关的代码

恩,一句话评论:mips的smp结构就是x86的smp的一种精简

依旧是kernel 3.5.4 ,主要在目录/arch/mips下

和MIPS有关的SMP数据结构和函数

xchg指令,CPU锁总线

spinlock_t数据结构

include/linux/spinlock_types.h, line 76

struct {
    u8 __padding[LOCK_PADSIZE];
    struct lockdep_map dep_map;
};

spin_trylock()spin_unlock()之间是需要保证互斥,同一时间中,只有一个CPU在里面执行的临界区。

内存路障Memory Barrier

高速缓存的使用可能会使实际的内存操作改变次序。从访问内存的角度看,CPU可能会有一些路基操作已经完成,但是物理上尚未实现。“内存路障”就是使得某些操作之前,把之前的物理操作完成,才能开始新的。函数mb(),rmb(),wmb()
arch/mips/include/asm/barrier.h, line 132

#define wmb()           fast_wmb()
#define rmb()           fast_rmb()
#define mb()            fast_mb()

知道当前进程在哪个cpu上运行

smp_processor_id(),include/linux/smp.h, line 218

# define smp_processor_id() debug_smp_processor_id()

smp_processor_id(),include/linux/smp.h, line 220

# define smp_processor_id() raw_smp_processor_id()

hard_smp_processor_id(),arch/mips/include/asm/netlogic/mips-extns.h, line 71

static inline int hard_smp_processor_id(void)
{
    return __read_32bit_c0_register($15, 1) & 0x3ff;
}

一CPU应系统中另一CPU的请求而进行一次进程调度

当一个CPU需要另一个CPU进行一次进程调度时,就可以通过调用一个函数smp_send_reschedule()向目标CPU发出一个RESCHEDULE_VECTOR中断请求。

smp_send_reschedule(),arch/mips/include/asm/smp.h, line 53

static inline void smp_send_reschedule(int cpu)
{
    extern struct plat_smp_ops *mp_ops;     /* private */ 
    mp_ops->send_ipi_single(cpu, SMP_RESCHEDULE_YOURSELF);
}

处理器间某种中断向量:CALL_FUNCTION_VECTOR

还有一个处理器间中断向量是CALL_FUNCTION_VECTOR,用来请求目标CPU执行一个指定的函数。
(x86才找到这个,mips没找到)发送者先设置好一个全局的call_data_struct数据结构,然后向目标发出请求。

该向量的中断服务程序是smp_call_function_interrupt()

arch/mips/kernel/smp.c, line 146

void __irq_entry smp_call_function_interrupt(void)
{
    irq_enter();
    generic_smp_call_function_single_interrupt();
    generic_smp_call_function_interrupt();
    irq_exit();
}

SMP结构中的进程调度

cpu会通过schedule()从系统的就绪队列中挑选了一个进程作为运行的下一个进程。

kernel/sched/core.c, line 3462

asmlinkage void __sched schedule(void)
{
     struct task_struct *tsk = current; 
     sched_submit_work(tsk);
     __schedule();
}
EXPORT_SYMBOL(schedule);

__schedule()中,区分了smp和单CPU。

SMP系统的引导

系统刚刚加电时或者reset后,系统中暂时只有一个处理器运行:“引导处理器”BP,其余暂停状态的是“应用处理器”AP。

BP完成自身初始化,进入保护模式,开启页式存储管理机制,完成内存的初始化,然后start_kernel()会调用smp_init()SMP结构初始化

init/main.c, line 322

static void __init smp_init(void)
{
    APIC_init_uniprocessor();   //其中内容很多
}
//2.6代码如下:
smp_boot_cpus();
smp_threads_read=1
smp_commence()

在某处注释发现:smp_boot_cpus()/smp_commence() is replaced by smp_prepare_cpus()/__cpu_up()/smp_cpus_done()

依次启动系统中的各个CPU。各自初始化后都停下来等待统一的“起跑”命令。smp_commence()

smp_prepare_boot_cpu,arch/mips/kernel/smp.c, line 189

/* preload SMP state for boot cpu */
void __devinit smp_prepare_boot_cpu(void)
{
    set_cpu_possible(0, true);
    set_cpu_online(0, true);
    cpu_set(0, cpu_callin_map);
}

smp_prepare_cpus,arch/mips/kernel/smp.c, line 178

void __init smp_prepare_cpus(unsigned int max_cpus)
{
    init_new_context(current, &init_mm);
    current_thread_info()->cpu = 0;
    mp_ops->prepare_cpus(max_cpus);
    set_cpu_sibling_map(0);
#ifndef CONFIG_HOTPLUG_CPU
    init_cpu_present(cpu_possible_mask);
#endif
}

__cpu_up,arch/mips/kernel/smp.c, line 197

int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
    mp_ops->boot_secondary(cpu, tidle); 
    /*


     * Trust is futile.  We should really have timeouts ...

     */
    while (!cpu_isset(cpu, cpu_callin_map))
            udelay(100);

    return 0;
}

smp_cpus_done,arch/mips/kernel/smp.c, line 171

void __init smp_cpus_done(unsigned int max_cpus)
{
    mp_ops->cpus_done();
    synchronise_count_master();
}

内核中的全局变量,max_cpus,表示系统中有多少个CPU。也可以指定。

arch/mips/kernel/smp-bmips.c, line 39

static int __maybe_unused max_cpus = 1;