前沿拓展:
切换用户
1、第一进入系统设置,第二在“ 用户账户 ”中点击“ 登录本地账户 ”;2、接着为显示你的账户信息,不需要管,点右
第一是蓝色的部分,线程1在运行过程中,通过系统调用进程到内核状态,此时发生系统阻塞,需要调度,内核态此时保持用户态的现场到内核栈中,第二通过调度子系统调度到线程2中运行,此时发生线程控制块的切换,从TCB1切换到TCB2切换到线程2的TCB时候,TCB中存放了内核栈的指针,此时运行在内核态,此时内核态运行一段收尾代码后,一般会通过iret指令,切换线程2的用户空间,执行用户空间的代码,就完成的用户栈的切换过程
所以对于内核级线程,分为用户态和内核态,例如process 1,用户进程中有线程A和线程B,它们共享进程的内存空间,分别有自己的用户栈,用于存放自己的调用过程,同时在内核空间,有属于自己的PCB,但是对于每一个进程有一个内核栈
进程切换的时机
对于一个进程由哪些部分组成呢?主要包括用户空间和内核空间,如下图所示:
用户空间的进程地址空间一般由代码段、数据段、堆、栈组成,由task_struct的VMA维护,同时所有的内存空间都是存放在该进程的页表中,CPU中的reg也是由页表机制来管理内核空间进程地址空间维护了一个进程的控制块PCB task_struct,主要是内核栈和用户栈信息thread_info,这两个用户维护进程的上下文切换中有大用途
这个在linux进程管理章节中已经有详细介绍,要想进行进程的切换,那么OS必须第一获得控制权,其主要在以下情况下得到控制权
trap: 进程主动的切换,主要是通过执行一个system callException: 被动的切换,执行了一个意外的**作,例如常见的page faultInterrupt: 硬件设备请求OS服务 ,比如time中断,IO中断进程切换
基于内核栈实现进程切换的基本思路:
1, 当进程由用户态进入内核态时,主要是通过系统调用或者中断,会引起堆栈切换,用户信息会被压入到内核栈中,包括此时的用户的栈指针,PC和程序状态保存在内核栈中
2, 当进入到内核后,此时由于某些原因,由于该进程需要读取磁盘或者网络等信息,变成阻塞状态,或者时间片用完,此时需要让出CPU,重新引起调度时,**作系统会找到一个新的进程的PCB,并完成新进程PCB的切换
3, 当完成新进程的切换时,内核也完成了内核栈的切换,那么当中断返回时,执行IRET,弹出的就是新进程的EIP,从而跳转到新进程的用户指令进行执行。
这个切换的核心就是构建出内核栈的样子,要在适当的地方压入栈,适当的地方返回地址,并根据内核栈的样子,编写相应的汇编代码,完成内核堆栈的入栈和出站**作,以便保证顺利完成进程切换。
4.1 中断入口
**作系统负责进程的调度和切换,所以进程的切换一定是内核中发生,而用户程序是运行在内核态,所以就需要使用系统调用进入到内核态。主要的伪代码如下:
push ds;
mov ds, 内核段号
system_call 4.2 中断处理
用户态进入内核态,要发生堆栈的切换,系统调用的核心指令对于X86来说是指令int 0x80,这个系统调用中断。 当执行int 0x80 这条语句时由用户态进入内核态时,CPU会自动按照***SS、ESP、EFLAGS、CS、EIP***的顺序,将这几个寄存器的值压入到内核栈中,由于执行int 0x80时还未进入内核,所以压入内核栈的这五个寄存器的值是用户态时的值,其中***EIP*为int 0x80的下一条语句 "=a" (__res),这条语句的含义是将eax所代表的寄存器的值放入到_res变量中。所以当应用程序在内核中返回时,会继续执行 “=a” (__res) 这条语句。**这个过程完成了进程切换中的第一步,通过在内核栈中压入用户栈的ss、esp建立了用户栈和内核栈的联系,形象点说,即在用户栈和内核栈之间拉了一条线,形成了一套栈。
在system_call中执行完相应的系统调用sys_call_xx后,又将函数的返回值eax压栈。若引起调度,则跳转执行reschedule。否则则执行ret_from_sys_call。
在执行schedule前将ret_from_sys_call压栈,因为schedule是c函数,所以在c函数末尾的},相当于ret指令,将会弹出ret_from_sys_call作为返回地址,跳转到ret_from_sys_call执行。 小编综合来说,在系统调用结束后,将要中断返回前,内核栈主要是SS:SP指向用户栈,EFLAGS标志寄存器,返回地址EIP,还有一些其他的other Registers:EAX,EBX等,如下图所示
4.3 找到当前进程的PCB和新进程的PCB
当前进程的PCB 当前进程的PCB是用一个全局变量current指向的*(在sched.c中定义)* ,所以current即指向当前进程的PCB,pnext就指向下个进程的PCB。 在schedule()*函数中,当调用函数*switch_to(pent, _LDT(next))*时,会依次将返回地址**}***、参数2 ***_LDT(next)***、参数1 *pnext**压栈。当执行*switch_to*的返回指令ret时,就回弹出schedule()函数的}执行*schedule()*函数的返回指令
4.4 switch_to
对于schedule中switch_to,表示要取出表示下一个进程的PCB参数,并与当前的current做一个比较,如果是当前的current,则什么也不做;如果不等于当前的curret,则开始进程切换,以次完成PCB的切换,内核栈的切换等
在schedule.c中定义struct tss_struct *tss=&(init_task.task.tss)这样一个全局变量,即0号进程的tss,所有进程都共用这个tss,任务切换时不再发生变化。 虽然所有进程共用一个tss,但不同进程的内核栈是不同的,所以在每次进程切换时,需要更新tss中esp0的值,让它指向新的进程的内核栈,并且要指向新的进程的内核栈的栈底,即要保证此时的内核栈是个空栈,帧指针和栈指针都指向内核栈的栈底。
4.5 中断出口
PC的切换对于被切换出去的进程,当再次被调度的时,根据切换出去的进程的内核栈的样子,switch_to的最后一句指令ret会弹出switch_to后面的指令,作为返回地址继续执行,将弹出ret_from_sys_call作为返回地址,在ret_from_sys_call中继续进行一些处理,最后执行iret指令,进行终端返回,将弹出原来用户进程被中断的地方作为返回地址,继续被中断处执行。
5. 小编综合来说
对于进程切换不同于我们熟知的“模式切换”,模式切换,CPU还是在同一进程中运行systemcall或者中断上下文;而进程切换是CPU转向另外一个进程执行,进程切换改变当前的进程空间,其主要的工作如下:
保持当前进程的硬件上下文(PC/SP和通用寄存器等),对于linux系统而言,其硬件上下文大部分都保存在struct thread_struct thread中,但通用寄存器等都保存在内核栈中
修改当前进程的PCB,比如将其状态由运行态修改为就绪或者等待态,并将该进程PCB加入到相关队列中
调度另外一个进程,修改被调度进程的PCB,并将其状态修改为运行
将“当前进程"的管理数据改为调度进程的存储数据,如页表,TLB,同时恢复新进程的硬件上下文,让PC执行新进程的代码
拓展知识:
切换用户
桌面状态快捷键Alt+F4 选择切换用户
台式机(AMD平台)性能如何优化
¥2.99
电脑调修-专家1对1远程在线服务
¥38
路由器的选购、设置与进阶玩法
¥39
一看就会的RAID实用教程
¥29.9
小白必看的硬盘知识
¥9.9
查
看
更
多
官方服务
官方网站
切换用户
启动Windows 10时第一看到的是登录屏幕,此外,如果你已经登录,则可以按键盘上的Windows + L锁定Windows 10。
第二单击“锁定屏幕”以显示登录屏幕。默认情况下,Windows 10会加载用于登录的最新用户帐户,可用用户帐户列表显示在屏幕的左下角。
如果要切换用户,请在此列表中单击要使用的帐户,第二输入登录详细信息。默认情况下,Windows 10会要求输入该用户登录时使用的最新信息:密码、PIN或图片密码。
如果需要更改登录方法,请单击“登录选项”,第二按要使用的方法,之后,输入必要的信息以登录。
原创文章,作者:九贤生活小编,如若转载,请注明出处:http://www.wangguangwei.com/60578.html