start_kernel——setup_nr_cpu_ids

kernel/smp.c

/* An arch may set nr_cpu_ids earlier if needed, so this would be redundant */
void __init setup_nr_cpu_ids(void)
{
    nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
}

include/linux/cpumask.h

#if NR_CPUS == 1
#define nr_cpu_ids      1
#else
extern int nr_cpu_ids;
#endif

NR_CPUS不是1,所以编译extern int nr_cpu_ids;,我在源代码中没有找到nr_cpu_ids的定义,资料上说nr_cpu_ids全局变量被声明为__read_mostly属性。

nr_cpu_ids保存的是所有可处于联机状态的CPU总数。

nr_cpu_ids具有当前系统能具备的CPU数的信息,默认值为NR_CPUS值,NR_CPUS是编译时用户可设置的常量值。NR_CPUS并非当前系统内存在的CPU的数值,而是Linux内核能支持的最大CPU数的最大值。

UP(Uni-Processor)中是1,32位SMP中具有2~32的值,64位内核中具有2~64位的值。

kernel/cpu.c

#ifdef CONFIG_INIT_ALL_POSSIBLE
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly
    = CPU_BITS_ALL;
#else
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
#endif

没有定义CONFIG_INIT_ALL_POSSIBLE,所以编译

static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;

DECLARE_BITMAP我们在http://blog.csdn.net/yin262/article/details/46774041已经分析过了,这句定义的最终结果是生车功能一个unsigned long 类型的数组,数组名为cpu_possible_bits,用位图来管理cpu个数,每一位对应一个cpu。

关于利用位图来管理cpu变量,还有以下:

include/linux/cpumask.h

/*
 * The following particular system cpumasks and operations manage
 * possible, present, active and online cpus.
 *
 *     cpu_possible_mask- has bit ‘cpu‘ set iff cpu is populatable
 *     cpu_present_mask - has bit ‘cpu‘ set iff cpu is populated
 *     cpu_online_mask  - has bit ‘cpu‘ set iff cpu available to scheduler
 *     cpu_active_mask  - has bit ‘cpu‘ set iff cpu available to migration
 *
 *  If !CONFIG_HOTPLUG_CPU, present == possible, and active == online.
 *
 *  The cpu_possible_mask is fixed at boot time, as the set of CPU id‘s
 *  that it is possible might ever be plugged in at anytime during the
 *  life of that system boot.  The cpu_present_mask is dynamic(*),
 *  representing which CPUs are currently plugged in.  And
 *  cpu_online_mask is the dynamic subset of cpu_present_mask,
 *  indicating those CPUs available for scheduling.
 *
 *  If HOTPLUG is enabled, then cpu_possible_mask is forced to have
 *  all NR_CPUS bits set, otherwise it is just the set of CPUs that
 *  ACPI reports present at boot.
 *
 *  If HOTPLUG is enabled, then cpu_present_mask varies dynamically,
 *  depending on what ACPI reports as currently plugged in, otherwise
 *  cpu_present_mask is just a copy of cpu_possible_mask.
 *
 *  (*) Well, cpu_present_mask is dynamic in the hotplug case.  If not
 *      hotplug, it‘s a copy of cpu_possible_mask, hence fixed at boot.
 *
 * Subtleties:
 * 1) UP arch‘s (NR_CPUS == 1, CONFIG_SMP not defined) hardcode
 *    assumption that their single CPU is online.  The UP
 *    cpu_{online,possible,present}_masks are placebos.  Changing them
 *    will have no useful affect on the following num_*_cpus()
 *    and cpu_*() macros in the UP case.  This ugliness is a UP
 *    optimization - don‘t waste any instructions or memory references
 *    asking if you‘re online or how many CPUs there are if there is
 *    only one CPU.
 */

extern const struct cpumask *const cpu_possible_mask;
extern const struct cpumask *const cpu_online_mask;
extern const struct cpumask *const cpu_present_mask;
extern const struct cpumask *const cpu_active_mask;

cpu_possible_mask:系统内可安装的最多CPU的位图

cpu_online_mask:系统内安装的CPU中,正在使用的CPU的位图

cpu_present_mask:系统内安装的CPU的位图

cpu_active_mask:处于联机状态且可以动的(migration)的CPU的位图

以上都是结构体指针类型,由相应的bitmap转化而来:

kernel/cpu.c

#ifdef CONFIG_INIT_ALL_POSSIBLE
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly
    = CPU_BITS_ALL;
#else
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
#endif
const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
EXPORT_SYMBOL(cpu_possible_mask);

static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits);
EXPORT_SYMBOL(cpu_online_mask);

