Linux如何创建idle进程

关于idle进程

也就是pid=0的进程。它是内核完成初始化后所创建的第一个进程,在系统空闲时执行。它的代码很简单:

for(;;) pause();

强调一下,idle进程是用户态进程。那么问题来了,内核从启动到初始化过程总都处在内核态,那么内核是怎么创    建idle并且切换到用户态呢?

一种很直接简单的想法是,内核直接调用用户空间的代码实现内核态到用户态的转换,但是这是不可能的,因为规

不能这么做。那怎么办呢?这就是这篇文章要讲的问题。

进程相关的结构

进程是一个动态的概念,要管理进程首先我们需要将这个动态的概念用一些静态数据结构抽象化。这个结构就是经    常所说的task_struct。里面存放了保护模式下进程的信息(比如ldt和tss等)。关于保护模式相关知识请参考       《linux0.11内核完全注释》前几章。所以我们要创建idle,首先就要先准备好相应的task_struct。在linux0.11中
   是直接初始化的:

static union task_union init_task = {INIT_TASK,};

#define INIT_TASK \

/* state etc */ { 0,15,15, \

/* signals */ 0,{{},},0, \

/* ec,brk... */ 0,0,0,0,0,0, \

/* pid etc.. */ 0,-1,0,0,0, \

/* uid etc */ 0,0,0,0,0,0, \

/* alarm */ 0,0,0,0,0,0, \

/* math */ 0, \

/* fs info */ -1,0022,NULL,NULL,NULL,0, \

/* filp */ {NULL,}, \

{ \

{0,0}, \

/* ldt */ {0x9f,0xc0fa00}, \

{0x9f,0xc0f200}, \

}, \

/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\

0,0,0,0,0,0,0,0, \

0,0,0x17,0x17,0x17,0x17,0x17,0x17, \

_LDT(0),0x80000000, \

{} \

}, \

}

然后把idle任务的LDT和TSS放在全局描述符表GDT中:

set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));

set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));

内核态--->用户态

进程相关的信息准备好了,接下来就是状态的切换了。

直接调用显然是不能改变特权级的,但是我们知道,中断处理是可以在不同的特权级之间切换的。所以内核采用     了一种“模拟中断返回”的方式。

先看看CPU处理中断的时候是怎么做的:

其中上半部分着色的“原ss,原esp,原flags,原cs,原eip”,是指被中断的程序ss、esp、flags、cs、eip,    这些寄存器的入栈和出栈(由iret指令完成)都是由CPU自动完成,而且其他的寄存器出入栈全部由程序员自己处     理。提醒一下,这里的cs和eip是用在保护模式下的,所以cs是在GDT中寻址相应的代码段(idle的代码段和数据段已经在前一节里面准备好放在GDT中了。)

接下来看linux0.11是怎么模仿中断返回的:

#define move_to_user_mode() \//切换到用户态

__asm__ ("movl %%esp,%%eax\n\t" \

"pushl $0x17\n\t" \//压入原ss(指向idle的代码段,低两位代表cpl=3,代表用户
态)

"pushl %%eax\n\t" \//压入原esp

"pushfl\n\t" \//压入原flags

"pushl $0x0f\n\t" \                //压入原cs(指向idle的代码段,低两位代表cpl=3,代表用户态)

"pushl $1f\n\t" \//压入原eip,指向iret指令后面的代码

/*以上的入栈操作本来都应该在程序被中断是由CPU自动完成,这里是手动压入,制造被中断的假象。以便马        上调用iret,由CPU自动完成这些寄存器的出栈操作,完成内核态到用户态的切换*/

"iret\n" \
//中断返回,由CPU恢复先前压入的寄存器。

"1:\tmovl $0x17,%%eax\n\t" \

"movw %%ax,%%ds\n\t" \

"movw %%ax,%%es\n\t" \

"movw %%ax,%%fs\n\t" \

"movw %%ax,%%gs" \

:::"ax")

时间: 2024-11-09 04:27:09

Linux如何创建idle进程的相关文章

Linux内核的idle进程分析

