进程与线程

进程 和 线程都是动态概念

进程 = 资源(包括寄存器值,PCB,内存映射表)+指令序列

线程 = 指令序列

线程的资源是共享的

进程间的资源是独立隔离的,内存映射表不同,占用物理内存地址是分割的

线程的切换只是切换PC,切换了指令序列

进程的切换不仅切换PC,还包括切换资源,即切换内存映射表

用户级线程:调用yield函数,自己主动让出CPU,0.11内核看不见,内核只能看见所属进程而看不见用户线程,所以一个用户级线程需要等待,内核会切到别的进程上,不会切到该进程下的其他用户级线程!!

内核级线程:内核能看见内核级线程,一个线程需要等待,内核会切到所属进程下的其他内核级线程。

内核级线程:

只有内核级线程才能发挥多核性能,因为多核级线程共用一套MMU,即内存映射表,但是有多个CPU,可以一个CPU执行一个内核级线程

进程无法发挥多核性能,因为进程切换都得切MMU,即切换内存映射表,一个内核级线程的切换需要两套栈:用户栈+内核栈

系统调用中断过程:

1,INT中断自动压栈的有下一条指令,以及用户级线程SS:SP,就是下面五个参数

2,_system_call把寄存器保护压栈是压到内核栈中,需要手动压栈

3,系统调用,(有可能是_sys_fork,其实就是根据标号找到系统调用),结束之后继续执行,要执行reschedule,先push $ret_from_sys_call,让其在_schedule之后返回到ret_from_sys_call,_schedule为c函数,结束右括号会把ret_from_sys_call pop出来,返回到这里执行,即执行ret_from_sys_call;

4,在ret_from_sys_call中pop出_system_call是保存的寄存器内容,然后中断返回!!

5,中断返回是在最后,中断返回会把SS:SP以及用户态的下一条指令POP出来,即把5个寄存器pop出来!!!这样就会返回到用户栈,运行用户态的下一条指令!!!

代码:

reschedule:
    pushl $ret_from_sys_call
    jmp _schedule                              //如果用call就是先将下一条指令压栈,然后jmp,这样只能顺序往下走,但是用push+jmp则可以改变跳转地址!!

switch_to五段论

在“实地址模式”中,IRET 指令执行到中断程序或过程的远返回。在执行此操作的过程中,处理器从堆栈将返回指令指针、返回代码段选择器以及 EFLAGS 映像分别弹入 EIP、CS 以及 EFLAGS 寄存器,然后恢复执行中断的程序或过程。

这里要注意,中断出口这里已经经过了前面的switch_to,中断的iret已经不是原来的中断返回了,是切换后的新中断的执行返回!!这样返回以后就来到了引发该新中断的用户态代码来执行。

内核级线程切换实例

fork函数经典调用

if (!fork())          //关键在于 INT 80 后面的指令 mov res, %eax;父进程和子进程都会执行这个代码,但是%eax的值不一样
{
     子进程
}
else
{
     父进程
}

fork创建子进程时,copy_process复制父进程相应资源,申请内存空间,创建内核栈,创建用户栈。

eip[0] 赋值为新的程序的开始执行内存地址(可执行程序ELF结构里有entry地址),实际是赋值给esp+28地址处。

eip[3] 赋值为新的程序的用户栈,实际是赋值给esp+40地址处。

汇编调用c函数

实际上是把参数都压到栈里,然后c程序就可以调用,用call来调用

但是要注意c语言 调用结束后,要把栈里的参数删除,即addl指令,吧指针改一下,忽略那些参数

实际上是

push 参数

push 返回值

jmp 调用地址

c函数右括号会生成ret指令,会返回到返回地址

cpu调度算法

周转时间:从开始申请执行任务,到执行任务完成

响应时间:从开始申请执行任务到开始执行任务

三种调度方法:

调度算法:考虑优先级,任务类型,响应时间,周转时间,调度算法要简单些,内耗低。

1,先来先服务 平均周转时间可能会很长

2,短作业优先(SJF) 周期时间短,但是响应时间长,适用于后台程序,如gcc的编译,快点把整个程序编译完

3,时间片轮转(RR) 响应时间可以得到保证,nT,n为任务个数,T为时间片长度,适用于前台程序,IO操作多的

4,优先级轮转 固定优先级,可能会造成程序一直没法执行下去,需要动态调整优先级

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) {
                        if ((*p)->alarm && (*p)->alarm < jiffies) {
                                        (*p)->signal |= (1<<(SIGALRM-1));
                                        (*p)->alarm = 0;
                                }
                        if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
                        (*p)->state==TASK_INTERRUPTIBLE)
                                {
                                        (*p)->state=TASK_RUNNING;
                                        /*可中断睡眠 => 就绪*/
                                        fprintk(3,"%d\tJ\t%d\n",(*p)->pid,jiffies);
                                }
                }

/* this is the scheduler proper: */

        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 = (*p)->counter, next = i;
                }
                //首先找到counter最大并且TASK_RUNNING的进程作为调度进程
                //counter 可以作为时间片和优先级的表达
                if (c) break;
                //如果所有进程的counter为0,则增加阻塞进程的counter
                for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
                        if (*p)
                                (*p)->counter = ((*p)->counter >> 1) +
                                                (*p)->priority;
        }
        /*编号为next的进程 运行*/
        if(current->pid != task[next] ->pid)
        {
                /*时间片到时程序 => 就绪*/
                if(current->state == TASK_RUNNING)
                        fprintk(3,"%d\tJ\t%d\n",current->pid,jiffies);
                fprintk(3,"%d\tR\t%d\n",task[next]->pid,jiffies);
        }
        switch_to(next);
}
void do_timer(long cpl)
{
        extern int beepcount;
        extern void sysbeepstop(void);

        if (beepcount)
                if (!--beepcount)
                        sysbeepstop();

        if (cpl)
                current->utime++;
        else
                current->stime++;

        if (next_timer) {
                next_timer->jiffies--;
                while (next_timer && next_timer->jiffies <= 0) {
                        void (*fn)(void);
    
                        fn = next_timer->fn;
                        next_timer->fn = NULL;
                        next_timer = next_timer->next;
                        (fn)();
                }   
        }   
        if (current_DOR & 0xf0)
                do_floppy_timer();
        //时间中断,减少counter,近似RR轮转算法,考虑到SJF短左右优先
        if ((--current->counter)>0) return;
        current->counter=0;
        if (!cpl) return;
        schedule();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值