Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3003666
  • 博文数量: 674
  • 博客积分: 17881
  • 博客等级: 上将
  • 技术积分: 4849
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-17 10:15
文章分类

全部博文(674)

文章存档

2013年(34)

2012年(146)

2011年(197)

2010年(297)

分类: LINUX

2010-04-26 20:49:23

asmlinkage void __init start_kernel(void)
{
......
/* Do the rest non-__init'ed, we're now alive */


rest_init();
}

现在我们来看一下rest_init()函数,它也在文件init/main.c中,它的前面几行是:

static void noinline __init_refok rest_init(void) __releases(kernel_lock)
{
int pid;
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

static int __init kernel_init(void * unused)
{
lock_kernel();
/*
* init can run on any cpu.
*/
set_cpus_allowed_ptr(current, CPU_MASK_ALL_PTR);
/*
* Tell the world that we're going to be the grim
* reaper of innocent orphaned children.
* We don't want people to have to make incorrect
* assumptions about where in the task array this
* can be found.
*/
init_pid_ns.child_reaper = current;
cad_pid = task_pid(current);
smp_prepare_cpus(setup_max_cpus);
do_pre_smp_initcalls();
smp_init();
sched_init_smp();
cpuset_init_smp();
do_basic_setup();
/*
* check if there is an early userspace init. If yes, let it do all
* the work
*/
if (!ramdisk_execute_command)
ramdisk_execute_command = "/init";
if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
ramdisk_execute_command = NULL;
prepare_namespace();
}
/*
* Ok, we have completed the initial bootup, and
* we're essentially up and running. Get rid of the
* initmem segments and start the user-mode stuff..
*/
init_post();
return 0;
}

static inline int set_cpus_allowed_ptr(struct task_struct *p,
const cpumask_t *new_mask)
{
if (!cpu_isset(0, *new_mask))
return -EINVAL;
return 0;
}

这函数其实就调用了cpu_isset宏,定义在文件"include/linux/cpumask.h中,如下:

#define cpu_isset(cpu, cpumask) test_bit((cpu), (cpumask).bits)

typedef struct { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;

接着尾随着DECLAR_BITMAP宏到文件include/linux/types.h中,定义如下:

#define DECLARE_BITMAP(name,bits) \
unsigned long name[BITS_TO_LONGS(bits)]

#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
DIV_ROUND_UP宏定义在文件include/linux/kernel.h中,BITS_PER_BYTE 宏定义在文件include/linux/bitops.h中,实现如下:

#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE 8

即当NR_CPUS为1~32时,cpumask_t类型为

struct {
unsigned long bits[1];
}

然后来看看在set_cpus_allowed_ptr(current, CPU_MASK_ALL_PTR);中的 CPU_MASK_ALL_PTR宏,定义在include/linux/cpumask.h中:

#define CPU_MASK_ALL_PTR (&CPU_MASK_ALL)

而CPU_MASK_ALL宏也定义在文件include/linux/cpumask.h中:

#define CPU_MASK_ALL \
(cpumask_t) { { \
[BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
} }

NR_CPUS宏定义在文件include/linux/threads.h中,实现如下:

#ifdef CONFIG_SMP
#define NR_CPUS CONFIG_NR_CPUS
#else
#define NR_CPUS 1
#endif

CPU_MASK_LAST_WORD宏定义在文件include/linux/cpumask.h中,实现如下:

#define CPU_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(NR_CPUS)
BITMAP_LAST_WORD_MASK(NR_CPUS)宏定义在文件include/linux/bitmap.h中,实现如下:

#define BITMAP_LAST_WORD_MASK(nbits) \
( \
((nbits) % BITS_PER_LONG) ? \
(1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL \
)
当NR_CPUS为1时,CPU_MASK_LAST_WORD为1
当NR_CPUS为2时,CPU_MASK_LAST_WORD为2
当NR_CPUS为n时,CPU_MASK_LAST_WORD为2的n-1次方

有点晕了,我们现在把参数带入,即set_cpus_allowed_ptr(current, CPU_MASK_ALL_PTR)
-->cpu_isset(0,CPU_MASK_ALL_PTR)-->test_bit(0,CPU_MASK_ALL_PTR.bits)

现在kernel_init中的set_cpus_allowed_ptr(current, CPU_MASK_ALL_PTR); 分析完了,我们接着往下看,首先 init_pid_ns.child_reaper = current; init_pid_ns定义在kernel/pid.c文件中

struct pid_namespace init_pid_ns = {
.kref = {
.refcount = ATOMIC_INIT(2),
},
.pidmap = {
[ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL }
},
.last_pid = 0,
.level = 0,
.child_reaper = &init_task,
};

include/linux/pid_namespace.h中,具体定义如下:
struct pid_namespace {
struct kref kref;
struct pidmap pidmap[PIDMAP_ENTRIES];
int last_pid;
struct task_struct *child_reaper;
struct kmem_cache *pid_cachep;
unsigned int level;
struct pid_namespace *parent;
#ifdef CONFIG_PROC_FS
struct vfsmount *proc_mnt;
#endif
};

即把当前进程设为接受其它孤儿进程的进程,然后取得该进程的进程ID,如:

cad_pid = task_pid(current);

然后调用 smp_prepare_cpus(setup_max_cpus);如果编译时没有指定CONFIG_SMP,它什么也不做,接着往下看,调用

do_pre_smp_initcalls()函数,它定义在init/main.c文件中,实现如下:

static void __init do_pre_smp_initcalls(void)
{
extern int spawn_ksoftirqd(void);
migration_init();
spawn_ksoftirqd();
if (!nosoftlockup)
spawn_softlockup_task();
}
其中migration_init()定义在文件include/linux/sched.h中,具体实现如下:
#ifdef CONFIG_SMP
void migration_init(void);
#else
static inline void migration_init(void)
{
}
#endif

好像什么也没有做,然后是调用spawn_ksoftirqd()函数,定义在文件kernel/softirq.c中,代码如下:

__init int spawn_ksoftirqd(void)
{
void *cpu = (void *)(long)smp_processor_id();
int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
BUG_ON(err == NOTIFY_BAD);
cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
register_cpu_notifier(&cpu_nfb);
return 0;
}

阅读(1835) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~