1. idle是什么 简单的说idle是一个进程,其pid号为 0.其前身是系统创建的第一个进程.也是唯一一个没有通过fork()产生的进程. 在smp系统中,每一个处理器单元有独立的一个执行队列,而每一个执行队列上又有一个idle进程,即有多少处理器单元.就有多少idle进程. 系统的空暇时间,事实上就是指idle进程的"执行时间".既然是idle是进程.那我们来看看idle是怎样被创建,又详细做了哪些事情? 2. idle的创建 我们知道系统是从BIOS加电自检,载入MBR中的引导

Linux内核创建新进程的过程

作者:xujianguo  原创作品转载请注明出处,<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ——————————————————————————————————————————————————————-———— 实验目的:  使用gdb跟踪分析一个fork系统调用内核处理函数sys_clone ,验证您对Linux系统创建一个新进程的理解; 分析fork函数对应的内核处理过程sys_clone,理解创建

分析Linux内核创建一个新进程的过程【转】

转自:http://www.cnblogs.com/MarkWoo/p/4420588.html 前言说明 本篇为网易云课堂Linux内核分析课程的第六周作业,本次作业我们将具体来分析fork系统调用,来分析Linux内核创建新进程的过程 关键词:fork, 系统调用,进程 *运行环境:** Ubuntu 14.04 LTS x64 gcc 4.9.2 gdb 7.8 vim 7.4 with vundle 分析 分析方法说明 PCB包含了一个进程的重要运行信息,所以我们将围绕在创建一个新进程时

分析Linux内核创建一个新进程的过程

一.原理分析 1.进程的描述 进程控制块PCB——task_struct,为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息. struct task_struct{ volatile long state; //进程状态,-1表示不可执行,0表示可执行,大于1表示停止 void *stack; //内核堆栈 atomic_t usage; unsigned int flags; //进程标识符 unsigned int ptrace; …… } 2.进程的创

[linux]进程(三)——idle进程

9,linux进程切换 进程切换:基本概念:进程上下文:当一个进程在执行时,CPU的所有寄存器中的值.进程的状态以及堆栈中的内容被称为该进程的上下文.当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的上下文,运行于进程上下文的进程是可以被抢占的.硬件上下文:进程恢复执行前必须载入寄存器的一组数据称为硬件上下文linux内核在进程切换的时候是并不区分进程和线程的~因为切换是针对task,进程切换的时机:一般是在系统调用或者中断的时候,发生在内核态.进程切换过程:进程切换统

Linux下0号进程的前世(init_task进程)今生(idle进程)----Linux进程的管理与调度(五)

日期 内核版本 架构 作者 GitHub CSDN 2016-05-12 Linux-4.5 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的创建 前言 Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2) * idle进程由系统自动创建, 运行在内核态 idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_t

第六周分析Linux内核创建一个新进程的过程

潘恒 原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 task_struct结构: struct task_struct {   volatile long state;进程状态  void *stack; 堆栈  pid_t pid; 进程标识符  unsigned int rt_priority;实时优先级  unsigned int policy;调度策略  struct files

linux c学习笔记----进程创建(fork,wait,waitpid)

1.pid_t fork(); (1)当一个进程调用了fork 以后,系统会创建一个子进程.这个子进程和父进程不同的地方只有他的进程ID 和父进程ID,其他的都是一样.就象符进程克隆(clone)自己一样. (2)为了区分父进程和子进程,我们必须跟踪fork 的返回值. 当fork 掉用失败的时候(内存不足或者是用户的最大进程数已到)fork 返回-1,否则fork 的返回值有重要的作用.对于父进程fork 返回子进程的ID,而对于fork 子进程返回0.我 们就是根据这个返回值来区分父子进程的

ASP.ENT Core Linux 下 为 donet创建守护进程(转载)

原文地址:http://www.cnblogs.com/savorboard/p/dotnetcore-supervisor.html 前言 在上篇文章中介绍了如何在 Docker 容器中部署我们的 asp.net core 应用程序,本篇主要是怎么样为我们在 Linux 或者 macOs 中部署的 dotnet 程序创建一个守护进程,来保证我们的程序在异常或者是电脑重启的时候仍然能够正常访问. 如果你以后用准备使用 asp.net core来开发项目的话,程序并且部署到 Linux 上的话,那