目录
1.进程介绍
2.进程调度
2.1.进程状态
2.2.进程调度函数 ---schedule
2.3.进程切换函数 ---switch_to()
1.进程介绍
在进程模块里面,我们知道了进程就是一个task_struct的结构体,里面含有进程的各种信息。进程存放在进程数组task_struct的数组里面。
2.进程调度
在进程调度里面主要的两个函数:
//进程调度函数
void schedule(void);
//切换到下一个进程 这个功能使用宏定义完成的
        switch_to(next);
2.1.进程状态
运行态: 可以被运行
就绪态: 进程切换时,只能在就绪态里面挑选进程
可中断睡眠状态: 可以被信号打断,变成就绪态或者运行态
不可中断睡眠状态: 只能被wakeup所唤醒变成就绪态或者运行态
暂停状态: 收到SIGTOP,SIGTSTP,SIGTTIN
僵死状态: 进程停止运行,但是父进程没有回收, waitpid函数。
2.2.进程调度函数 ---schedule
1. 检查所有进程的定时器,然后唤醒某一些进程,将进程从可中断睡眠状态变为就绪态
2.循环task列表 根据counter大小决定进程切换
(1)如果找到最大值,而且不为0,直接返回,没有(2)了。
(2)如果都为0,进行时间片的重新分配,然后重新执行2步骤。
3.切换到下一个进程------switch_to函数
// 时间片分配
void schedule(void)
{
	int i,next,c;
	struct task_struct ** p;
/* check alarm, wake up any interruptible tasks that have got a signal */
	for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
		if (*p) {//alarm是用来设置警告,比如jiffies有1000个可能其中一些需要警告那么就用alarm来实现
			if ((*p)->alarm && (*p)->alarm < jiffies) {
					(*p)->signal |= (1<<(SIGALRM-1));
					(*p)->alarm = 0;
				}
				//~(_BLOCKABLE & (*p)->blocked  
				//&&(*p)->state==TASK_INTERRUPTIBLE
				//用来排除非阻塞信号
				//如果该进程为可中断睡眠状态 则如果该进程有非屏蔽信号出现就将该进程的状态设置为running
			if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
			(*p)->state==TASK_INTERRUPTIBLE)
				(*p)->state=TASK_RUNNING;
		}
/* this is the scheduler proper: */
	// 以下思路,循环task列表 根据counter大小决定进程切换
	while (1) {
		c = -1;
		next = 0;
		i = NR_TASKS;
		p = &task[NR_TASKS];
		while (--i) {
			if (!*--p)
				continue;//进程为空就继续循环
			if ((*p)->state == TASK_RUNNING && (*p)->counter > c)//找出c最大的task
				c = (*p)->counter, next = i;
		}
		if (c) break;//如果c找到了,就终结循环,说明找到了
		//进行时间片的重新分配
		for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
			if (*p)//这里很关键,在低版本内核中,是进行优先级时间片轮转分配,这里搞清楚了优先级和时间片的关系
			//counter = counter/2 + priority
				(*p)->counter = ((*p)->counter >> 1) +
						(*p)->priority;
	}
	//切换到下一个进程 这个功能使用宏定义完成的
	switch_to(next);
}2.3.进程切换函数 ---switch_to()
1.先判断是否为当前进程,如果是,不用切换
2.切换进程:
(1)将进程赋值给全局变量current这个变量,就可以完成进程切换
(2)将进程的上下文(TSS和当前堆栈中的信息)切换
// 进程切换是用汇编宏定义实现的
//1. 将需要切换的进程赋值给当前进程的指针
//2. 将进程的上下文(TSS和当前堆栈中的信息)切换
#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__("cmpl %%ecx,_current\n\t" \
	"je 1f\n\t" \
	"movw %%dx,%1\n\t" \
	"xchgl %%ecx,_current\n\t" \
	"ljmp %0\n\t" \
	"cmpl %%ecx,_last_task_used_math\n\t" \
	"jne 1f\n\t" \
	"clts\n" \
	"1:" \
	::"m" (*&__tmp.a),"m" (*&__tmp.b), \
	"d" (_TSS(n)),"c" ((long) task[n])); \
}3.sleep_on函数
当某个进程想访问CPU资源,但是CPU资源被占用访问不到,就会休眠。休眠是以链表形成的,类似递归的情况。-----sleep等待队列

// 当某个进程想访问CPU资源,但是CPU资源被占用访问不到,就会休眠
void sleep_on(struct task_struct **p)
{
	struct task_struct *tmp;
	if (!p)//如果传进来的是空的 就返回
		return;
	if (current == &(init_task.task))//当前进程是0号 
		panic("task[0] trying to sleep");//就打印并且返回
	tmp = *p;
	*p = current;//这两步相当于 给休眠链表添加了一个新node
	// 其实核心就是把state置为TASK_UNINTERRUPTIBLE
	current->state = TASK_UNINTERRUPTIBLE;
	schedule();
	if (tmp)
		tmp->state=0;
}


















