参考文章:
Linux系统内核空间与用户空间通信的实现及分析:
进程上下文VS中断上下文:
内核态与用户态最大的区别就是特权级别,运行在用户态的程序不能直接访问操作系统内核的数据结构和程序。
当我们在系统中执行一个程序时,它大部分时间都是运行在用户态的,当它需要操作系统的帮助去完成一些它没有权力和能力去完成的任务时,它就会切换到内核态。比如()一开始是运行在用户态的进程中,当它调用fork()并最终触发()的执行时,它就切换到内核态。
从用户态切换到内核态有三种方式:
1. 系统调用(主动)
用户态进程通过系统调用来请求使用操作系统提供的服务程序来完成自己的工作
2. 异常(被动)
当CPU在执行一个运行在用户态的程序时,发生了一些未知的异常,这些异常会触发当前运行的进程切换到处理这个异常的内核相关程序,进而切换回内核态,比如缺页异常。
3.外围设备中断()
当外围设备完成用户请求的操作后,就会向 CPU 发出相应的中断信号,此时 CPU 会暂停执行下一条要执行的指令,转而执行中断信号对应的处理程序。如果之前执行的指令是用户态的程序,那么这个转换过程自然就涉及到从用户态到内核态的切换。
CPU始终处于以下3个状态:
内核态:进程上下文(内核代表运行在内核空间的进程)
内核态:中断上下文(硬中断,软中断,内核代表硬件运行在内核空间)
用户模式
上下文:上下文只是一个环境
进程的上下文可以分为三部分:用户级上下文,寄存器上下文,系统级上下文。
用户级上下文:主体、数据、用户堆栈和共享内存
内存上下文:通用寄存器、程序寄存器(IP)、处理器状态寄存器()、堆栈指针(ESP)
系统级上下文:进程控制块、内存管理信息(pgd、pte)、内核堆栈
进程上下文:进程执行时,所有CPU寄存器的值、进程状态、堆栈内容等。当内核切换到其他进程时,需要保存当前进程的所有状态,也就是保存当前进程上下文,以便进程执行到这里时,能恢复当前状态,继续执行。
中断上下文:硬件传递的参数以及内核需要保存的其他环境(主要是当时被中断的进程环境)
在进程上下文中运行的内核代码可以被抢占,但中断上下文会运行到完成,不会被抢占。
因此内核对中断上下文的工作进行了限制,不允许进行如下操作:
1、进入睡眠状态或者主动让出CPU;(中断上下文不属于任何进程,一旦进入睡眠就无法被唤醒,所以又叫原子上下文)
2. 占用互斥锁;为了保护中断句柄的临界区资源,不允许使用。如果无法获取信号量,代码会休眠并进入上述情况。如果必须使用锁,请使用
3. 执行耗时任务;中断处理应尽可能快。占用过多的 CPU 时间将严重影响系统功能。如果需要执行耗时任务,应由中断处理的下半部分来处理。
4.访问用户空间虚拟内存;由于中断上下文运行在内核空间,所以无法访问用户空间虚拟地址
5. 中断处理例程不应设置为;(可并行或递归调用的例程)
6、被更高级别的IRQ中断;将中断处理例程设置为快速处理例程,相当于告诉CPU,在这个例程运行时,禁止所有的CPU中断请求,但这会导致其他中断响应延迟,性能下降。
Linux内核态与用户态通信的方法:
1. 流程上下文:
进程上下文环境中运行的代码可以采用阻塞方式,利用消息队列、UNIX域套接字等实现内核态与用户态的通信,但这种方式效率较低。
Linux内核提供了()和()来实现内核态和用户态之间的数据拷贝,但是这两个函数会引起阻塞,所以不能在中断上下文中使用。
这两个函数一般用在系统调用函数中,工作原理如下:
2.中断上下文环境:
中断上下文与用户态进程无关,正在运行的进程不能被阻塞。
2.1 使用通用的进程间通信方法
中断环境与内核线程通过自旋锁进行同步,内核线程运行在进程上下文中,内核线程可以使用或者消息队列获取用户空间数据,然后通过临界区将数据传递给中断进程,如下:
2.2 使用套接字
.4以及之后的版本在中断进程与用户态的通信上,也使用了IP队列工具,但是IP队列的使用有局限性,不能在各种中断进程中随意使用。
扫一扫在手机端查看
-
Tags : linux能否查看处于用户态还是内核态
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。