linux异常控制小结

        这篇博客主要是为了说明程序异常中断的机理和在try catch的时候操作系统进程之间到底发生了什么,写这篇博客既是为了分享,也是为了总结这一阶段的学习。

        首先说明一下什么是异常,这里所说的异常时一种抽象的概念,异常是处理器控制流状态的一种改变,有四种,分别是中断,陷阱,故障,终止,一般来说,不用区分的这么细,这东西和我们写的程序有啥关系?当然有关系,当我们写的程序需要调用一些操作系统内核才能做的事情,比如读文件等,程序就得触发异常,让进程的执行从用户态切换到内核态。(操作系统内核是操作系统连接底层硬件和用户程序之间的桥梁。)内核态拥有一切权限,而用户态无法访问内核态内存地址,linux巧妙的用/proc文件系统,让用户可以不用切换到内核态就可以读取一些敏感信息,如cpu状态等。

        下面该进入正题了,我们自己的进程在跑的时候,就像一直没有中断一样,但是你想,cpu一共就那么多核心,有那么多任务需要它同时运行,肯定不会是一个接着一个执行的,这样等待中的程序就会用户体验极差。实际的进程运行会进行上下文切换,保存当前的堆栈寄存器信息,运行另一个进程,异常处理和这个过程类似,当触发异常时,进程由用户态切换到内核态,由操作系统内核接管程序,换言之,内核态与用户态的切换是通过异常这种形式来进行的。同时,要对进程有一个抽象的认识,进程不是像水流一样连绵不断的运行,反而像是在跳机械舞,卡蹦卡蹦的,且每次变换舞姿的时候都要维持之前的形态。

        这篇博客的主要内容其实是来源于csapp的第八章,异常控制流,但是这章讲述的内容有点多,就只写一下实际工作中经常遇到的进程运行crash的问题,进程运行中断是收到了中断信号。信号是一种软件异常,比如,在程序中把零作为除数,被内核检测到,内核会发送SIGILL信号,中断程序,在shell前台运行程序的时候,ctrl+c会发送SIGINT信号,终止进程。一个完整的流程应该是这样的:

程序运行 --》内核检测到异常 --》信号处理程序发送响应异常信号给进程 --》linux检测信号表(一段连续的内存,第n位为1代表存在第n类异常)--》根据相应异常做出继续或中断进程的处理。

需要注意的是,信号不止是可以从内核发送给进程,同样可以由一个进程发送给另一个进程。

        操作系统有权发送各种信号,用户进程也可以对各种信号进行检测判断,不执行这些处理,常见的try catch,throw就是这样的。try catch,throw的底层实现是通过setjmp和longjmp,这两个函数都是在用户态可执行的函数,称为非本地跳转,setjmp执行时,保存当前的调用信息到缓冲区,然后执行预定函数,longjmp是跳转到指定函数调用位置,(如果了解汇编的话,看到jmp就大概知道是什么意思了。)所以,try catch就是setjmp的包装实现,而throw是longjmp的包装实现。这两种函数统称为非本地跳转,一个重要应用是允许从一个深层嵌套的函数调用中立即返回,通常是由检测到某个错误情况引起的;另一个重要应用是使信号处理程序分支到一个特殊的代码位置,而不是返回到信号到达中断了的指令位置。

setjmp 保存当前程序的堆栈上下文环境(stack context),注意,这个保存的堆栈上下文环境仅在调用 setjmp 的函数内有效,如果调用 setjmp 的函数返回了,这个保存的堆栈上下文环境就失效了。调用 setjmp 的直接返回值为 0。

longjmp 将会恢复由 setjmp 保存的程序堆栈上下文,即程序从调用 setjmp 处重新开始执行,不过此时的 setjmp 的返回值将是由 longjmp 指定的值。注意longjmp 不能指定0为返回值,即使指定了 0,longjmp 也会使 setjmp 返回 1。

斜体部分引用自:https://wdxtub.com/2016/04/16/thin-csapp-5/

        代码还是很神奇的,每一个小小的简单指令,背后都是成千上万条电路和一整套自洽完整的操作系统逻辑,要对代码有敬畏之心啊。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值