Linux 0号进程的建立


0号进程在内核中是一个比较特殊的进程,因为它是静态创建的,不是通过do_fork()创建的。所以从0号进程出发有助于理解一个进程的创建需要为它准备好哪些条件。

进程的内核表示

进程可以简单理解为Linux操作系统中的一个运行实体,在内核中用数据结构task_struct表示,这个结构体表示了进程运行时所需要的所有信息,所以这是内核中较为复杂的一个结构体,基于我们此篇文章所需要表达的知识,我们重点介绍下该结构体的成员thread_info,这个成员所分配的内存空间与该进程的栈连在一起,通常是8Kb,并且在thread_info结构体中有个成员task指向进程描述符。所以它们的关系如下图所以:
在这里插入图片描述

进程0的创建

对于32位的x86平台,进程0的描述符定义在arch/i386/kernel/init_task.c中,变量名为init_task,在这个文件中同时也定义了进程描述符所指向的下表,也能从代码中看到对它们的初始化。

  • init_thread_union - 包含堆栈和thread_info的区域
  • init_mm - 内存管理相关
  • init_fs
  • init_files
  • init_signals
  • init_sighand

对init_task的初始化如下所示:

/**
 * 初始化进程0的任务描述符。
 */
#define INIT_TASK(tsk)	\
{									\
	.state		= 0,						\
	.thread_info	= &init_thread_info,				\
	.usage		= ATOMIC_INIT(2),				\
	.flags		= 0,						\
	.lock_depth	= -1,						\
	.prio		= MAX_PRIO-20,					\
	.static_prio	= MAX_PRIO-20,					\
	.policy		= SCHED_NORMAL,					\
	.cpus_allowed	= CPU_MASK_ALL,					\
	.mm		= NULL,						\
	.active_mm	= &init_mm,					\
	.run_list	= LIST_HEAD_INIT(tsk.run_list),			\
	.time_slice	= HZ,						\
	.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
	.ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children),		\
	.ptrace_list	= LIST_HEAD_INIT(tsk.ptrace_list),		\
	.real_parent	= &tsk,						\
	.parent		= &tsk,						\
	.children	= LIST_HEAD_INIT(tsk.children),			\
	.sibling	= LIST_HEAD_INIT(tsk.sibling),			\
	.group_leader	= &tsk,						\
	.real_timer	= {						\
		.function	= it_real_fn				\
	},								\
	.group_info	= &init_groups,					\
	.cap_effective	= CAP_INIT_EFF_SET,				\
	.cap_inheritable = CAP_INIT_INH_SET,				\
	.cap_permitted	= CAP_FULL_SET,					\
	.keep_capabilities = 0,						\
	.user		= INIT_USER,					\
	.comm		= "swapper",					\
	.thread		= INIT_THREAD,					\
	.fs		= &init_fs,					\
	.files		= &init_files,					\
	.signal		= &init_signals,				\
	.sighand	= &init_sighand,				\
	.pending	= {						\
		.list = LIST_HEAD_INIT(tsk.pending.list),		\
		.signal = {{0}}},					\
	.blocked	= {{0}},					\
	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
	.journal_info	= NULL,						\
}

进程0的运行

对于0号进程的软件抽象实体已经通过静态的方式定义好了,那如何让这个实体运行呢?回想一下,进程的软件抽象是由描述进程相关的成员及执行时的栈空间组成,对于进程描述符描述的是进程的相关静态属性,而栈空间是进程执行时动态空间。因为在进程0初次执行时,对于进程的调度程序其实还没初始化,所以进程0的首次运行肯定不是通过内核中的调度程序加载的,而是简单的通过将栈寄存器(esp)指向进程0的栈底位置,从而表示了在接下来的程序执行是在进程0的栈空间中,也就是进程0在执行了。
进程0的栈起始位置(arch/i386/kernel/head.S):

ENTRY(stack_start)
	.long init_thread_union+THREAD_SIZE
	.long __BOOT_DS

使能完分页机制后,将进程0的栈起始位置赋值给esp寄存器,至此,后面的程序就是在进程0的上下文执行了:

/*
 * Enable paging
 */
	movl $swapper_pg_dir-__PAGE_OFFSET,%eax
	movl %eax,%cr3		/* set the page table pointer.. */
	movl %cr0,%eax
	orl $0x80000000,%eax
	movl %eax,%cr0		/* ..and set paging (PG) bit */
	ljmp $__BOOT_CS,$1f	/* Clear prefetch and normalize %eip */
1:
	/* Set up the stack pointer */
	/* 意味着后面的程序在进程0的上下文开始执行了 */
	lss stack_start,%esp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值