##《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”学习笔记 ##
源码组成:mypcb.h mymain.c myinterrupt.c
- mypcb.h
#define MAX_TASK_NUM 4
#define KERNEL_STACK_SIZE 1024*8
struct Thread {
unsigned long ip;
unsigned long sp;
};
typedef struct PCB{
int pid;
volatile long state;
char stack[KERNEL_STACK_SIZE];
struct Thread thread;
unsigned long task_entry;
struct PCB *next;
}tPCB;
void my_schedule(void);
2.mymain.c
void __init my_start_kernel(void)
{
int pid = 0;
int i;
task[pid].pid = pid;
task[pid].state = 0;
task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;
task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
task[pid].next = &task[pid];
for(i=1;i<MAX_TASK_NUM;i++)
{
memcpy(&task[i],&task[0],sizeof(tPCB));
task[i].pid = i;
task[i].state = -1;
task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-1];
task[i].next = task[i-1].next;
task[i-1].next = &task[i];
}
pid = 0;
my_current_task = &task[pid];
asm volatile(
"movl %1,%%esp\n\t"
"pushl %1\n\t"
"pushl %0\n\t"
"ret\n\t"
"popl %%ebp\n\t"
:
: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)
);
}
void my_process(void)
{
int i = 0;
while(1)
{
i++;
if(i%10000000 == 0)
{
printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);
if(my_need_sched == 1)
{
my_need_sched = 0;
my_schedule();
}
printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);
}
}
}
3.myinterrupt.c
void my_schedule(void)
{
tPCB * next;
tPCB * prev;
if(my_current_task == NULL
|| my_current_task->next == NULL)
{
return;
}
printk(KERN_NOTICE ">>>my_schedule<<<\n");
next = my_current_task->next;
prev = my_current_task;
if(next->state == 0)
{
asm volatile(
"pushl %%ebp\n\t"
"movl %%esp,%0\n\t"
"movl %2,%%esp\n\t"
"movl $1f,%1\n\t"
"pushl %3\n\t"
"ret\n\t"
"1:\t"
"popl %%ebp\n\t"
: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
: "m" (next->thread.sp),"m" (next->thread.ip)
);
my_current_task = next;
printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);
}
else
{
next->state = 0;
my_current_task = next;
printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);
asm volatile(
"pushl %%ebp\n\t"
"movl %%esp,%0\n\t"
"movl %2,%%esp\n\t"
"movl %2,%%ebp\n\t"
"movl $1f,%1\n\t"
"pushl %3\n\t"
"ret\n\t"
: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
: "m" (next->thread.sp),"m" (next->thread.ip)
);
}
return;
}
4.小结
进程切换过程与函数调用堆栈基本类似
- 保存当前进程的堆栈环境(esp,eip,ebp),首先将当前进程的ebp压栈,并将esp和eip保存在当前进程的结构体中。
- 构建下一进程的堆栈环境。然后下一条进程的thread.sp读出,赋给esp;thread.ip读出赋给eip。若下一条进程是新的进程,处于未运行状态,则新进程堆栈为空,esp与ebp指向同一地址,这种情况与函数调用堆栈更加类似。若下一条进程处于运行态,那么ebp与当前进程的ebp指向同一地址。
- 恢复堆栈环境,为下下个进程做准备。恢复eip,即把执行完成的进程的thread.ip(下一进程的指令地址)赋给eip,上例中所有进程的thread.ip设为my_process。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)