码迷,mamicode.com
首页 > 其他好文 > 详细

进程切换

时间:2014-05-11 14:26:57      阅读:316      评论:0      收藏:0      [点我收藏+]

标签:内核

进程切换

为了控制进程的执行,内核必须有能力挂起在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换,任务切换或上下文切换。

尽管每个进程可以拥有属于自己的地址空间,但所有进程必须共享CPU寄存器。因此,在恢复一个进程执行前,内核必须确保每个寄存器装入了挂起进程时的值。

进程恢复执行前必须装入寄存器的一组称为硬件上下文(hardware context)。硬件上下文是进程可执行上下文的一个子集,因为可执行上下文包含进程执行时需要的所有信息。在linux中,进程硬件上下文的一部分放在TSS段,而剩余的部分存放在内核态信息堆栈中。

进程切换只发生在内核态。在执行进程切换之前,用户态进程使用的所有寄存器内容都已保存在内核态堆栈上。

任务状态段

80x86体系结构包括了一个特殊的段类型,叫任务状态段(Task State Segment,TSS)来存放硬件上下文。尽管Linux并不使用硬件上下文切换,但是强制它为系统中每个不同的CPU创建一个TSS。主要有两个理由:

1、当80x86的一个CPU从用户态切换到内核态时,它就从TSS中获取内核态堆栈的地址。

2、当用户态进程试图通过in或者out指令访问一个I/O端口是,CPU需要访问存放在TSS中的I/O许可权位图(permission bitmap)以检查进程是否有访问端口的权利。

thread字段

在每次进程切换时,被替换进程的硬件上下文必须保存在别处。不能像Intel原始设计那样把它保存在TSS中,因为Linux为每个处理器而不是为每个进程使用TSS。

因此,每个进程描述符包含一个类型为thread_struct的thread字段,只要进程切换出去,内核就把其他硬件上下文保存在这个结构中。

struct thread_struct {
/* cached TLS descriptors. */
	struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
	unsigned long	esp0;
	unsigned long	eip;
	unsigned long	esp;
	unsigned long	fs;
	unsigned long	gs;
/* Hardware debugging registers */
	unsigned long	debugreg[8];  /* %%db0-7 debug registers */
/* fault info */
	unsigned long	cr2, trap_no, error_code;
/* floating point info */
	union i387_union	i387;
/* virtual 86 mode info */
	struct vm86_struct __user * vm86_info;
	unsigned long		screen_bitmap;
	unsigned long		v86flags, v86mask, saved_esp0;
	unsigned int		saved_fs, saved_gs;
/* IO permissions */
	unsigned long	*io_bitmap_ptr;
};

执行进程切换

进程切换可能只发生在精心定义的点:schedule()函数。

从本质上说,每个进程切换由两步组成:

1、切换页全局目录以安装一个新的地址空间;

2、切换内核态堆栈和硬件上下文,因为硬件上下文提供了内核执行新进程所需要的所有信息,包含CPU寄存器。

IA-32架构处理器在程序应用中提供16个基本程序指令寄存器,可以被分为以下几组:

General-purpose registers. These eight registers are available for storing operands and pointers.

  ? EAX — Accumulator for operands and results data
  ? EBX — Pointer to data in the DS segment
  ? ECX — Counter for string and loop operations
  ? EDX — I/O pointer
  ? ESI — Pointer to data in the segment pointed to by the DS register; source pointer for string operations
  ? EDI — Pointer to data (or destination) in the segment pointed to by the ES register; destination pointer for
          string operations
  ? ESP — Stack pointer (in the SS segment)
  ? EBP — Pointer to data on the stack (in the SS segment)
? Segment registers. These registers hold up to six segment selectors.
? EFLAGS (program status and control) register. The EFLAGS register report on the status of the program
          being executed and allows limited (application-program level) control of the processor.
? EIP (instruction pointer) register. The EIP register contains a 32-bit pointer to the next instruction to be
       executed.

linux-2.6.11.1/include/asm-i386/system.h

#define switch_to(prev,next,last) do {						unsigned long esi,edi;							asm volatile("pushfl\n\t"							     "pushl %%ebp\n\t"							     "movl %%esp,%0\n\t"	/* save ESP */				     "movl %5,%%esp\n\t"	/* restore ESP */			     "movl $1f,%1\n\t"		/* save EIP */				     "pushl %6\n\t"		/* restore EIP */			     "jmp __switch_to\n"						     "1:\t"								     "popl %%ebp\n\t"							     "popfl"								     :"=m" (prev->thread.esp),"=m" (prev->thread.eip),			      "=a" (last),"=S" (esi),"=D" (edi)					     :"m" (next->thread.esp),"m" (next->thread.eip),			      "2" (prev), "d" (next));				} while (0)

linux嵌入式汇编参考

PUSHF/PUSHFD Push EFLAGS onto stack
POPF/POPFD Pop EFLAGS from stack
AT&T汇编中,命令中可以指定操作范围,如pushb是将一个byte压栈,而pushw就是将一个word压栈,同样pushl就是压栈long(也就是双字)

这个程序做了以下工作:

1、在eax和edx寄存器中分别保存prev和next的值

2、把eflags和esp寄存器的内容保存在prev内核栈中。

3、把esp的内容保存到prev->thread.esp中以使该字段指向prev内核栈的栈顶

4、把next->thread.esp装入esp。此时内核开始在next的内核栈上操作,因此这条指令实际上完成了从prev到next的切换。由于进程描述符的地址和    内核栈的地址紧挨着,所以改变内核栈意味着改变当前进程。

5、把标记为1的地址存入prev->thread.eip。当被替换进程重新恢复执行时,进程执行被标记为1的那条指令。

6、宏把next->thread.eip的值压入next的内核栈。

7、跳到__switch_to()函数

8、这里被替换进程再次获得CPU;它执行一些指令恢复eflags和ebp寄存器的内容指令

9、拷贝eax寄存器的内容到第三个参数last标识的内存区域

eax寄存器指向刚被替换的进程的描述符

进程切换,布布扣,bubuko.com

进程切换

标签:内核

原文地址:http://blog.csdn.net/wangpeihuixyz/article/details/25474311

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!