static DECLARE_BITMAP(cpu_present_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_present_mask = to_cpumask(cpu_present_bits);
EXPORT_SYMBOL(cpu_present_mask);

static DECLARE_BITMAP(cpu_active_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_active_mask = to_cpumask(cpu_active_bits);
EXPORT_SYMBOL(cpu_active_mask);

转换的过程,在之前的文章里也分析了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-13 22:17:25

start_kernel——setup_nr_cpu_ids的相关文章

arm linux 启动之二:start_kernel到创建1号进程

本文介绍arm linux启动的第二部分,C语言编写,主要讲述start_kernel到1号进程的创建.主要讲述大概过程,以后再对子函数进行讲解. 一.start_kernel start_kernel位于init/main.c,主要完成linux一些子系统的初始化. 1)smp_setup_processor_id() 单CPU位为空. 2)lock_kernel() 锁CPU,linux是支持抢占的,多CPU时调用这个函数防止其他CPU抢占.3)tick_init() 时间相关初始化4)bo

gdb跟踪调试内核从start_kernel到init进程启动

顾涛原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 如果我写的不好或者有误的地方请留言 题目自拟,内容围绕Linux内核的启动过程,即从start_kernel到init进程启动: 博客中需要使用实验截图 博客内容中需要仔细分析start_kernel函数的执行过程 总结部分需要阐明自己对“Linux系统启动过程”的理解,尤其是idle进程.1号进程是怎么来的. 实验报告: 在实验楼里跑了

(转)start_kernel 代码分析

head-common.S---具体做了哪些动作---跳转到init/main.c ---b start_kernel//关于start_kernel的强文深入理解linux内核,第八章main.casmlinkage void __init start_kernel(void){char * command_line;extern struct kernel_param __start___param[], __stop___param[];//来设置smp process id,当然目前看到

Linux学习之源码2:start_kernel流程

一.X86的流程可以参考http://www.kerneltravel.net/kernel-book/第十三章%20启动系统/13.5.htm 二.arm的流程,在http://www.cnblogs.com/gangsaleisi/archive/2013/01/09/2851734.html基础上进行分析. 并且是在3.9.7版本上进行分析的,差别不是太大. 1.lockdep_init():lockdep哈希表初始化,lockdep是linux内核的一个调试模块,用来检查内核互斥机制尤其

理解start_kernel中函数语句的作用

asmlinkage void __init start_kernel(void) { char * command_line; extern const struct kernel_param __start___param[], __stop___param[]; /*这两个变量为地址指针,指向内核启动参数处理相关结构体段在内存中的位置(虚拟地址). 声明传入参数的外部参数对于ARM平台,位于 include\asm-generic\vmlinux.lds.h*/ /* * Need to

(作业3)Linux内核的启动过程(从start_kernel到init进程启动)

作业题目: 详细分析从start_kernel到init进程启动的过程并结合实验截图撰写一篇署名博客,并在博客文章中注明“真实姓名(与最后申请证书的姓名务必一致) + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”,博客内容的具体要求如下: 题目自拟,内容围绕Linux内核的启动过程,即从start_kernel到init进程启动: 博客中需要使用实验截图 博客内容中需要仔细分析

Linux内核分析-使用gdb跟踪调试内核从start_kernel到init进程启动

姓名:江军 ID:fuchen1994 实验日期:2016.3.13 实验指导 使用实验楼的虚拟机打开shell cd LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img 内核启动完成后进入menu程序(<软件工程C编码实践篇>的课程项目),支持三个命令help.version和quit,您也可以添加更多的命令,对选修过<软件工程C编码实践篇>的童鞋应该是a piece of

linux start_kernel相关进程的思考

退休的贵族进程 0号进程 所有进程的祖先叫做进程0 在系统初始化阶段由start_kernel()函数从无到有手工创建的一个内核线程 进程0最后的初始化工作创建init内核线程,此后运行cpu_idle,成为idle进程 控制权的接力棒从bios-->bootloader-->idle,某种程度上说,就是完成子系统初始化使命后,就退居二线了. 0号进程一直处于皇宫"内核态",没有出过宫"到用户态",所谓贵族终身. 0号进程的代码概要图 进入loop的堆栈

第3阶段——内核启动分析之start_kernel初始化函数(5)

内核启动分析之start_kernel初始化函数(init/main.c) stext函数启动内核后,就开始进入start_kernel初始化各个函数, 下面只是浅尝辄止的描述一下函数的功能,很多函数真正理解需要对linux相关体系有很深的了解后才能明白 代码如下: asmlinkage void __init start_kernel(void) { char * command_line; extern struct kernel_param __start___param[], __sto